diff options
Diffstat (limited to 'indra/llui/lltoolbar.cpp')
-rw-r--r-- | indra/llui/lltoolbar.cpp | 2533 |
1 files changed, 1266 insertions, 1267 deletions
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 1c1414dd74..9753881dfc 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1,1267 +1,1266 @@ -/** - * @file lltoolbar.cpp - * @author Richard Nelson - * @brief User customizable toolbar class - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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. - * - * 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. - * - * 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 - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "lltoolbar.h" - -#include "llcommandmanager.h" -#include "llmenugl.h" -#include "lltrans.h" -#include "llinventory.h" -#include "lliconctrl.h" - -// uncomment this and remove the one in llui.cpp when there is an external reference to this translation unit -// thanks, MSVC! -//static LLDefaultChildRegistry::Register<LLToolBar> r1("toolbar"); - -namespace LLToolBarEnums -{ - LLView::EOrientation getOrientation(SideType sideType) - { - LLView::EOrientation orientation = LLLayoutStack::HORIZONTAL; - - if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT)) - { - orientation = LLLayoutStack::VERTICAL; - } - - return orientation; - } -} - -using namespace LLToolBarEnums; - - -namespace LLInitParam -{ - void TypeValues<ButtonType>::declareValues() - { - declare("icons_with_text", BTNTYPE_ICONS_WITH_TEXT); - declare("icons_only", BTNTYPE_ICONS_ONLY); - } - - void TypeValues<SideType>::declareValues() - { - declare("bottom", SIDE_BOTTOM); - declare("left", SIDE_LEFT); - declare("right", SIDE_RIGHT); - declare("top", SIDE_TOP); - } -} - -LLToolBar::Params::Params() -: button_display_mode("button_display_mode"), - commands("command"), - side("side", SIDE_TOP), - button_icon("button_icon"), - button_icon_and_text("button_icon_and_text"), - read_only("read_only", false), - wrap("wrap", true), - pad_left("pad_left"), - pad_top("pad_top"), - pad_right("pad_right"), - pad_bottom("pad_bottom"), - pad_between("pad_between"), - min_girth("min_girth"), - button_panel("button_panel") -{} - -LLToolBar::LLToolBar(const LLToolBar::Params& p) -: LLUICtrl(p), - mReadOnly(p.read_only), - mButtonType(p.button_display_mode), - mSideType(p.side), - mWrap(p.wrap), - mNeedsLayout(false), - mModified(false), - mButtonPanel(NULL), - mCenteringStack(NULL), - mPadLeft(p.pad_left), - mPadRight(p.pad_right), - mPadTop(p.pad_top), - mPadBottom(p.pad_bottom), - mPadBetween(p.pad_between), - mMinGirth(p.min_girth), - mPopupMenuHandle(), - mRightMouseTargetButton(NULL), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), - mHandleDropCallback(NULL), - mButtonAddSignal(NULL), - mButtonEnterSignal(NULL), - mButtonLeaveSignal(NULL), - mButtonRemoveSignal(NULL), - mDragAndDropTarget(false), - mCaretIcon(NULL), - mCenterPanel(NULL) -{ - mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; - mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; -} - -LLToolBar::~LLToolBar() -{ - auto menu = mPopupMenuHandle.get(); - if (menu) - { - menu->die(); - mPopupMenuHandle.markDead(); - } - delete mButtonAddSignal; - delete mButtonEnterSignal; - delete mButtonLeaveSignal; - delete mButtonRemoveSignal; -} - -void LLToolBar::createContextMenu() -{ - if (!mPopupMenuHandle.get()) - { - // Setup bindings specific to this instance for the context menu options - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg; - commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2)); - commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this)); - - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg; - enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2)); - - // Create the context menu - llassert(LLMenuGL::sMenuContainer != NULL); - LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); - - if (menu) - { - menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); - mPopupMenuHandle = menu->getHandle(); - mRemoveButtonHandle = menu->getChild<LLView>("Remove button")->getHandle(); - } - else - { - LL_WARNS() << "Unable to load toolbars context menu." << LL_ENDL; - } - } - - if (mRemoveButtonHandle.get()) - { - // Disable/Enable the "Remove button" menu item depending on whether or not a button was clicked - mRemoveButtonHandle.get()->setEnabled(mRightMouseTargetButton != NULL); - } -} - -void LLToolBar::initFromParams(const LLToolBar::Params& p) -{ - // Initialize the base object - LLUICtrl::initFromParams(p); - - LLView::EOrientation orientation = getOrientation(p.side); - - LLLayoutStack::Params centering_stack_p; - centering_stack_p.name = "centering_stack"; - centering_stack_p.rect = getLocalRect(); - centering_stack_p.follows.flags = FOLLOWS_ALL; - centering_stack_p.orientation = orientation; - centering_stack_p.mouse_opaque = false; - - mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p); - addChild(mCenteringStack); - - LLLayoutPanel::Params border_panel_p; - border_panel_p.name = "border_panel"; - border_panel_p.rect = getLocalRect(); - border_panel_p.auto_resize = true; - border_panel_p.user_resize = false; - border_panel_p.mouse_opaque = false; - - mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); - - LLLayoutPanel::Params center_panel_p; - center_panel_p.name = "center_panel"; - center_panel_p.rect = getLocalRect(); - center_panel_p.auto_resize = false; - center_panel_p.user_resize = false; - center_panel_p.mouse_opaque = false; - mCenterPanel = LLUICtrlFactory::create<LLCenterLayoutPanel>(center_panel_p); - mCenteringStack->addChild(mCenterPanel); - - LLPanel::Params button_panel_p(p.button_panel); - button_panel_p.rect = mCenterPanel->getLocalRect(); - button_panel_p.follows.flags = FOLLOWS_BOTTOM|FOLLOWS_LEFT; - mButtonPanel = LLUICtrlFactory::create<LLPanel>(button_panel_p); - mCenterPanel->setButtonPanel(mButtonPanel); - mCenterPanel->addChild(mButtonPanel); - - mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); - - for (const auto& id : p.commands) - { - addCommand(id); - } - - mNeedsLayout = true; -} - -bool LLToolBar::addCommand(const LLCommandId& commandId, int rank) -{ - LLCommand * command = LLCommandManager::instance().getCommand(commandId); - if (!command) return false; - - // Create the button and do the things that don't need ordering - LLToolBarButton* button = createButton(commandId); - mButtonPanel->addChild(button); - mButtonMap.insert(std::make_pair(commandId.uuid(), button)); - - // Insert the command and button in the right place in their respective lists - if ((rank >= mButtonCommands.size()) || (rank == RANK_NONE)) - { - // In that case, back load - mButtonCommands.push_back(command->id()); - mButtons.push_back(button); - } - else - { - // Insert in place: iterate to the right spot... - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - command_id_list_t::iterator it_command = mButtonCommands.begin(); - while (rank > 0) - { - ++it_button; - ++it_command; - rank--; - } - // ...then insert - mButtonCommands.insert(it_command, command->id()); - mButtons.insert(it_button,button); - } - - mNeedsLayout = true; - - updateLayoutAsNeeded(); - - - if (mButtonAddSignal) - { - (*mButtonAddSignal)(button); - } - - return true; -} - -// Remove a command from the list -// Returns the rank of the command in the original list so that doing addCommand(id,rank) right after -// a removeCommand(id) would leave the list unchanged. -// Returns RANK_NONE if the command is not found in the list -int LLToolBar::removeCommand(const LLCommandId& commandId) -{ - if (!hasCommand(commandId)) return RANK_NONE; - - // First erase the map record - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - mButtonMap.erase(it); - - // Now iterate on the commands and buttons to identify the relevant records - int rank = 0; - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - command_id_list_t::iterator it_command = mButtonCommands.begin(); - while (*it_command != commandId) - { - ++it_button; - ++it_command; - ++rank; - } - - if (mButtonRemoveSignal) - { - (*mButtonRemoveSignal)(*it_button); - } - - // Delete the button and erase the command and button records - delete (*it_button); - mButtonCommands.erase(it_command); - mButtons.erase(it_button); - - mNeedsLayout = true; - - return rank; -} - -void LLToolBar::clearCommandsList() -{ - // Clears the commands list - mButtonCommands.clear(); - // This will clear the buttons - createButtons(); -} - -bool LLToolBar::hasCommand(const LLCommandId& commandId) const -{ - if (commandId != LLCommandId::null) - { - command_id_map::const_iterator it = mButtonMap.find(commandId.uuid()); - return (it != mButtonMap.end()); - } - - return false; -} - -bool LLToolBar::enableCommand(const LLCommandId& commandId, bool enabled) -{ - LLButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - command_button->setEnabled(enabled); - } - } - - return (command_button != NULL); -} - -bool LLToolBar::stopCommandInProgress(const LLCommandId& commandId) -{ - // - // Note from Leslie: - // - // This implementation was largely put in place to handle EXP-1348 which is related to - // dragging and dropping the "speak" button. The "speak" button can be in one of two - // modes, i.e., either a toggle action or a push-to-talk action. Because of this it - // responds to mouse down and mouse up in different ways, based on which behavior the - // button is currently set to obey. This was the simplest way of getting the button - // to turn off the microphone for both behaviors without risking duplicate state. - // - - LLToolBarButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - LLCommand* command = LLCommandManager::instance().getCommand(commandId); - llassert(command); - - // If this command has an explicit function for execution stop - if (command->executeStopFunctionName().length() > 0) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - llassert(command_button->mIsRunningSignal); - - // Check to see if it is running - if ((*command_button->mIsRunningSignal)(command_button, command->isRunningParameters())) - { - // Trigger an additional button commit, which calls mouse down, mouse up and commit - command_button->onCommit(); - } - } - } - } - - return (command_button != NULL); -} - -bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing/* = false */) -{ - LLButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - command_button->setFlashing((bool)(flash),(bool)(force_flashing)); - } - } - - return (command_button != NULL); -} - -bool LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - LLRect button_panel_rect; - mButtonPanel->localRectToOtherView(mButtonPanel->getLocalRect(), &button_panel_rect, this); - bool handle_it_here = !mReadOnly && button_panel_rect.pointInRect(x, y); - - if (handle_it_here) - { - // Determine which button the mouse was over during the click in case the context menu action - // is intended to affect the button. - mRightMouseTargetButton = NULL; - for (LLToolBarButton* button : mButtons) - { - LLRect button_rect; - button->localRectToOtherView(button->getLocalRect(), &button_rect, this); - - if (button_rect.pointInRect(x, y)) - { - mRightMouseTargetButton = button; - break; - } - } - - createContextMenu(); - - LLContextMenu * menu = (LLContextMenu *) mPopupMenuHandle.get(); - - if (menu) - { - menu->show(x, y); - - LLMenuGL::showPopup(this, menu, x, y); - } - } - - return handle_it_here; -} - -bool LLToolBar::isSettingChecked(const LLSD& userdata) -{ - bool retval = false; - - const std::string setting_name = userdata.asString(); - - if (setting_name == "icons_with_text") - { - retval = (mButtonType == BTNTYPE_ICONS_WITH_TEXT); - } - else if (setting_name == "icons_only") - { - retval = (mButtonType == BTNTYPE_ICONS_ONLY); - } - - return retval; -} - -void LLToolBar::onSettingEnable(const LLSD& userdata) -{ - llassert(!mReadOnly); - - const std::string setting_name = userdata.asString(); - - if (setting_name == "icons_with_text") - { - setButtonType(BTNTYPE_ICONS_WITH_TEXT); - } - else if (setting_name == "icons_only") - { - setButtonType(BTNTYPE_ICONS_ONLY); - } -} - -void LLToolBar::onRemoveSelectedCommand() -{ - llassert(!mReadOnly); - - if (mRightMouseTargetButton) - { - removeCommand(mRightMouseTargetButton->getCommandId()); - - mRightMouseTargetButton = NULL; - } -} - -void LLToolBar::setButtonType(LLToolBarEnums::ButtonType button_type) -{ - bool regenerate_buttons = (mButtonType != button_type); - - mButtonType = button_type; - - if (regenerate_buttons) - { - createButtons(); - } -} - -void LLToolBar::resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth) -{ - // make buttons in current row all same girth - for (LLToolBarButton* button : buttons_in_row) - { - if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) - { - button->reshape(button->mWidthRange.clamp(button->getRect().getWidth()), max_row_girth); - } - else // VERTICAL - { - button->reshape(max_row_girth, button->getRect().getHeight()); - } - } -} - -// Returns the position of the coordinates as a rank in the button list. -// The rank is the position a tool dropped in (x,y) would assume in the button list. -// The returned value is between 0 and mButtons.size(), 0 being the first element to the left -// (or top) and mButtons.size() the last one to the right (or bottom). -// Various drag data are stored in the toolbar object though are not exposed outside (and shouldn't). -int LLToolBar::getRankFromPosition(S32 x, S32 y) -{ - if (mButtons.empty()) - { - return RANK_NONE; - } - - int rank = 0; - - // Convert the toolbar coord into button panel coords - LLView::EOrientation orientation = getOrientation(mSideType); - S32 button_panel_x = 0; - S32 button_panel_y = 0; - localPointToOtherView(x, y, &button_panel_x, &button_panel_y, mButtonPanel); - S32 dx = x - button_panel_x; - S32 dy = y - button_panel_y; - - // Simply compare the passed coord with the buttons outbound box + padding - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); - LLRect button_rect; - while (it_button != end_button) - { - button_rect = (*it_button)->getRect(); - S32 point_x = button_rect.mRight + mPadRight; - S32 point_y = button_rect.mBottom - mPadBottom; - - if ((button_panel_x < point_x) && (button_panel_y > point_y)) - { - break; - } - rank++; - ++it_button; - } - - // Update the passed coordinates to the hit button relevant corner - // (different depending on toolbar orientation) - if (rank < mButtons.size()) - { - if (orientation == LLLayoutStack::HORIZONTAL) - { - // Horizontal - S32 mid_point = (button_rect.mRight + button_rect.mLeft) / 2; - if (button_panel_x < mid_point) - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mTop + mPadTop; - } - else - { - rank++; - mDragx = button_rect.mRight + mPadRight - 1; - mDragy = button_rect.mTop + mPadTop; - } - } - else - { - // Vertical - S32 mid_point = (button_rect.mTop + button_rect.mBottom) / 2; - if (button_panel_y > mid_point) - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mTop + mPadTop; - } - else - { - rank++; - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mBottom - mPadBottom + 1; - } - } - } - else - { - // We hit passed the end of the list so put the insertion point at the end - if (orientation == LLLayoutStack::HORIZONTAL) - { - mDragx = button_rect.mRight + mPadRight; - mDragy = button_rect.mTop + mPadTop; - } - else - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mBottom - mPadBottom; - } - } - - // Update the "girth" of the caret, i.e. the width or height (depending of orientation) - if (orientation == LLLayoutStack::HORIZONTAL) - { - mDragGirth = button_rect.getHeight() + mPadBottom + mPadTop; - } - else - { - mDragGirth = button_rect.getWidth() + mPadLeft + mPadRight; - } - - // The delta account for the coord model change (i.e. convert back to toolbar coord) - mDragx += dx; - mDragy += dy; - - return rank; -} - -int LLToolBar::getRankFromPosition(const LLCommandId& id) -{ - if (!hasCommand(id)) - { - return RANK_NONE; - } - int rank = 0; - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); - while (it_button != end_button) - { - if ((*it_button)->mId == id) - { - break; - } - rank++; - ++it_button; - } - return rank; -} - -void LLToolBar::updateLayoutAsNeeded() -{ - if (!mNeedsLayout) return; - - LLView::EOrientation orientation = getOrientation(mSideType); - - // our terminology for orientation-agnostic layout is such that - // length refers to a distance in the direction we stack the buttons - // and girth refers to a distance in the direction buttons wrap - S32 max_row_girth = 0; - S32 max_row_length = 0; - - S32 max_length; - S32 cur_start; - S32 cur_row ; - S32 row_pad_start; - S32 row_pad_end; - S32 girth_pad_end; - S32 row_running_length; - - if (orientation == LLLayoutStack::HORIZONTAL) - { - max_length = getRect().getWidth() - mPadLeft - mPadRight; - row_pad_start = mPadLeft; - row_pad_end = mPadRight; - cur_row = mPadTop; - girth_pad_end = mPadBottom; - } - else // VERTICAL - { - max_length = getRect().getHeight() - mPadTop - mPadBottom; - row_pad_start = mPadTop; - row_pad_end = mPadBottom; - cur_row = mPadLeft; - girth_pad_end = mPadRight; - } - - row_running_length = row_pad_start; - cur_start = row_pad_start; - - - LLRect panel_rect = mButtonPanel->getLocalRect(); - - std::vector<LLToolBarButton*> buttons_in_row; - - for (LLToolBarButton* button : mButtons) - { - button->reshape(button->mWidthRange.getMin(), button->mDesiredHeight); - button->autoResize(); - - S32 button_clamped_width = button->mWidthRange.clamp(button->getRect().getWidth()); - S32 button_length = (orientation == LLLayoutStack::HORIZONTAL) - ? button_clamped_width - : button->getRect().getHeight(); - S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL) - ? button->getRect().getHeight() - : button_clamped_width; - - // wrap if needed - if (mWrap - && row_running_length + button_length > max_length // out of room... - && cur_start != row_pad_start) // ...and not first button in row - { - if (orientation == LLLayoutStack::VERTICAL) - { // row girth (width in this case) is clamped to allowable button widths - max_row_girth = button->mWidthRange.clamp(max_row_girth); - } - - // make buttons in current row all same girth - resizeButtonsInRow(buttons_in_row, max_row_girth); - buttons_in_row.clear(); - - max_row_length = llmax(max_row_length, row_running_length); - row_running_length = row_pad_start; - cur_start = row_pad_start; - cur_row += max_row_girth + mPadBetween; - max_row_girth = 0; - } - - LLRect button_rect; - if (orientation == LLLayoutStack::HORIZONTAL) - { - button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight()); - } - else // VERTICAL - { - button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight()); - } - button->setShape(button_rect); - - buttons_in_row.push_back(button); - - row_running_length += button_length + mPadBetween; - cur_start = row_running_length; - max_row_girth = llmax(button_girth, max_row_girth); - } - - // final resizing in "girth" direction - S32 total_girth = cur_row // current row position... - + max_row_girth // ...incremented by size of final row... - + girth_pad_end; // ...plus padding reserved on end - total_girth = llmax(total_girth,mMinGirth); - - max_row_length = llmax(max_row_length, row_running_length - mPadBetween + row_pad_end); - - resizeButtonsInRow(buttons_in_row, max_row_girth); - - // grow and optionally shift toolbar to accommodate buttons - if (orientation == LLLayoutStack::HORIZONTAL) - { - if (mSideType == SIDE_TOP) - { // shift down to maintain top edge - translate(0, getRect().getHeight() - total_girth); - } - - reshape(getRect().getWidth(), total_girth); - mButtonPanel->reshape(max_row_length, total_girth); - } - else // VERTICAL - { - if (mSideType == SIDE_RIGHT) - { // shift left to maintain right edge - translate(getRect().getWidth() - total_girth, 0); - } - - reshape(total_girth, getRect().getHeight()); - mButtonPanel->reshape(total_girth, max_row_length); - } - - // make parent fit button panel - mButtonPanel->getParent()->setShape(mButtonPanel->getLocalRect()); - - // re-center toolbar buttons - mCenteringStack->updateLayout(); - - if (!mButtons.empty()) - { - mButtonPanel->setVisible(true); - mButtonPanel->setMouseOpaque(true); - } - - // don't clear flag until after we've resized ourselves, to avoid laying out every frame - mNeedsLayout = false; -} - - -void LLToolBar::draw() -{ - if (mButtons.empty()) - { - mButtonPanel->setVisible(false); - mButtonPanel->setMouseOpaque(false); - } - else - { - mButtonPanel->setVisible(true); - mButtonPanel->setMouseOpaque(true); - } - - // Update enable/disable state and highlight state for editable toolbars - if (!mReadOnly) - { - for (toolbar_button_list::iterator btn_it = mButtons.begin(); btn_it != mButtons.end(); ++btn_it) - { - LLToolBarButton* btn = *btn_it; - LLCommand* command = LLCommandManager::instance().getCommand(btn->mId); - - if (command && btn->mIsEnabledSignal) - { - const bool button_command_enabled = (*btn->mIsEnabledSignal)(btn, command->isEnabledParameters()); - btn->setEnabled(button_command_enabled); - } - - if (command && btn->mIsRunningSignal) - { - const bool button_command_running = (*btn->mIsRunningSignal)(btn, command->isRunningParameters()); - btn->setToggleState(button_command_running); - } - } - } - - updateLayoutAsNeeded(); - // rect may have shifted during layout - LLUI::popMatrix(); - LLUI::pushMatrix(); - LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); - - // Position the caret - if (!mCaretIcon) - { - mCaretIcon = getChild<LLIconCtrl>("caret"); - } - - LLIconCtrl* caret = mCaretIcon; - caret->setVisible(false); - if (mDragAndDropTarget && !mButtonCommands.empty()) - { - LLRect caret_rect = caret->getRect(); - if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) - { - caret->setRect(LLRect(mDragx-caret_rect.getWidth()/2+1, - mDragy, - mDragx+caret_rect.getWidth()/2+1, - mDragy-mDragGirth)); - } - else - { - caret->setRect(LLRect(mDragx, - mDragy+caret_rect.getHeight()/2, - mDragx+mDragGirth, - mDragy-caret_rect.getHeight()/2)); - } - caret->setVisible(true); - } - - LLUICtrl::draw(); - caret->setVisible(false); - mDragAndDropTarget = false; -} - -void LLToolBar::reshape(S32 width, S32 height, bool called_from_parent) -{ - LLUICtrl::reshape(width, height, called_from_parent); - mNeedsLayout = true; -} - -void LLToolBar::createButtons() -{ - std::set<LLUUID> set_flashing; - - for (LLToolBarButton* button : mButtons) - { - if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress()) - { - set_flashing.insert(button->getCommandId().uuid()); - } - - if (mButtonRemoveSignal) - { - (*mButtonRemoveSignal)(button); - } - - delete button; - } - mButtons.clear(); - mButtonMap.clear(); - mRightMouseTargetButton = NULL; - - for (const LLCommandId& command_id : mButtonCommands) - { - LLToolBarButton* button = createButton(command_id); - mButtons.push_back(button); - mButtonPanel->addChild(button); - mButtonMap.insert(std::make_pair(command_id.uuid(), button)); - - if (mButtonAddSignal) - { - (*mButtonAddSignal)(button); - } - - if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end()) - { - button->setFlashing(true); - } - } - mNeedsLayout = true; -} - -void LLToolBarButton::callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param ) -{ - LLCommand* command = LLCommandManager::instance().getCommand(mId); - - if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) - { - commit(ctrl, param); - } -} - -LLToolBarButton* LLToolBar::createButton(const LLCommandId& id) -{ - LLCommand* commandp = LLCommandManager::instance().getCommand(id); - if (!commandp) return NULL; - - LLToolBarButton::Params button_p; - button_p.name = commandp->name(); - button_p.label = LLTrans::getString(commandp->labelRef()); - button_p.tool_tip = LLTrans::getString(commandp->tooltipRef()); - button_p.image_overlay = LLUI::getUIImage(commandp->icon()); - button_p.button_flash_enable = commandp->isFlashingAllowed(); - button_p.overwriteFrom(mButtonParams[mButtonType]); - LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p); - - if (!mReadOnly) - { - enable_callback_t isEnabledCB; - - const std::string& isEnabledFunction = commandp->isEnabledFunctionName(); - if (isEnabledFunction.length() > 0) - { - LLUICtrl::EnableCallbackParam isEnabledParam; - isEnabledParam.function_name = isEnabledFunction; - isEnabledParam.parameter = commandp->isEnabledParameters(); - isEnabledCB = initEnableCallback(isEnabledParam); - - if (NULL == button->mIsEnabledSignal) - { - button->mIsEnabledSignal = new enable_signal_t(); - } - - button->mIsEnabledSignal->connect(isEnabledCB); - } - - LLUICtrl::CommitCallbackParam executeParam; - executeParam.function_name = commandp->executeFunctionName(); - executeParam.parameter = commandp->executeParameters(); - - // If we have a "stop" function then we map the command to mouse down / mouse up otherwise commit - const std::string& executeStopFunction = commandp->executeStopFunctionName(); - if (executeStopFunction.length() > 0) - { - LLUICtrl::CommitCallbackParam executeStopParam; - executeStopParam.function_name = executeStopFunction; - executeStopParam.parameter = commandp->executeStopParameters(); - LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam); - button->setFunctionName(commandp->executeFunctionName()); - LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL; - LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam); - - button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2)); - button->setMouseUpCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, stop_func, _1, _2)); - } - else - { - button->setFunctionName(commandp->executeFunctionName()); - LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL; - button->setCommitCallback(executeParam); - } - - // Set up "is running" query callback - const std::string& isRunningFunction = commandp->isRunningFunctionName(); - if (isRunningFunction.length() > 0) - { - LLUICtrl::EnableCallbackParam isRunningParam; - isRunningParam.function_name = isRunningFunction; - isRunningParam.parameter = commandp->isRunningParameters(); - enable_signal_t::slot_type isRunningCB = initEnableCallback(isRunningParam); - - if (NULL == button->mIsRunningSignal) - { - button->mIsRunningSignal = new enable_signal_t(); - } - - button->mIsRunningSignal->connect(isRunningCB); - } - } - - // Drag and drop behavior must work also if provided in the Toybox and, potentially, any read-only toolbar - button->setStartDragCallback(mStartDragItemCallback); - button->setHandleDragCallback(mHandleDragItemCallback); - - button->setCommandId(id); - - return button; -} - -boost::signals2::connection connectSignal(LLToolBar::button_signal_t*& signal, const LLToolBar::button_signal_t::slot_type& cb) -{ - if (!signal) - { - signal = new LLToolBar::button_signal_t(); - } - - return signal->connect(cb); -} - -boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb) -{ - return connectSignal(mButtonAddSignal, cb); -} - -boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb) -{ - return connectSignal(mButtonEnterSignal, cb); -} - -boost::signals2::connection LLToolBar::setButtonLeaveCallback(const button_signal_t::slot_type& cb) -{ - return connectSignal(mButtonLeaveSignal, cb); -} - -boost::signals2::connection LLToolBar::setButtonRemoveCallback(const button_signal_t::slot_type& cb) -{ - return connectSignal(mButtonRemoveSignal, cb); -} - -bool LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - // If we have a drop callback, that means that we can handle the drop - bool handled = mHandleDropCallback != nullptr; - - // if drop is set, it's time to call the callback to get the operation done - if (handled && drop) - { - handled = mHandleDropCallback(cargo_data, x, y, this); - } - - // We accept only single tool drop on toolbars - *accept = handled ? ACCEPT_YES_SINGLE : ACCEPT_NO; - - // We'll use that flag to change the visual aspect of the toolbar target on draw() - mDragAndDropTarget = false; - - // Convert drag position into insert position and rank - if (!isReadOnly() && handled && !drop) - { - if (cargo_type == DAD_WIDGET) - { - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - LLCommandId dragged_command(inv_item->getUUID()); - int orig_rank = getRankFromPosition(dragged_command); - mDragRank = getRankFromPosition(x, y); - // Don't DaD if we're dragging a command on itself - mDragAndDropTarget = ((orig_rank != RANK_NONE) && ((mDragRank == orig_rank) || ((mDragRank - 1) == orig_rank))); - //LL_INFOS() << "Merov debug : DaD, rank = " << mDragRank << ", dragged uui = " << inv_item->getUUID() << LL_ENDL; - /* Do the following if you want to animate the button itself - LLCommandId dragged_command(inv_item->getUUID()); - removeCommand(dragged_command); - addCommand(dragged_command,rank); - */ - } - else - { - handled = false; - } - } - - return handled; -} - -LLToolBarButton::LLToolBarButton(const Params& p) -: LLButton(p), - mMouseDownX(0), - mMouseDownY(0), - mWidthRange(p.button_width), - mDesiredHeight(p.desired_height), - mId(""), - mIsEnabledSignal(NULL), - mIsRunningSignal(NULL), - mIsStartingSignal(NULL), - mIsDragged(false), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), - mOriginalImageSelected(p.image_selected), - mOriginalImageUnselected(p.image_unselected), - mOriginalImagePressed(p.image_pressed), - mOriginalImagePressedSelected(p.image_pressed_selected), - mOriginalLabelColor(p.label_color), - mOriginalLabelColorSelected(p.label_color_selected), - mOriginalImageOverlayColor(p.image_overlay_color), - mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color) -{ -} - -LLToolBarButton::~LLToolBarButton() -{ - delete mIsEnabledSignal; - delete mIsRunningSignal; - delete mIsStartingSignal; -} - -bool LLToolBarButton::handleMouseDown(S32 x, S32 y, MASK mask) -{ - mMouseDownX = x; - mMouseDownY = y; - return LLButton::handleMouseDown(x, y, mask); -} - -bool LLToolBarButton::handleHover(S32 x, S32 y, MASK mask) -{ - bool handled = false; - - S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); - static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3); - if (mouse_distance_squared > drag_threshold * drag_threshold - && hasMouseCapture() && - mStartDragItemCallback && mHandleDragItemCallback) - { - if (!mIsDragged) - { - mStartDragItemCallback(x, y, this); - mIsDragged = true; - handled = true; - } - else - { - handled = mHandleDragItemCallback(x, y, mId.uuid(), LLAssetType::AT_WIDGET); - } - } - else - { - handled = LLButton::handleHover(x, y, mask); - } - - return handled; -} - -void LLToolBarButton::onMouseEnter(S32 x, S32 y, MASK mask) -{ - LLUICtrl::onMouseEnter(x, y, mask); - - // Always highlight toolbar buttons, even if they are disabled - if (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this) - { - mNeedsHighlight = true; - } - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonEnterSignal) - { - (*(parent_toolbar->mButtonEnterSignal))(this); - } -} - -void LLToolBarButton::onMouseLeave(S32 x, S32 y, MASK mask) -{ - LLButton::onMouseLeave(x, y, mask); - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonLeaveSignal) - { - (*(parent_toolbar->mButtonLeaveSignal))(this); - } -} - -void LLToolBarButton::onMouseCaptureLost() -{ - mIsDragged = false; -} - -void LLToolBarButton::onCommit() -{ - LLCommand* command = LLCommandManager::instance().getCommand(mId); - - if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) - { - LLButton::onCommit(); - } -} - -void LLToolBarButton::reshape(S32 width, S32 height, bool called_from_parent) -{ - LLButton::reshape(mWidthRange.clamp(width), height, called_from_parent); -} - -void LLToolBarButton::setEnabled(bool enabled) -{ - if (enabled) - { - mImageSelected = mOriginalImageSelected; - mImageUnselected = mOriginalImageUnselected; - mImagePressed = mOriginalImagePressed; - mImagePressedSelected = mOriginalImagePressedSelected; - mUnselectedLabelColor = mOriginalLabelColor; - mSelectedLabelColor = mOriginalLabelColorSelected; - mImageOverlayColor = mOriginalImageOverlayColor; - mImageOverlaySelectedColor = mOriginalImageOverlaySelectedColor; - } - else - { - mImageSelected = mImageDisabledSelected; - mImageUnselected = mImageDisabled; - mImagePressed = mImageDisabled; - mImagePressedSelected = mImageDisabledSelected; - mUnselectedLabelColor = mDisabledLabelColor; - mSelectedLabelColor = mDisabledSelectedLabelColor; - mImageOverlayColor = mImageOverlayDisabledColor; - mImageOverlaySelectedColor = mImageOverlayDisabledColor; - } -} - -const std::string LLToolBarButton::getToolTip() const -{ - std::string tooltip; - - if (labelIsTruncated() || getCurrentLabel().empty()) - { - tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip(); - } - else - { - tooltip = LLView::getToolTip(); - } - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0) - { - tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")"; - } - - return tooltip; -} - -void LLToolBar::LLCenterLayoutPanel::handleReshape(const LLRect& rect, bool by_user) -{ - LLLayoutPanel::handleReshape(rect, by_user); - - if (!mReshapeCallback.empty()) - { - LLRect r; - localRectToOtherView(mButtonPanel->getRect(), &r, gFloaterView); - r.stretch(FLOATER_MIN_VISIBLE_PIXELS); - mReshapeCallback(mLocationId, r); - } -} +/**
+ * @file lltoolbar.cpp
+ * @author Richard Nelson
+ * @brief User customizable toolbar class
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltoolbar.h"
+
+#include "llcommandmanager.h"
+#include "llmenugl.h"
+#include "lltrans.h"
+#include "llinventory.h"
+#include "lliconctrl.h"
+
+// uncomment this and remove the one in llui.cpp when there is an external reference to this translation unit
+// thanks, MSVC!
+//static LLDefaultChildRegistry::Register<LLToolBar> r1("toolbar");
+
+namespace LLToolBarEnums
+{
+ LLView::EOrientation getOrientation(SideType sideType)
+ {
+ LLView::EOrientation orientation = LLLayoutStack::HORIZONTAL;
+
+ if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT))
+ {
+ orientation = LLLayoutStack::VERTICAL;
+ }
+
+ return orientation;
+ }
+}
+
+using namespace LLToolBarEnums;
+
+
+namespace LLInitParam
+{
+ void TypeValues<ButtonType>::declareValues()
+ {
+ declare("icons_with_text", BTNTYPE_ICONS_WITH_TEXT);
+ declare("icons_only", BTNTYPE_ICONS_ONLY);
+ }
+
+ void TypeValues<SideType>::declareValues()
+ {
+ declare("bottom", SIDE_BOTTOM);
+ declare("left", SIDE_LEFT);
+ declare("right", SIDE_RIGHT);
+ declare("top", SIDE_TOP);
+ }
+}
+
+LLToolBar::Params::Params()
+: button_display_mode("button_display_mode"),
+ commands("command"),
+ side("side", SIDE_TOP),
+ button_icon("button_icon"),
+ button_icon_and_text("button_icon_and_text"),
+ read_only("read_only", false),
+ wrap("wrap", true),
+ pad_left("pad_left"),
+ pad_top("pad_top"),
+ pad_right("pad_right"),
+ pad_bottom("pad_bottom"),
+ pad_between("pad_between"),
+ min_girth("min_girth"),
+ button_panel("button_panel")
+{}
+
+LLToolBar::LLToolBar(const LLToolBar::Params& p)
+: LLUICtrl(p),
+ mReadOnly(p.read_only),
+ mButtonType(p.button_display_mode),
+ mSideType(p.side),
+ mWrap(p.wrap),
+ mNeedsLayout(false),
+ mModified(false),
+ mButtonPanel(NULL),
+ mCenteringStack(NULL),
+ mPadLeft(p.pad_left),
+ mPadRight(p.pad_right),
+ mPadTop(p.pad_top),
+ mPadBottom(p.pad_bottom),
+ mPadBetween(p.pad_between),
+ mMinGirth(p.min_girth),
+ mPopupMenuHandle(),
+ mRightMouseTargetButton(NULL),
+ mStartDragItemCallback(NULL),
+ mHandleDragItemCallback(NULL),
+ mHandleDropCallback(NULL),
+ mButtonAddSignal(NULL),
+ mButtonEnterSignal(NULL),
+ mButtonLeaveSignal(NULL),
+ mButtonRemoveSignal(NULL),
+ mDragAndDropTarget(false),
+ mCaretIcon(NULL),
+ mCenterPanel(NULL)
+{
+ mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text;
+ mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon;
+}
+
+LLToolBar::~LLToolBar()
+{
+ auto menu = mPopupMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mPopupMenuHandle.markDead();
+ }
+ delete mButtonAddSignal;
+ delete mButtonEnterSignal;
+ delete mButtonLeaveSignal;
+ delete mButtonRemoveSignal;
+}
+
+void LLToolBar::createContextMenu()
+{
+ if (!mPopupMenuHandle.get())
+ {
+ // Setup bindings specific to this instance for the context menu options
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg;
+ commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2));
+ commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this));
+
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg;
+ enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2));
+
+ // Create the context menu
+ llassert(LLMenuGL::sMenuContainer != NULL);
+ LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+
+ if (menu)
+ {
+ menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
+ mPopupMenuHandle = menu->getHandle();
+ mRemoveButtonHandle = menu->getChild<LLView>("Remove button")->getHandle();
+ }
+ else
+ {
+ LL_WARNS() << "Unable to load toolbars context menu." << LL_ENDL;
+ }
+ }
+
+ if (mRemoveButtonHandle.get())
+ {
+ // Disable/Enable the "Remove button" menu item depending on whether or not a button was clicked
+ mRemoveButtonHandle.get()->setEnabled(mRightMouseTargetButton != NULL);
+ }
+}
+
+void LLToolBar::initFromParams(const LLToolBar::Params& p)
+{
+ // Initialize the base object
+ LLUICtrl::initFromParams(p);
+
+ LLView::EOrientation orientation = getOrientation(p.side);
+
+ LLLayoutStack::Params centering_stack_p;
+ centering_stack_p.name = "centering_stack";
+ centering_stack_p.rect = getLocalRect();
+ centering_stack_p.follows.flags = FOLLOWS_ALL;
+ centering_stack_p.orientation = orientation;
+ centering_stack_p.mouse_opaque = false;
+
+ mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p);
+ addChild(mCenteringStack);
+
+ LLLayoutPanel::Params border_panel_p;
+ border_panel_p.name = "border_panel";
+ border_panel_p.rect = getLocalRect();
+ border_panel_p.auto_resize = true;
+ border_panel_p.user_resize = false;
+ border_panel_p.mouse_opaque = false;
+
+ mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));
+
+ LLLayoutPanel::Params center_panel_p;
+ center_panel_p.name = "center_panel";
+ center_panel_p.rect = getLocalRect();
+ center_panel_p.auto_resize = false;
+ center_panel_p.user_resize = false;
+ center_panel_p.mouse_opaque = false;
+ mCenterPanel = LLUICtrlFactory::create<LLCenterLayoutPanel>(center_panel_p);
+ mCenteringStack->addChild(mCenterPanel);
+
+ LLPanel::Params button_panel_p(p.button_panel);
+ button_panel_p.rect = mCenterPanel->getLocalRect();
+ button_panel_p.follows.flags = FOLLOWS_BOTTOM|FOLLOWS_LEFT;
+ mButtonPanel = LLUICtrlFactory::create<LLPanel>(button_panel_p);
+ mCenterPanel->setButtonPanel(mButtonPanel);
+ mCenterPanel->addChild(mButtonPanel);
+
+ mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));
+
+ for (const auto& id : p.commands)
+ {
+ addCommand(id);
+ }
+
+ mNeedsLayout = true;
+}
+
+bool LLToolBar::addCommand(const LLCommandId& commandId, int rank)
+{
+ LLCommand * command = LLCommandManager::instance().getCommand(commandId);
+ if (!command) return false;
+
+ // Create the button and do the things that don't need ordering
+ LLToolBarButton* button = createButton(commandId);
+ mButtonPanel->addChild(button);
+ mButtonMap.insert(std::make_pair(commandId.uuid(), button));
+
+ // Insert the command and button in the right place in their respective lists
+ if ((rank >= mButtonCommands.size()) || (rank == RANK_NONE))
+ {
+ // In that case, back load
+ mButtonCommands.push_back(command->id());
+ mButtons.push_back(button);
+ }
+ else
+ {
+ // Insert in place: iterate to the right spot...
+ std::list<LLToolBarButton*>::iterator it_button = mButtons.begin();
+ command_id_list_t::iterator it_command = mButtonCommands.begin();
+ while (rank > 0)
+ {
+ ++it_button;
+ ++it_command;
+ rank--;
+ }
+ // ...then insert
+ mButtonCommands.insert(it_command, command->id());
+ mButtons.insert(it_button,button);
+ }
+
+ mNeedsLayout = true;
+
+ updateLayoutAsNeeded();
+
+
+ if (mButtonAddSignal)
+ {
+ (*mButtonAddSignal)(button);
+ }
+
+ return true;
+}
+
+// Remove a command from the list
+// Returns the rank of the command in the original list so that doing addCommand(id,rank) right after
+// a removeCommand(id) would leave the list unchanged.
+// Returns RANK_NONE if the command is not found in the list
+int LLToolBar::removeCommand(const LLCommandId& commandId)
+{
+ if (!hasCommand(commandId)) return RANK_NONE;
+
+ // First erase the map record
+ command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+ mButtonMap.erase(it);
+
+ // Now iterate on the commands and buttons to identify the relevant records
+ int rank = 0;
+ std::list<LLToolBarButton*>::iterator it_button = mButtons.begin();
+ command_id_list_t::iterator it_command = mButtonCommands.begin();
+ while (*it_command != commandId)
+ {
+ ++it_button;
+ ++it_command;
+ ++rank;
+ }
+
+ if (mButtonRemoveSignal)
+ {
+ (*mButtonRemoveSignal)(*it_button);
+ }
+
+ // Delete the button and erase the command and button records
+ delete (*it_button);
+ mButtonCommands.erase(it_command);
+ mButtons.erase(it_button);
+
+ mNeedsLayout = true;
+
+ return rank;
+}
+
+void LLToolBar::clearCommandsList()
+{
+ // Clears the commands list
+ mButtonCommands.clear();
+ // This will clear the buttons
+ createButtons();
+}
+
+bool LLToolBar::hasCommand(const LLCommandId& commandId) const
+{
+ if (commandId != LLCommandId::null)
+ {
+ command_id_map::const_iterator it = mButtonMap.find(commandId.uuid());
+ return (it != mButtonMap.end());
+ }
+
+ return false;
+}
+
+bool LLToolBar::enableCommand(const LLCommandId& commandId, bool enabled)
+{
+ LLButton * command_button = NULL;
+
+ if (commandId != LLCommandId::null)
+ {
+ command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+ if (it != mButtonMap.end())
+ {
+ command_button = it->second;
+ command_button->setEnabled(enabled);
+ }
+ }
+
+ return (command_button != NULL);
+}
+
+bool LLToolBar::stopCommandInProgress(const LLCommandId& commandId)
+{
+ //
+ // Note from Leslie:
+ //
+ // This implementation was largely put in place to handle EXP-1348 which is related to
+ // dragging and dropping the "speak" button. The "speak" button can be in one of two
+ // modes, i.e., either a toggle action or a push-to-talk action. Because of this it
+ // responds to mouse down and mouse up in different ways, based on which behavior the
+ // button is currently set to obey. This was the simplest way of getting the button
+ // to turn off the microphone for both behaviors without risking duplicate state.
+ //
+
+ LLToolBarButton * command_button = NULL;
+
+ if (commandId != LLCommandId::null)
+ {
+ LLCommand* command = LLCommandManager::instance().getCommand(commandId);
+ llassert(command);
+
+ // If this command has an explicit function for execution stop
+ if (command->executeStopFunctionName().length() > 0)
+ {
+ command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+ if (it != mButtonMap.end())
+ {
+ command_button = it->second;
+ llassert(command_button->mIsRunningSignal);
+
+ // Check to see if it is running
+ if ((*command_button->mIsRunningSignal)(command_button, command->isRunningParameters()))
+ {
+ // Trigger an additional button commit, which calls mouse down, mouse up and commit
+ command_button->onCommit();
+ }
+ }
+ }
+ }
+
+ return (command_button != NULL);
+}
+
+bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing/* = false */)
+{
+ LLButton * command_button = NULL;
+
+ if (commandId != LLCommandId::null)
+ {
+ command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+ if (it != mButtonMap.end())
+ {
+ command_button = it->second;
+ command_button->setFlashing((bool)(flash),(bool)(force_flashing));
+ }
+ }
+
+ return (command_button != NULL);
+}
+
+bool LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ LLRect button_panel_rect;
+ mButtonPanel->localRectToOtherView(mButtonPanel->getLocalRect(), &button_panel_rect, this);
+ bool handle_it_here = !mReadOnly && button_panel_rect.pointInRect(x, y);
+
+ if (handle_it_here)
+ {
+ // Determine which button the mouse was over during the click in case the context menu action
+ // is intended to affect the button.
+ mRightMouseTargetButton = NULL;
+ for (LLToolBarButton* button : mButtons)
+ {
+ LLRect button_rect;
+ button->localRectToOtherView(button->getLocalRect(), &button_rect, this);
+
+ if (button_rect.pointInRect(x, y))
+ {
+ mRightMouseTargetButton = button;
+ break;
+ }
+ }
+
+ createContextMenu();
+
+ LLContextMenu * menu = (LLContextMenu *) mPopupMenuHandle.get();
+
+ if (menu)
+ {
+ menu->show(x, y);
+
+ LLMenuGL::showPopup(this, menu, x, y);
+ }
+ }
+
+ return handle_it_here;
+}
+
+bool LLToolBar::isSettingChecked(const LLSD& userdata)
+{
+ bool retval = false;
+
+ const std::string setting_name = userdata.asString();
+
+ if (setting_name == "icons_with_text")
+ {
+ retval = (mButtonType == BTNTYPE_ICONS_WITH_TEXT);
+ }
+ else if (setting_name == "icons_only")
+ {
+ retval = (mButtonType == BTNTYPE_ICONS_ONLY);
+ }
+
+ return retval;
+}
+
+void LLToolBar::onSettingEnable(const LLSD& userdata)
+{
+ llassert(!mReadOnly);
+
+ const std::string setting_name = userdata.asString();
+
+ if (setting_name == "icons_with_text")
+ {
+ setButtonType(BTNTYPE_ICONS_WITH_TEXT);
+ }
+ else if (setting_name == "icons_only")
+ {
+ setButtonType(BTNTYPE_ICONS_ONLY);
+ }
+}
+
+void LLToolBar::onRemoveSelectedCommand()
+{
+ llassert(!mReadOnly);
+
+ if (mRightMouseTargetButton)
+ {
+ removeCommand(mRightMouseTargetButton->getCommandId());
+
+ mRightMouseTargetButton = NULL;
+ }
+}
+
+void LLToolBar::setButtonType(LLToolBarEnums::ButtonType button_type)
+{
+ bool regenerate_buttons = (mButtonType != button_type);
+
+ mButtonType = button_type;
+
+ if (regenerate_buttons)
+ {
+ createButtons();
+ }
+}
+
+void LLToolBar::resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth)
+{
+ // make buttons in current row all same girth
+ for (LLToolBarButton* button : buttons_in_row)
+ {
+ if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL)
+ {
+ button->reshape(button->mWidthRange.clamp(button->getRect().getWidth()), max_row_girth);
+ }
+ else // VERTICAL
+ {
+ button->reshape(max_row_girth, button->getRect().getHeight());
+ }
+ }
+}
+
+// Returns the position of the coordinates as a rank in the button list.
+// The rank is the position a tool dropped in (x,y) would assume in the button list.
+// The returned value is between 0 and mButtons.size(), 0 being the first element to the left
+// (or top) and mButtons.size() the last one to the right (or bottom).
+// Various drag data are stored in the toolbar object though are not exposed outside (and shouldn't).
+int LLToolBar::getRankFromPosition(S32 x, S32 y)
+{
+ if (mButtons.empty())
+ {
+ return RANK_NONE;
+ }
+
+ int rank = 0;
+
+ // Convert the toolbar coord into button panel coords
+ LLView::EOrientation orientation = getOrientation(mSideType);
+ S32 button_panel_x = 0;
+ S32 button_panel_y = 0;
+ localPointToOtherView(x, y, &button_panel_x, &button_panel_y, mButtonPanel);
+ S32 dx = x - button_panel_x;
+ S32 dy = y - button_panel_y;
+
+ // Simply compare the passed coord with the buttons outbound box + padding
+ std::list<LLToolBarButton*>::iterator it_button = mButtons.begin();
+ std::list<LLToolBarButton*>::iterator end_button = mButtons.end();
+ LLRect button_rect;
+ while (it_button != end_button)
+ {
+ button_rect = (*it_button)->getRect();
+ S32 point_x = button_rect.mRight + mPadRight;
+ S32 point_y = button_rect.mBottom - mPadBottom;
+
+ if ((button_panel_x < point_x) && (button_panel_y > point_y))
+ {
+ break;
+ }
+ rank++;
+ ++it_button;
+ }
+
+ // Update the passed coordinates to the hit button relevant corner
+ // (different depending on toolbar orientation)
+ if (rank < mButtons.size())
+ {
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ // Horizontal
+ S32 mid_point = (button_rect.mRight + button_rect.mLeft) / 2;
+ if (button_panel_x < mid_point)
+ {
+ mDragx = button_rect.mLeft - mPadLeft;
+ mDragy = button_rect.mTop + mPadTop;
+ }
+ else
+ {
+ rank++;
+ mDragx = button_rect.mRight + mPadRight - 1;
+ mDragy = button_rect.mTop + mPadTop;
+ }
+ }
+ else
+ {
+ // Vertical
+ S32 mid_point = (button_rect.mTop + button_rect.mBottom) / 2;
+ if (button_panel_y > mid_point)
+ {
+ mDragx = button_rect.mLeft - mPadLeft;
+ mDragy = button_rect.mTop + mPadTop;
+ }
+ else
+ {
+ rank++;
+ mDragx = button_rect.mLeft - mPadLeft;
+ mDragy = button_rect.mBottom - mPadBottom + 1;
+ }
+ }
+ }
+ else
+ {
+ // We hit passed the end of the list so put the insertion point at the end
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ mDragx = button_rect.mRight + mPadRight;
+ mDragy = button_rect.mTop + mPadTop;
+ }
+ else
+ {
+ mDragx = button_rect.mLeft - mPadLeft;
+ mDragy = button_rect.mBottom - mPadBottom;
+ }
+ }
+
+ // Update the "girth" of the caret, i.e. the width or height (depending of orientation)
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ mDragGirth = button_rect.getHeight() + mPadBottom + mPadTop;
+ }
+ else
+ {
+ mDragGirth = button_rect.getWidth() + mPadLeft + mPadRight;
+ }
+
+ // The delta account for the coord model change (i.e. convert back to toolbar coord)
+ mDragx += dx;
+ mDragy += dy;
+
+ return rank;
+}
+
+int LLToolBar::getRankFromPosition(const LLCommandId& id)
+{
+ if (!hasCommand(id))
+ {
+ return RANK_NONE;
+ }
+ int rank = 0;
+ std::list<LLToolBarButton*>::iterator it_button = mButtons.begin();
+ std::list<LLToolBarButton*>::iterator end_button = mButtons.end();
+ while (it_button != end_button)
+ {
+ if ((*it_button)->mId == id)
+ {
+ break;
+ }
+ rank++;
+ ++it_button;
+ }
+ return rank;
+}
+
+void LLToolBar::updateLayoutAsNeeded()
+{
+ if (!mNeedsLayout) return;
+
+ LLView::EOrientation orientation = getOrientation(mSideType);
+
+ // our terminology for orientation-agnostic layout is such that
+ // length refers to a distance in the direction we stack the buttons
+ // and girth refers to a distance in the direction buttons wrap
+ S32 max_row_girth = 0;
+ S32 max_row_length = 0;
+
+ S32 max_length;
+ S32 cur_start;
+ S32 cur_row ;
+ S32 row_pad_start;
+ S32 row_pad_end;
+ S32 girth_pad_end;
+ S32 row_running_length;
+
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ max_length = getRect().getWidth() - mPadLeft - mPadRight;
+ row_pad_start = mPadLeft;
+ row_pad_end = mPadRight;
+ cur_row = mPadTop;
+ girth_pad_end = mPadBottom;
+ }
+ else // VERTICAL
+ {
+ max_length = getRect().getHeight() - mPadTop - mPadBottom;
+ row_pad_start = mPadTop;
+ row_pad_end = mPadBottom;
+ cur_row = mPadLeft;
+ girth_pad_end = mPadRight;
+ }
+
+ row_running_length = row_pad_start;
+ cur_start = row_pad_start;
+
+
+ LLRect panel_rect = mButtonPanel->getLocalRect();
+
+ std::vector<LLToolBarButton*> buttons_in_row;
+
+ for (LLToolBarButton* button : mButtons)
+ {
+ button->reshape(button->mWidthRange.getMin(), button->mDesiredHeight);
+ button->autoResize();
+
+ S32 button_clamped_width = button->mWidthRange.clamp(button->getRect().getWidth());
+ S32 button_length = (orientation == LLLayoutStack::HORIZONTAL)
+ ? button_clamped_width
+ : button->getRect().getHeight();
+ S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL)
+ ? button->getRect().getHeight()
+ : button_clamped_width;
+
+ // wrap if needed
+ if (mWrap
+ && row_running_length + button_length > max_length // out of room...
+ && cur_start != row_pad_start) // ...and not first button in row
+ {
+ if (orientation == LLLayoutStack::VERTICAL)
+ { // row girth (width in this case) is clamped to allowable button widths
+ max_row_girth = button->mWidthRange.clamp(max_row_girth);
+ }
+
+ // make buttons in current row all same girth
+ resizeButtonsInRow(buttons_in_row, max_row_girth);
+ buttons_in_row.clear();
+
+ max_row_length = llmax(max_row_length, row_running_length);
+ row_running_length = row_pad_start;
+ cur_start = row_pad_start;
+ cur_row += max_row_girth + mPadBetween;
+ max_row_girth = 0;
+ }
+
+ LLRect button_rect;
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight());
+ }
+ else // VERTICAL
+ {
+ button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight());
+ }
+ button->setShape(button_rect);
+
+ buttons_in_row.push_back(button);
+
+ row_running_length += button_length + mPadBetween;
+ cur_start = row_running_length;
+ max_row_girth = llmax(button_girth, max_row_girth);
+ }
+
+ // final resizing in "girth" direction
+ S32 total_girth = cur_row // current row position...
+ + max_row_girth // ...incremented by size of final row...
+ + girth_pad_end; // ...plus padding reserved on end
+ total_girth = llmax(total_girth,mMinGirth);
+
+ max_row_length = llmax(max_row_length, row_running_length - mPadBetween + row_pad_end);
+
+ resizeButtonsInRow(buttons_in_row, max_row_girth);
+
+ // grow and optionally shift toolbar to accommodate buttons
+ if (orientation == LLLayoutStack::HORIZONTAL)
+ {
+ if (mSideType == SIDE_TOP)
+ { // shift down to maintain top edge
+ translate(0, getRect().getHeight() - total_girth);
+ }
+
+ reshape(getRect().getWidth(), total_girth);
+ mButtonPanel->reshape(max_row_length, total_girth);
+ }
+ else // VERTICAL
+ {
+ if (mSideType == SIDE_RIGHT)
+ { // shift left to maintain right edge
+ translate(getRect().getWidth() - total_girth, 0);
+ }
+
+ reshape(total_girth, getRect().getHeight());
+ mButtonPanel->reshape(total_girth, max_row_length);
+ }
+
+ // make parent fit button panel
+ mButtonPanel->getParent()->setShape(mButtonPanel->getLocalRect());
+
+ // re-center toolbar buttons
+ mCenteringStack->updateLayout();
+
+ if (!mButtons.empty())
+ {
+ mButtonPanel->setVisible(true);
+ mButtonPanel->setMouseOpaque(true);
+ }
+
+ // don't clear flag until after we've resized ourselves, to avoid laying out every frame
+ mNeedsLayout = false;
+}
+
+
+void LLToolBar::draw()
+{
+ if (mButtons.empty())
+ {
+ mButtonPanel->setVisible(false);
+ mButtonPanel->setMouseOpaque(false);
+ }
+ else
+ {
+ mButtonPanel->setVisible(true);
+ mButtonPanel->setMouseOpaque(true);
+ }
+
+ // Update enable/disable state and highlight state for editable toolbars
+ if (!mReadOnly)
+ {
+ for (toolbar_button_list::iterator btn_it = mButtons.begin(); btn_it != mButtons.end(); ++btn_it)
+ {
+ LLToolBarButton* btn = *btn_it;
+ LLCommand* command = LLCommandManager::instance().getCommand(btn->mId);
+
+ if (command && btn->mIsEnabledSignal)
+ {
+ const bool button_command_enabled = (*btn->mIsEnabledSignal)(btn, command->isEnabledParameters());
+ btn->setEnabled(button_command_enabled);
+ }
+
+ if (command && btn->mIsRunningSignal)
+ {
+ const bool button_command_running = (*btn->mIsRunningSignal)(btn, command->isRunningParameters());
+ btn->setToggleState(button_command_running);
+ }
+ }
+ }
+
+ updateLayoutAsNeeded();
+ // rect may have shifted during layout
+ LLUI::popMatrix();
+ LLUI::pushMatrix();
+ LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom);
+
+ // Position the caret
+ if (!mCaretIcon)
+ {
+ mCaretIcon = getChild<LLIconCtrl>("caret");
+ }
+
+ LLIconCtrl* caret = mCaretIcon;
+ caret->setVisible(false);
+ if (mDragAndDropTarget && !mButtonCommands.empty())
+ {
+ LLRect caret_rect = caret->getRect();
+ if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL)
+ {
+ caret->setRect(LLRect(mDragx-caret_rect.getWidth()/2+1,
+ mDragy,
+ mDragx+caret_rect.getWidth()/2+1,
+ mDragy-mDragGirth));
+ }
+ else
+ {
+ caret->setRect(LLRect(mDragx,
+ mDragy+caret_rect.getHeight()/2,
+ mDragx+mDragGirth,
+ mDragy-caret_rect.getHeight()/2));
+ }
+ caret->setVisible(true);
+ }
+
+ LLUICtrl::draw();
+ caret->setVisible(false);
+ mDragAndDropTarget = false;
+}
+
+void LLToolBar::reshape(S32 width, S32 height, bool called_from_parent)
+{
+ LLUICtrl::reshape(width, height, called_from_parent);
+ mNeedsLayout = true;
+}
+
+void LLToolBar::createButtons()
+{
+ std::set<LLUUID> set_flashing;
+
+ for (LLToolBarButton* button : mButtons)
+ {
+ if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress())
+ {
+ set_flashing.insert(button->getCommandId().uuid());
+ }
+
+ if (mButtonRemoveSignal)
+ {
+ (*mButtonRemoveSignal)(button);
+ }
+
+ delete button;
+ }
+ mButtons.clear();
+ mButtonMap.clear();
+ mRightMouseTargetButton = NULL;
+
+ for (const LLCommandId& command_id : mButtonCommands)
+ {
+ LLToolBarButton* button = createButton(command_id);
+ mButtons.push_back(button);
+ mButtonPanel->addChild(button);
+ mButtonMap.insert(std::make_pair(command_id.uuid(), button));
+
+ if (mButtonAddSignal)
+ {
+ (*mButtonAddSignal)(button);
+ }
+
+ if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end())
+ {
+ button->setFlashing(true);
+ }
+ }
+ mNeedsLayout = true;
+}
+
+void LLToolBarButton::callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param )
+{
+ LLCommand* command = LLCommandManager::instance().getCommand(mId);
+
+ if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters()))
+ {
+ commit(ctrl, param);
+ }
+}
+
+LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
+{
+ LLCommand* commandp = LLCommandManager::instance().getCommand(id);
+ if (!commandp) return NULL;
+
+ LLToolBarButton::Params button_p;
+ button_p.name = commandp->name();
+ button_p.label = LLTrans::getString(commandp->labelRef());
+ button_p.tool_tip = LLTrans::getString(commandp->tooltipRef());
+ button_p.image_overlay = LLUI::getUIImage(commandp->icon());
+ button_p.button_flash_enable = commandp->isFlashingAllowed();
+ button_p.overwriteFrom(mButtonParams[mButtonType]);
+ LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p);
+
+ if (!mReadOnly)
+ {
+ enable_callback_t isEnabledCB;
+
+ const std::string& isEnabledFunction = commandp->isEnabledFunctionName();
+ if (isEnabledFunction.length() > 0)
+ {
+ LLUICtrl::EnableCallbackParam isEnabledParam;
+ isEnabledParam.function_name = isEnabledFunction;
+ isEnabledParam.parameter = commandp->isEnabledParameters();
+ isEnabledCB = initEnableCallback(isEnabledParam);
+
+ if (NULL == button->mIsEnabledSignal)
+ {
+ button->mIsEnabledSignal = new enable_signal_t();
+ }
+
+ button->mIsEnabledSignal->connect(isEnabledCB);
+ }
+
+ LLUICtrl::CommitCallbackParam executeParam;
+ executeParam.function_name = commandp->executeFunctionName();
+ executeParam.parameter = commandp->executeParameters();
+
+ // If we have a "stop" function then we map the command to mouse down / mouse up otherwise commit
+ const std::string& executeStopFunction = commandp->executeStopFunctionName();
+ if (executeStopFunction.length() > 0)
+ {
+ LLUICtrl::CommitCallbackParam executeStopParam;
+ executeStopParam.function_name = executeStopFunction;
+ executeStopParam.parameter = commandp->executeStopParameters();
+ LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam);
+ button->setFunctionName(commandp->executeFunctionName());
+ LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL;
+ LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam);
+
+ button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2));
+ button->setMouseUpCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, stop_func, _1, _2));
+ }
+ else
+ {
+ button->setFunctionName(commandp->executeFunctionName());
+ LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL;
+ button->setCommitCallback(executeParam);
+ }
+
+ // Set up "is running" query callback
+ const std::string& isRunningFunction = commandp->isRunningFunctionName();
+ if (isRunningFunction.length() > 0)
+ {
+ LLUICtrl::EnableCallbackParam isRunningParam;
+ isRunningParam.function_name = isRunningFunction;
+ isRunningParam.parameter = commandp->isRunningParameters();
+ enable_signal_t::slot_type isRunningCB = initEnableCallback(isRunningParam);
+
+ if (NULL == button->mIsRunningSignal)
+ {
+ button->mIsRunningSignal = new enable_signal_t();
+ }
+
+ button->mIsRunningSignal->connect(isRunningCB);
+ }
+ }
+
+ // Drag and drop behavior must work also if provided in the Toybox and, potentially, any read-only toolbar
+ button->setStartDragCallback(mStartDragItemCallback);
+ button->setHandleDragCallback(mHandleDragItemCallback);
+
+ button->setCommandId(id);
+
+ return button;
+}
+
+boost::signals2::connection connectSignal(LLToolBar::button_signal_t*& signal, const LLToolBar::button_signal_t::slot_type& cb)
+{
+ if (!signal)
+ {
+ signal = new LLToolBar::button_signal_t();
+ }
+
+ return signal->connect(cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb)
+{
+ return connectSignal(mButtonAddSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb)
+{
+ return connectSignal(mButtonEnterSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonLeaveCallback(const button_signal_t::slot_type& cb)
+{
+ return connectSignal(mButtonLeaveSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonRemoveCallback(const button_signal_t::slot_type& cb)
+{
+ return connectSignal(mButtonRemoveSignal, cb);
+}
+
+bool LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ // If we have a drop callback, that means that we can handle the drop
+ bool handled = mHandleDropCallback != nullptr;
+
+ // if drop is set, it's time to call the callback to get the operation done
+ if (handled && drop)
+ {
+ handled = mHandleDropCallback(cargo_data, x, y, this);
+ }
+
+ // We accept only single tool drop on toolbars
+ *accept = handled ? ACCEPT_YES_SINGLE : ACCEPT_NO;
+
+ // We'll use that flag to change the visual aspect of the toolbar target on draw()
+ mDragAndDropTarget = false;
+
+ // Convert drag position into insert position and rank
+ if (!isReadOnly() && handled && !drop)
+ {
+ if (cargo_type == DAD_WIDGET)
+ {
+ LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+ LLCommandId dragged_command(inv_item->getUUID());
+ int orig_rank = getRankFromPosition(dragged_command);
+ mDragRank = getRankFromPosition(x, y);
+ // Don't DaD if we're dragging a command on itself
+ mDragAndDropTarget = ((orig_rank != RANK_NONE) && ((mDragRank == orig_rank) || ((mDragRank - 1) == orig_rank)));
+ //LL_INFOS() << "Merov debug : DaD, rank = " << mDragRank << ", dragged uui = " << inv_item->getUUID() << LL_ENDL;
+ /* Do the following if you want to animate the button itself
+ LLCommandId dragged_command(inv_item->getUUID());
+ removeCommand(dragged_command);
+ addCommand(dragged_command,rank);
+ */
+ }
+ else
+ {
+ handled = false;
+ }
+ }
+
+ return handled;
+}
+
+LLToolBarButton::LLToolBarButton(const Params& p)
+: LLButton(p),
+ mMouseDownX(0),
+ mMouseDownY(0),
+ mWidthRange(p.button_width),
+ mDesiredHeight(p.desired_height),
+ mId(""),
+ mIsEnabledSignal(NULL),
+ mIsRunningSignal(NULL),
+ mIsStartingSignal(NULL),
+ mIsDragged(false),
+ mStartDragItemCallback(NULL),
+ mHandleDragItemCallback(NULL),
+ mOriginalImageSelected(p.image_selected),
+ mOriginalImageUnselected(p.image_unselected),
+ mOriginalImagePressed(p.image_pressed),
+ mOriginalImagePressedSelected(p.image_pressed_selected),
+ mOriginalLabelColor(p.label_color),
+ mOriginalLabelColorSelected(p.label_color_selected),
+ mOriginalImageOverlayColor(p.image_overlay_color),
+ mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color)
+{
+}
+
+LLToolBarButton::~LLToolBarButton()
+{
+ delete mIsEnabledSignal;
+ delete mIsRunningSignal;
+ delete mIsStartingSignal;
+}
+
+bool LLToolBarButton::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ mMouseDownX = x;
+ mMouseDownY = y;
+ return LLButton::handleMouseDown(x, y, mask);
+}
+
+bool LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
+{
+ bool handled = false;
+
+ S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
+ if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
+ && hasMouseCapture() &&
+ mStartDragItemCallback && mHandleDragItemCallback)
+ {
+ if (!mIsDragged)
+ {
+ mStartDragItemCallback(x, y, this);
+ mIsDragged = true;
+ handled = true;
+ }
+ else
+ {
+ handled = mHandleDragItemCallback(x, y, mId.uuid(), LLAssetType::AT_WIDGET);
+ }
+ }
+ else
+ {
+ handled = LLButton::handleHover(x, y, mask);
+ }
+
+ return handled;
+}
+
+void LLToolBarButton::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ LLUICtrl::onMouseEnter(x, y, mask);
+
+ // Always highlight toolbar buttons, even if they are disabled
+ if (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)
+ {
+ mNeedsHighlight = true;
+ }
+
+ LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+ if (parent_toolbar && parent_toolbar->mButtonEnterSignal)
+ {
+ (*(parent_toolbar->mButtonEnterSignal))(this);
+ }
+}
+
+void LLToolBarButton::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ LLButton::onMouseLeave(x, y, mask);
+
+ LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+ if (parent_toolbar && parent_toolbar->mButtonLeaveSignal)
+ {
+ (*(parent_toolbar->mButtonLeaveSignal))(this);
+ }
+}
+
+void LLToolBarButton::onMouseCaptureLost()
+{
+ mIsDragged = false;
+}
+
+void LLToolBarButton::onCommit()
+{
+ LLCommand* command = LLCommandManager::instance().getCommand(mId);
+
+ if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters()))
+ {
+ LLButton::onCommit();
+ }
+}
+
+void LLToolBarButton::reshape(S32 width, S32 height, bool called_from_parent)
+{
+ LLButton::reshape(mWidthRange.clamp(width), height, called_from_parent);
+}
+
+void LLToolBarButton::setEnabled(bool enabled)
+{
+ if (enabled)
+ {
+ mImageSelected = mOriginalImageSelected;
+ mImageUnselected = mOriginalImageUnselected;
+ mImagePressed = mOriginalImagePressed;
+ mImagePressedSelected = mOriginalImagePressedSelected;
+ mUnselectedLabelColor = mOriginalLabelColor;
+ mSelectedLabelColor = mOriginalLabelColorSelected;
+ mImageOverlayColor = mOriginalImageOverlayColor;
+ mImageOverlaySelectedColor = mOriginalImageOverlaySelectedColor;
+ }
+ else
+ {
+ mImageSelected = mImageDisabledSelected;
+ mImageUnselected = mImageDisabled;
+ mImagePressed = mImageDisabled;
+ mImagePressedSelected = mImageDisabledSelected;
+ mUnselectedLabelColor = mDisabledLabelColor;
+ mSelectedLabelColor = mDisabledSelectedLabelColor;
+ mImageOverlayColor = mImageOverlayDisabledColor;
+ mImageOverlaySelectedColor = mImageOverlayDisabledColor;
+ }
+}
+
+const std::string LLToolBarButton::getToolTip() const
+{
+ std::string tooltip;
+
+ if (labelIsTruncated() || getCurrentLabel().empty())
+ {
+ tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip();
+ }
+ else
+ {
+ tooltip = LLView::getToolTip();
+ }
+
+ LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+ if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0)
+ {
+ tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")";
+ }
+
+ return tooltip;
+}
+
+void LLToolBar::LLCenterLayoutPanel::handleReshape(const LLRect& rect, bool by_user)
+{
+ LLLayoutPanel::handleReshape(rect, by_user);
+
+ if (!mReshapeCallback.empty())
+ {
+ LLRect r;
+ localRectToOtherView(mButtonPanel->getRect(), &r, gFloaterView);
+ r.stretch(FLOATER_MIN_VISIBLE_PIXELS);
+ mReshapeCallback(mLocationId, r);
+ }
+}
|