diff options
Diffstat (limited to 'indra/llui')
37 files changed, 1704 insertions, 241 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index b3b2f4ae56..dded8ab661 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -5,6 +5,7 @@ project(llui) include(00-Common) include(LLCommon) include(LLImage) +include(LLInventory) include(LLMath) include(LLMessage) include(LLRender) @@ -16,6 +17,7 @@ include(LLXUIXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} + ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} @@ -35,6 +37,7 @@ set(llui_SOURCE_FILES llcheckboxctrl.cpp llclipboard.cpp llcombobox.cpp + llcommandmanager.cpp llconsole.cpp llcontainerview.cpp llctrlselectioninterface.cpp @@ -99,6 +102,7 @@ set(llui_SOURCE_FILES lltimectrl.cpp lltransutil.cpp lltoggleablemenu.cpp + lltoolbar.cpp lltooltip.cpp llui.cpp lluicolortable.cpp @@ -131,6 +135,7 @@ set(llui_HEADER_FILES llcheckboxctrl.h llclipboard.h llcombobox.h + llcommandmanager.h llconsole.h llcontainerview.h llctrlselectioninterface.h @@ -200,6 +205,7 @@ set(llui_HEADER_FILES lltextvalidate.h lltimectrl.h lltoggleablemenu.h + lltoolbar.h lltooltip.h lltransutil.h lluicolortable.h @@ -245,6 +251,7 @@ target_link_libraries(llui ${LLRENDER_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLIMAGE_LIBRARIES} + ${LLINVENTORY_LIBRARIES} ${LLVFS_LIBRARIES} # ugh, just for LLDir ${LLXUIXML_LIBRARIES} ${LLXML_LIBRARIES} diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 2459429f6e..f259e8027e 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -314,7 +314,7 @@ boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t } -// *TODO: Deprecate (for backwards compatability only) +// *TODO: Deprecate (for backwards compatibility only) boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) { return setClickedCallback(boost::bind(cb, data)); @@ -554,6 +554,16 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) +{ + overlay_width = mImageOverlay->getWidth(); + overlay_height = mImageOverlay->getHeight(); + + F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); + overlay_width = llround((F32)overlay_width * scale_factor); + overlay_height = llround((F32)overlay_height * scale_factor); +} + // virtual void LLButton::draw() @@ -781,12 +791,10 @@ void LLButton::draw() if (mImageOverlay.notNull()) { // get max width and height (discard level 0) - S32 overlay_width = mImageOverlay->getWidth(); - S32 overlay_height = mImageOverlay->getHeight(); + S32 overlay_width; + S32 overlay_height; - F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); - overlay_width = llround((F32)overlay_width * scale_factor); - overlay_height = llround((F32)overlay_height * scale_factor); + getOverlayImageSize(overlay_width, overlay_height); S32 center_x = getLocalRect().getCenterX(); S32 center_y = getLocalRect().getCenterY(); @@ -811,6 +819,7 @@ void LLButton::draw() { case LLFontGL::LEFT: text_left += overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; mImageOverlay->draw( mLeftHPad, center_y - (overlay_height / 2), @@ -828,6 +837,7 @@ void LLButton::draw() break; case LLFontGL::RIGHT: text_right -= overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; mImageOverlay->draw( getRect().getWidth() - mRightHPad - overlay_width, center_y - (overlay_height / 2), @@ -919,7 +929,7 @@ void LLButton::setToggleState(BOOL b) void LLButton::setFlashing( BOOL b ) { - if (b != mFlashing) + if ((bool)b != mFlashing) { mFlashing = b; mFlashingTimer.reset(); @@ -989,11 +999,32 @@ void LLButton::resize(LLUIString label) // get current btn length S32 btn_width =getRect().getWidth(); // check if it need resize - if (mAutoResize == TRUE) + if (mAutoResize) { - if (btn_width - (mRightHPad + mLeftHPad) < label_width) + S32 min_width = label_width + mLeftHPad + mRightHPad; + if (mImageOverlay) + { + S32 overlay_width = mImageOverlay->getWidth(); + F32 scale_factor = getRect().getHeight() / (F32)mImageOverlay->getHeight(); + overlay_width = llround((F32)overlay_width * scale_factor); + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + case LLFontGL::RIGHT: + min_width += overlay_width + mImgOverlayLabelSpace; + break; + case LLFontGL::HCENTER: + min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad); + break; + default: + // draw nothing + break; + } + } + if (btn_width < min_width) { - setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom)); + reshape(min_width, getRect().getHeight()); } } } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 5968916006..08b45e01b3 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -270,6 +270,7 @@ public: protected: LLPointer<LLUIImage> getImageUnselected() const { return mImageUnselected; } LLPointer<LLUIImage> getImageSelected() const { return mImageSelected; } + void getOverlayImageSize(S32& overlay_width, S32& overlay_height); LLFrameTimer mMouseDownTimer; @@ -327,15 +328,14 @@ private: LLUIColor mImageColor; LLUIColor mDisabledImageColor; - BOOL mIsToggle; - BOOL mScaleImage; + bool mIsToggle; + bool mScaleImage; - BOOL mDropShadowedText; - BOOL mAutoResize; - BOOL mUseEllipses; - BOOL mBorderEnabled; - - BOOL mFlashing; + bool mDropShadowedText; + bool mAutoResize; + bool mUseEllipses; + bool mBorderEnabled; + bool mFlashing; LLFontGL::HAlign mHAlign; S32 mLeftHPad; @@ -355,9 +355,9 @@ private: F32 mHoverGlowStrength; F32 mCurGlowStrength; - BOOL mNeedsHighlight; - BOOL mCommitOnReturn; - BOOL mFadeWhenDisabled; + bool mNeedsHighlight; + bool mCommitOnReturn; + bool mFadeWhenDisabled; bool mForcePressedState; LLFrameTimer mFlashingTimer; diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 984c4ec5fb..6910b962a1 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -40,6 +40,7 @@ LLClipboard gClipboard; LLClipboard::LLClipboard() { + mSourceItem = NULL; } @@ -134,3 +135,8 @@ BOOL LLClipboard::canPastePrimaryString() const { return LLView::getWindow()->isPrimaryTextAvailable(); } + +void LLClipboard::setSourceObject(const LLUUID& source_id, LLAssetType::EType type) +{ + mSourceItem = new LLInventoryObject (source_id, LLUUID::null, type, ""); +} diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 24cb46c3f4..9371b94284 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -30,6 +30,8 @@ #include "llstring.h" #include "lluuid.h" +#include "stdenums.h" +#include "llinventory.h" class LLClipboard @@ -52,9 +54,14 @@ public: BOOL canPastePrimaryString() const; const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL); + // Support clipboard for object known only by their uuid and asset type + void setSourceObject(const LLUUID& source_id, LLAssetType::EType type); + const LLInventoryObject* getSourceObject() { return mSourceItem; } + private: - LLUUID mSourceID; + LLUUID mSourceID; LLWString mString; + LLInventoryObject* mSourceItem; }; diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp new file mode 100644 index 0000000000..2bd50af7af --- /dev/null +++ b/indra/llui/llcommandmanager.cpp @@ -0,0 +1,182 @@ +/** + * @file llcommandmanager.cpp + * @brief LLCommandManager class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +// A control that displays the name of the chosen item, which when +// clicked shows a scrolling box of options. + +#include "linden_common.h" + +#include "llcommandmanager.h" +#include "lldir.h" +#include "llerror.h" +#include "llxuiparser.h" + +#include <boost/foreach.hpp> + + +// +// LLCommandId class +// + +const LLCommandId LLCommandId::null("null command"); + +// +// LLCommand class +// + +LLCommand::Params::Params() + : available_in_toybox("available_in_toybox", false) + , icon("icon") + , label_ref("label_ref") + , name("name") + , tooltip_ref("tooltip_ref") + , execute_function("execute_function") + , execute_parameters("execute_parameters") + , is_enabled_function("is_enabled_function") + , is_enabled_parameters("is_enabled_parameters") + , is_running_function("is_running_function") + , is_running_parameters("is_running_parameters") + , is_starting_function("is_starting_function") + , is_starting_parameters("is_starting_parameters") +{ +} + +LLCommand::LLCommand(const LLCommand::Params& p) + : mAvailableInToybox(p.available_in_toybox) + , mIcon(p.icon) + , mIdentifier(p.name) + , mLabelRef(p.label_ref) + , mTooltipRef(p.tooltip_ref) + , mExecuteFunction(p.execute_function) + , mExecuteParameters(p.execute_parameters) + , mIsEnabledFunction(p.is_enabled_function) + , mIsEnabledParameters(p.is_enabled_parameters) + , mIsRunningFunction(p.is_running_function) + , mIsRunningParameters(p.is_running_parameters) + , mIsStartingFunction(p.is_starting_function) + , mIsStartingParameters(p.is_starting_parameters) +{ +} + + +// +// LLCommandManager class +// + +LLCommandManager::LLCommandManager() +{ +} + +LLCommandManager::~LLCommandManager() +{ + for (CommandVector::iterator cmdIt = mCommands.begin(); cmdIt != mCommands.end(); ++cmdIt) + { + LLCommand * command = *cmdIt; + + delete command; + } +} + +U32 LLCommandManager::commandCount() const +{ + return mCommands.size(); +} + +LLCommand * LLCommandManager::getCommand(U32 commandIndex) +{ + return mCommands[commandIndex]; +} + +LLCommand * LLCommandManager::getCommand(const LLCommandId& commandId) +{ + LLCommand * command_match = NULL; + + CommandIndexMap::const_iterator found = mCommandIndices.find(commandId); + + if (found != mCommandIndices.end()) + { + command_match = mCommands[found->second]; + } + + return command_match; +} + +LLCommand * LLCommandManager::getCommand(const LLUUID& commandUUID) +{ + LLCommand * command_match = NULL; + + CommandUUIDMap::const_iterator found = mCommandUUIDs.find(commandUUID); + + if (found != mCommandUUIDs.end()) + { + command_match = mCommands[found->second]; + } + + return command_match; +} + +void LLCommandManager::addCommand(LLCommand * command) +{ + LLCommandId command_id = command->id(); + mCommandIndices[command_id] = mCommands.size(); + mCommandUUIDs[command_id.uuid()] = mCommands.size(); + mCommands.push_back(command); + + lldebugs << "Successfully added command: " << command->id().name() << llendl; +} + +//static +bool LLCommandManager::load() +{ + LLCommandManager& mgr = LLCommandManager::instance(); + + std::string commands_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "commands.xml"); + + LLCommandManager::Params commandsParams; + + LLSimpleXUIParser parser; + + if (!parser.readXUI(commands_file, commandsParams)) + { + llerrs << "Unable to load xml file: " << commands_file << llendl; + return false; + } + + if (!commandsParams.validateBlock()) + { + llerrs << "Unable to validate commands param block from file: " << commands_file << llendl; + return false; + } + + BOOST_FOREACH(LLCommand::Params& commandParams, commandsParams.commands) + { + LLCommand * command = new LLCommand(commandParams); + + mgr.addCommand(command); + } + + return true; +} diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h new file mode 100644 index 0000000000..b11f905574 --- /dev/null +++ b/indra/llui/llcommandmanager.h @@ -0,0 +1,199 @@ +/** + * @file llcommandmanager.h + * @brief LLCommandManager class to hold commands + * + * $LicenseInfo:firstyear=2001&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$ + */ + +#ifndef LL_LLCOMMANDMANAGER_H +#define LL_LLCOMMANDMANAGER_H + +#include "llinitparam.h" +#include "llsingleton.h" + + +class LLCommand; +class LLCommandManager; + + +class LLCommandId +{ +public: + friend class LLCommand; + friend class LLCommandManager; + + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; + + Params() + : name("name") + {} + }; + + LLCommandId(const std::string& name) + : mName(name) + { + mUUID = LLUUID::LLUUID::generateNewID(name); + } + + LLCommandId(const Params& p) + : mName(p.name) + { + mUUID = LLUUID::LLUUID::generateNewID(p.name); + } + + const std::string& name() const { return mName; } + const LLUUID& uuid() const { return mUUID; } + + bool operator!=(const LLCommandId& command) const + { + return (mName != command.mName); + } + + bool operator==(const LLCommandId& command) const + { + return (mName == command.mName); + } + + bool operator<(const LLCommandId& command) const + { + return (mName < command.mName); + } + + static const LLCommandId null; + +private: + std::string mName; + LLUUID mUUID; +}; + +typedef std::list<LLCommandId> command_id_list_t; + + +class LLCommand +{ +public: + struct Params : public LLInitParam::Block<Params> + { + Mandatory<bool> available_in_toybox; + Mandatory<std::string> icon; + Mandatory<std::string> label_ref; + Mandatory<std::string> name; + Mandatory<std::string> tooltip_ref; + + Mandatory<std::string> execute_function; + Optional<LLSD> execute_parameters; + + Optional<std::string> is_enabled_function; + Optional<LLSD> is_enabled_parameters; + + Optional<std::string> is_running_function; + Optional<LLSD> is_running_parameters; + + Optional<std::string> is_starting_function; + Optional<LLSD> is_starting_parameters; + + Params(); + }; + + LLCommand(const LLCommand::Params& p); + + const bool availableInToybox() const { return mAvailableInToybox; } + const std::string& icon() const { return mIcon; } + const LLCommandId& id() const { return mIdentifier; } + const std::string& labelRef() const { return mLabelRef; } + const std::string& tooltipRef() const { return mTooltipRef; } + + const std::string& executeFunctionName() const { return mExecuteFunction; } + const LLSD& executeParameters() const { return mExecuteParameters; } + + const std::string& isEnabledFunctionName() const { return mIsEnabledFunction; } + const LLSD& isEnabledParameters() const { return mIsEnabledParameters; } + + const std::string& isRunningFunctionName() const { return mIsRunningFunction; } + const LLSD& isRunningParameters() const { return mIsRunningParameters; } + + const std::string& isStartingFunctionName() const { return mIsStartingFunction; } + const LLSD& isStartingParameters() const { return mIsStartingParameters; } + +private: + LLCommandId mIdentifier; + + bool mAvailableInToybox; + std::string mIcon; + std::string mLabelRef; + std::string mTooltipRef; + + std::string mExecuteFunction; + LLSD mExecuteParameters; + + std::string mIsEnabledFunction; + LLSD mIsEnabledParameters; + + std::string mIsRunningFunction; + LLSD mIsRunningParameters; + + std::string mIsStartingFunction; + LLSD mIsStartingParameters; +}; + + +class LLCommandManager +: public LLSingleton<LLCommandManager> +{ +public: + struct Params : public LLInitParam::Block<Params> + { + Multiple< LLCommand::Params, AtLeast<1> > commands; + + Params() + : commands("command") + { + } + }; + + LLCommandManager(); + ~LLCommandManager(); + + U32 commandCount() const; + LLCommand * getCommand(U32 commandIndex); + LLCommand * getCommand(const LLCommandId& commandId); + LLCommand * getCommand(const LLUUID& commandUUID); + + static bool load(); + +protected: + void addCommand(LLCommand * command); + +private: + typedef std::map<LLUUID, U32> CommandUUIDMap; + typedef std::map<LLCommandId, U32> CommandIndexMap; + typedef std::vector<LLCommand *> CommandVector; + + CommandVector mCommands; + CommandIndexMap mCommandIndices; + CommandUUIDMap mCommandUUIDs; +}; + + +#endif // LL_LLCOMMANDMANAGER_H diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index b1c27126d9..6e39fcd714 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -97,6 +97,7 @@ void LLDockControl::getAllowedRect(LLRect& rect) void LLDockControl::repositionDockable() { + if (!mDockWidget) return; LLRect dockRect = mDockWidget->calcScreenRect(); LLRect rootRect; mGetAllowedRectCallback(rootRect); @@ -160,7 +161,7 @@ bool LLDockControl::isDockVisible() case TOP: { // check is dock inside parent rect - // assume that parent for all dockable flaoters + // assume that parent for all dockable floaters // is the root view LLRect dockParentRect = mDockWidget->getRootView()->calcScreenRect(); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 58c2d34253..fba59e82e1 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -293,7 +293,7 @@ public: protected: virtual void applySavedVariables(); - void applyRectControl(); + virtual void applyRectControl(); void applyDockState(); void storeRectControl(); void storeVisibilityControl(); diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index fc7dcfcc4e..27e96856b3 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -453,6 +453,47 @@ void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname) } //static +void LLFloaterReg::toggleToolbarFloaterInstance(const LLSD& sdname) +{ + // + // Floaters controlled by the toolbar behave a bit differently from others. + // Namely they have 3-4 states as defined in the design wiki page here: + // https://wiki.lindenlab.com/wiki/FUI_Button_states + // + // The basic idea is this: + // * If the target floater is minimized, this button press will un-minimize it. + // * Else if the target floater is closed open it. + // * Else if the target floater does not have focus, give it focus. + // * Also, if it is not on top, bring it forward when focus is given. + // * Else the target floater is open, close it. + // + + // First parse the parameter + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + + LLFloater* instance = findInstance(name, key); + + if (LLFloater::isMinimized(instance)) + { + instance->setMinimized(FALSE); + } + else if (!LLFloater::isShown(instance)) + { + showInstance(name, key, TRUE); + } + else if (!instance->hasFocus() && !instance->getIsChrome()) + { + instance->setFocus(TRUE); + } + else + { + instance->closeFloater(); + } +} + +//static bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname) { LLSD key; diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index a2027a77a0..6239d98a7d 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -127,6 +127,7 @@ public: static void showFloaterInstance(const LLSD& sdname); static void hideFloaterInstance(const LLSD& sdname); static void toggleFloaterInstance(const LLSD& sdname); + static void toggleToolbarFloaterInstance(const LLSD& sdname); static bool floaterInstanceVisible(const LLSD& sdname); static bool floaterInstanceMinimized(const LLSD& sdname); diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index a250404292..4991c4afa6 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -58,7 +58,9 @@ LLLayoutPanel::LLLayoutPanel(const Params& p) mCollapsed(FALSE), mCollapseAmt(0.f), mVisibleAmt(1.f), // default to fully visible - mResizeBar(NULL) + mResizeBar(NULL), + mFractionalSize(0.f), + mOrientation(LLLayoutStack::HORIZONTAL) { // Set the expanded min dim if it is provided, otherwise it gets the p.min_dim value if (p.expanded_min_dim.isProvided()) @@ -88,9 +90,22 @@ LLLayoutPanel::~LLLayoutPanel() mResizeBar = NULL; } -F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation) +void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent) { - if (orientation == LLLayoutStack::HORIZONTAL) + if (mOrientation == LLLayoutStack::HORIZONTAL) + { + mFractionalSize += width - llround(mFractionalSize); + } + else + { + mFractionalSize += height - llround(mFractionalSize); + } + LLPanel::reshape(width, height, called_from_parent); +} + +F32 LLLayoutPanel::getCollapseFactor() +{ + if (mOrientation == LLLayoutStack::HORIZONTAL) { F32 collapse_amt = clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth())); @@ -149,11 +164,11 @@ void LLLayoutStack::draw() // scale clipping rectangle by visible amount if (mOrientation == HORIZONTAL) { - clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation)); + clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); } else { - clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation)); + clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); } LLPanel* panelp = (*panel_it); @@ -193,36 +208,15 @@ bool LLLayoutStack::addChild(LLView* child, S32 tab_group) LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child); if (panelp) { + panelp->mFractionalSize = (mOrientation == HORIZONTAL) + ? panelp->getRect().getWidth() + : panelp->getRect().getHeight(); + panelp->setOrientation(mOrientation); mPanels.push_back(panelp); } return LLView::addChild(child, tab_group); } - -S32 LLLayoutStack::getDefaultHeight(S32 cur_height) -{ - // if we are spanning our children (crude upward propagation of size) - // then don't enforce our size on our children - if (mOrientation == HORIZONTAL) - { - cur_height = llmax(mMinHeight, getRect().getHeight()); - } - - return cur_height; -} - -S32 LLLayoutStack::getDefaultWidth(S32 cur_width) -{ - // if we are spanning our children (crude upward propagation of size) - // then don't enforce our size on our children - if (mOrientation == VERTICAL) - { - cur_width = llmax(mMinWidth, getRect().getWidth()); - } - - return cur_width; -} - void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front) { LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move); @@ -317,9 +311,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize) createResizeBars(); // calculate current extents - S32 total_width = 0; - S32 total_height = 0; + F32 total_size = 0.f; + // + // animate visibility + // e_panel_list_t::iterator panel_it; for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { @@ -361,179 +357,110 @@ void LLLayoutStack::updateLayout(BOOL force_resize) } } - if (panelp->mCollapsed) - { - panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); - } - else - { - panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); - } + F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f; + panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); - if (mOrientation == HORIZONTAL) - { - // enforce minimize size constraint by default - if (panelp->getRect().getWidth() < panelp->getRelevantMinDim()) - { - panelp->reshape(panelp->getRelevantMinDim(), panelp->getRect().getHeight()); - } - total_width += llround(panelp->getRect().getWidth() * panelp->getCollapseFactor(mOrientation)); - // want n-1 panel gaps for n panels - if (panel_it != mPanels.begin()) - { - total_width += mPanelSpacing; - } - } - else //VERTICAL + total_size += panelp->mFractionalSize * panelp->getCollapseFactor(); + // want n-1 panel gaps for n panels + if (panel_it != mPanels.begin()) { - // enforce minimize size constraint by default - if (panelp->getRect().getHeight() < panelp->getRelevantMinDim()) - { - panelp->reshape(panelp->getRect().getWidth(), panelp->getRelevantMinDim()); - } - total_height += llround(panelp->getRect().getHeight() * panelp->getCollapseFactor(mOrientation)); - if (panel_it != mPanels.begin()) - { - total_height += mPanelSpacing; - } + total_size += mPanelSpacing; } } S32 num_resizable_panels = 0; - S32 shrink_headroom_available = 0; - S32 shrink_headroom_total = 0; + F32 shrink_headroom_available = 0.f; + F32 shrink_headroom_total = 0.f; for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { + LLLayoutPanel* panelp = (*panel_it); + // panels that are not fully visible do not count towards shrink headroom - if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f) + if (panelp->getCollapseFactor() < 1.f) { continue; } - S32 relevant_dimension = (mOrientation == HORIZONTAL) ? (*panel_it)->getRect().getWidth() : (*panel_it)->getRect().getHeight(); - S32 relevant_min = (*panel_it)->getRelevantMinDim(); + F32 cur_size = panelp->mFractionalSize; + F32 min_size = (F32)panelp->getRelevantMinDim(); // if currently resizing a panel or the panel is flagged as not automatically resizing // only track total available headroom, but don't use it for automatic resize logic - if ((*panel_it)->mResizeBar->hasMouseCapture() - || (!(*panel_it)->mAutoResize + if (panelp->mResizeBar->hasMouseCapture() + || (!panelp->mAutoResize && !force_resize)) { - shrink_headroom_total += relevant_dimension - relevant_min; + shrink_headroom_total += cur_size - min_size; } else { num_resizable_panels++; - shrink_headroom_available += relevant_dimension - relevant_min; - shrink_headroom_total += relevant_dimension - relevant_min; + shrink_headroom_available += cur_size - min_size; + shrink_headroom_total += cur_size - min_size; } } // calculate how many pixels need to be distributed among layout panels // positive means panels need to grow, negative means shrink - S32 pixels_to_distribute; - if (mOrientation == HORIZONTAL) - { - pixels_to_distribute = getRect().getWidth() - total_width; - } - else //VERTICAL - { - pixels_to_distribute = getRect().getHeight() - total_height; - } + F32 pixels_to_distribute = (mOrientation == HORIZONTAL) + ? getRect().getWidth() - total_size + : getRect().getHeight() - total_size; // now we distribute the pixels... - S32 cur_x = 0; - S32 cur_y = getRect().getHeight(); + F32 cur_x = 0.f; + F32 cur_y = (F32)getRect().getHeight(); for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) { LLLayoutPanel* panelp = (*panel_it); - S32 cur_width = panelp->getRect().getWidth(); - S32 cur_height = panelp->getRect().getHeight(); - S32 new_width = cur_width; - S32 new_height = cur_height; - S32 relevant_min = panelp->getRelevantMinDim(); - - if (mOrientation == HORIZONTAL) - { - new_width = llmax(relevant_min, new_width); - } - else - { - new_height = llmax(relevant_min, new_height); - } - S32 delta_size = 0; + F32 min_size = panelp->getRelevantMinDim(); + F32 delta_size = 0.f; // if panel can automatically resize (not animating, and resize flag set)... - if (panelp->getCollapseFactor(mOrientation) == 1.f + if (panelp->getCollapseFactor() == 1.f && (force_resize || panelp->mAutoResize) && !panelp->mResizeBar->hasMouseCapture()) { - if (mOrientation == HORIZONTAL) + if (pixels_to_distribute < 0.f) { - // if we're shrinking - if (pixels_to_distribute < 0) - { - // shrink proportionally to amount over minimum - // so we can do this in one pass - delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - relevant_min) / (F32)shrink_headroom_available)) : 0; - shrink_headroom_available -= (cur_width - relevant_min); - } - else - { - // grow all elements equally - delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels); - num_resizable_panels--; - } - pixels_to_distribute -= delta_size; - new_width = llmax(relevant_min, cur_width + delta_size); + // shrink proportionally to amount over minimum + // so we can do this in one pass + delta_size = (shrink_headroom_available > 0.f) + ? pixels_to_distribute * ((F32)(panelp->mFractionalSize - min_size) / shrink_headroom_available) + : 0.f; + shrink_headroom_available -= (panelp->mFractionalSize - min_size); } else { - new_width = getDefaultWidth(new_width); - } - - if (mOrientation == VERTICAL) - { - if (pixels_to_distribute < 0) - { - // shrink proportionally to amount over minimum - // so we can do this in one pass - delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - relevant_min) / (F32)shrink_headroom_available)) : 0; - shrink_headroom_available -= (cur_height - relevant_min); - } - else - { - delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels); - num_resizable_panels--; - } - pixels_to_distribute -= delta_size; - new_height = llmax(relevant_min, cur_height + delta_size); - } - else - { - new_height = getDefaultHeight(new_height); - } - } - else - { - if (mOrientation == HORIZONTAL) - { - new_height = getDefaultHeight(new_height); - } - else // VERTICAL - { - new_width = getDefaultWidth(new_width); + // grow all elements equally + delta_size = pixels_to_distribute / (F32)num_resizable_panels; + num_resizable_panels--; } + + panelp->mFractionalSize = llmax(min_size, panelp->mFractionalSize + delta_size); + pixels_to_distribute -= delta_size; } // adjust running headroom count based on new sizes shrink_headroom_total += delta_size; LLRect panel_rect; - panel_rect.setLeftTopAndSize(cur_x, cur_y, new_width, new_height); + if (mOrientation == HORIZONTAL) + { + panel_rect.setLeftTopAndSize(llround(cur_x), + llround(cur_y), + llround(panelp->mFractionalSize), + getRect().getHeight()); + } + else + { + panel_rect.setLeftTopAndSize(llround(cur_x), + llround(cur_y), + getRect().getWidth(), + llround(panelp->mFractionalSize)); + } panelp->setShape(panel_rect); LLRect resize_bar_rect = panel_rect; @@ -549,13 +476,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize) } (*panel_it)->mResizeBar->setRect(resize_bar_rect); + F32 size = ((*panel_it)->mFractionalSize * (*panel_it)->getCollapseFactor()) + (F32)mPanelSpacing; if (mOrientation == HORIZONTAL) { - cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing; + cur_x += size; } else //VERTICAL { - cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing; + cur_y -= size; } } @@ -570,13 +498,13 @@ void LLLayoutStack::updateLayout(BOOL force_resize) { (*panel_it)->mResizeBar->setResizeLimits( relevant_min, - relevant_min + shrink_headroom_total); + relevant_min + llround(shrink_headroom_total)); } else //VERTICAL { (*panel_it)->mResizeBar->setResizeLimits( relevant_min, - relevant_min + shrink_headroom_total); + relevant_min + llround(shrink_headroom_total)); } // toggle resize bars based on panel visibility, resizability, etc diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index d8ef0aeaca..5d79505fc3 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -126,8 +126,6 @@ protected: private: void createResizeBars(); void calcMinExtents(); - S32 getDefaultHeight(S32 cur_height); - S32 getDefaultWidth(S32 cur_width); const ELayoutOrientation mOrientation; @@ -181,6 +179,8 @@ public: void initFromParams(const Params& p); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + S32 getMinDim() const { return mMinDim; } void setMinDim(S32 value) { mMinDim = value; if (!mExpandedMinDimSpecified) mExpandedMinDim = value; } @@ -202,22 +202,26 @@ public: return min_dim; } + void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; } + protected: LLLayoutPanel(const Params& p); - F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation); + F32 getCollapseFactor(); - bool mExpandedMinDimSpecified; - S32 mExpandedMinDim; + bool mExpandedMinDimSpecified; + S32 mExpandedMinDim; - S32 mMinDim; - S32 mMaxDim; - BOOL mAutoResize; - BOOL mUserResize; - BOOL mCollapsed; + S32 mMinDim; + S32 mMaxDim; + bool mAutoResize; + bool mUserResize; + bool mCollapsed; + F32 mVisibleAmt; + F32 mCollapseAmt; + F32 mFractionalSize; + LLLayoutStack::ELayoutOrientation mOrientation; class LLResizeBar* mResizeBar; - F32 mVisibleAmt; - F32 mCollapseAmt; }; diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 583bde360a..2518dbe3c7 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -60,7 +60,7 @@ public: typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t; - struct MaxLength : public LLInitParam::Choice<MaxLength> + struct MaxLength : public LLInitParam::ChoiceBlock<MaxLength> { Alternative<S32> bytes, chars; diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp index c4eec1835c..6ac38f5ad4 100644 --- a/indra/llui/llloadingindicator.cpp +++ b/indra/llui/llloadingindicator.cpp @@ -34,6 +34,7 @@ // Project includes #include "lluictrlfactory.h" #include "lluiimage.h" +#include "boost/foreach.hpp" // registered in llui.cpp to avoid being left out by MS linker //static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator"); @@ -51,11 +52,9 @@ LLLoadingIndicator::LLLoadingIndicator(const Params& p) void LLLoadingIndicator::initFromParams(const Params& p) { - for (LLInitParam::ParamIterator<LLUIImage*>::const_iterator it = p.images().image.begin(), end_it = p.images().image.end(); - it != end_it; - ++it) + BOOST_FOREACH(LLUIImage* image, p.images.image) { - mImages.push_back(it->getValue()); + mImages.push_back(image); } // Start timer for switching images. diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h index 7c44478848..c1f979c111 100644 --- a/indra/llui/llloadingindicator.h +++ b/indra/llui/llloadingindicator.h @@ -51,7 +51,7 @@ class LLLoadingIndicator LOG_CLASS(LLLoadingIndicator); public: - struct Images : public LLInitParam::Block<Images> + struct Images : public LLInitParam::BatchBlock<Images> { Multiple<LLUIImage*> image; @@ -63,7 +63,7 @@ public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { Optional<F32> images_per_sec; - Batch<Images> images; + Optional<Images> images; Params() : images_per_sec("images_per_sec", 1.0f), diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 6cac841cde..badba7a416 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -947,7 +947,7 @@ LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p) LLMenuItemBranchGL::~LLMenuItemBranchGL() { - LLView::deleteViewByHandle(mBranchHandle); + delete mBranchHandle.get(); } // virtual diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 0c4d4fc897..462d69be2e 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -201,7 +201,7 @@ public: FormInput(); }; - struct FormElement : public LLInitParam::Choice<FormElement> + struct FormElement : public LLInitParam::ChoiceBlock<FormElement> { Alternative<FormButton> button; Alternative<FormInput> input; @@ -312,7 +312,7 @@ public: Optional<LLNotificationContext*> context; Optional<void*> responder; - struct Functor : public LLInitParam::Choice<Functor> + struct Functor : public LLInitParam::ChoiceBlock<Functor> { Alternative<std::string> name; Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index ab777d37a5..fb50c9c123 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -91,7 +91,7 @@ struct LLNotificationTemplate // <notification> <unique/> </notification> // as well as // <notification> <unique> <context></context> </unique>... - Flag dummy_val; + Optional<LLInitParam::Flag> dummy_val; public: Multiple<UniquenessContext> contexts; @@ -147,7 +147,7 @@ struct LLNotificationTemplate {} }; - struct FormRef : public LLInitParam::Choice<FormRef> + struct FormRef : public LLInitParam::ChoiceBlock<FormRef> { Alternative<LLNotificationForm::Params> form; Alternative<TemplateRef> form_template; diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h index 78bdec2a8f..78788a275c 100644 --- a/indra/llui/llnotificationvisibilityrule.h +++ b/indra/llui/llnotificationvisibilityrule.h @@ -59,7 +59,7 @@ struct LLNotificationVisibilityRule {} }; - struct Rule : public LLInitParam::Choice<Rule> + struct Rule : public LLInitParam::ChoiceBlock<Rule> { Alternative<Filter> show; Alternative<Filter> hide; diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 790025cb2d..ab1c87caff 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -96,9 +96,6 @@ public: Params(); }; - // valid children for LLPanel are stored in this registry - typedef LLDefaultChildRegistry child_registry_t; - protected: friend class LLUICtrlFactory; // RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8 diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp index c3a51c36c9..942e84eeb6 100644 --- a/indra/llui/llresizehandle.cpp +++ b/indra/llui/llresizehandle.cpp @@ -55,6 +55,8 @@ LLResizeHandle::LLResizeHandle(const LLResizeHandle::Params& p) mImage( NULL ), mMinWidth( p.min_width ), mMinHeight( p.min_height ), + mMaxWidth(S32_MAX), + mMaxHeight(S32_MAX), mCorner( p.corner ) { if( RIGHT_BOTTOM == mCorner) @@ -177,6 +179,11 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask) new_width = mMinWidth; delta_x = x_multiple * (mMinWidth - orig_rect.getWidth()); } + else if (new_width > mMaxWidth) + { + new_width = mMaxWidth; + delta_x = x_multiple * (mMaxWidth - orig_rect.getWidth()); + } S32 new_height = orig_rect.getHeight() + y_multiple * delta_y; if( new_height < mMinHeight ) @@ -184,6 +191,11 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask) new_height = mMinHeight; delta_y = y_multiple * (mMinHeight - orig_rect.getHeight()); } + else if (new_height > mMaxHeight) + { + new_height = mMaxHeight; + delta_y = y_multiple * (mMaxHeight - orig_rect.getHeight()); + } switch( mCorner ) { diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h index 531eb1db61..5cfe3fb63c 100644 --- a/indra/llui/llresizehandle.h +++ b/indra/llui/llresizehandle.h @@ -56,6 +56,9 @@ public: void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } + void setMaxWidth(S32 width) { mMaxWidth = width;} + void setMaxHeight(S32 height) { mMaxHeight = height;} + private: BOOL pointInHandle( S32 x, S32 y ); @@ -66,7 +69,9 @@ private: LLCoordGL mLastMouseDir; LLPointer<LLUIImage> mImage; S32 mMinWidth; + S32 mMaxWidth; S32 mMinHeight; + S32 mMaxHeight; const ECorner mCorner; }; diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h index 12baea8e0c..b4d4a6d05e 100644 --- a/indra/llui/llscrolllistcolumn.h +++ b/indra/llui/llscrolllistcolumn.h @@ -95,7 +95,7 @@ public: Optional<ESortDirection, SortNames> sort_direction; Optional<bool> sort_ascending; - struct Width : public LLInitParam::Choice<Width> + struct Width : public LLInitParam::ChoiceBlock<Width> { Alternative<bool> dynamic_width; Alternative<S32> pixel_width; @@ -112,7 +112,7 @@ public: Optional<Width> width; // either an image or label is used in column header - struct Header : public LLInitParam::Choice<Header> + struct Header : public LLInitParam::ChoiceBlock<Header> { Alternative<std::string> label; Alternative<LLUIImage*> image; diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index 04919e6991..4b69360e33 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -45,7 +45,7 @@ LLParamSDParser::LLParamSDParser() if (sReadFuncs.empty()) { - registerParserFuncs<LLInitParam::NoParamValue>(readNoValue, &LLParamSDParser::writeNoValue); + registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag); registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); @@ -72,7 +72,7 @@ bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const voi return true; } -bool LLParamSDParser::writeNoValue(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) +bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) { LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); if (!sdparser.mWriteRootSD) return false; @@ -226,7 +226,7 @@ LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack) return sd_to_write; } -bool LLParamSDParser::readNoValue(Parser& parser, void* val_ptr) +bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) { LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); return self.mCurReadSD == &NO_VALUE_MARKER; diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h index f776c781b3..a371c28f68 100644 --- a/indra/llui/llsdparam.h +++ b/indra/llui/llsdparam.h @@ -63,9 +63,9 @@ private: LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack); static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); - static bool writeNoValue(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); + static bool writeFlag(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); - static bool readNoValue(Parser& parser, void* val_ptr); + static bool readFlag(Parser& parser, void* val_ptr); static bool readS32(Parser& parser, void* val_ptr); static bool readU32(Parser& parser, void* val_ptr); static bool readF32(Parser& parser, void* val_ptr); diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 7d545a1ba6..384d9116fc 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -237,7 +237,7 @@ public: friend class LLNormalTextSegment; friend class LLUICtrlFactory; - struct LineSpacingParams : public LLInitParam::Choice<LineSpacingParams> + struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams> { Alternative<F32> multiple; Alternative<S32> pixels; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp new file mode 100644 index 0000000000..07beb147d7 --- /dev/null +++ b/indra/llui/lltoolbar.cpp @@ -0,0 +1,682 @@ +/** + * @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 <boost/foreach.hpp> +#include "lltoolbar.h" + +#include "llcommandmanager.h" +#include "llmenugl.h" +#include "lltrans.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 +{ + LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType) + { + LLLayoutStack::ELayoutOrientation 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"), + 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), + mButtonPanel(NULL), + mCenteringStack(NULL), + mPadLeft(p.pad_left), + mPadRight(p.pad_right), + mPadTop(p.pad_top), + mPadBottom(p.pad_bottom), + mPadBetween(p.pad_between), + mPopupMenuHandle() +{ + mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; + mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; +} + +LLToolBar::~LLToolBar() +{ + delete mPopupMenuHandle.get(); +} + +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)); + + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg; + enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2)); + + // Create the context menu + 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(); + } + else + { + llwarns << "Unable to load toolbars context menu." << llendl; + } + } +} + +void LLToolBar::initFromParams(const LLToolBar::Params& p) +{ + // Initialize the base object + LLUICtrl::initFromParams(p); + + LLLayoutStack::ELayoutOrientation 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; + LLLayoutPanel* center_panel = LLUICtrlFactory::create<LLLayoutPanel>(center_panel_p); + mCenteringStack->addChild(center_panel); + + LLPanel::Params button_panel_p(p.button_panel); + button_panel_p.rect = center_panel->getLocalRect(); + button_panel_p.follows.flags = FOLLOWS_BOTTOM|FOLLOWS_LEFT; + mButtonPanel = LLUICtrlFactory::create<LLPanel>(button_panel_p); + center_panel->addChild(mButtonPanel); + + mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); + + BOOST_FOREACH(LLCommandId::Params params, p.commands) + { + addCommand(params); + } + + 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, button)); + + // Insert the command and button in the right place in their respective lists + if ((rank >= mButtonCommands.size()) || (rank < 0)) + { + // In that case, back load + mButtonCommands.push_back(commandId); + 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,commandId); + mButtons.insert(it_button,button); + } + + mNeedsLayout = true; + + return true; +} + +bool LLToolBar::removeCommand(const LLCommandId& commandId) +{ + if (!hasCommand(commandId)) return false; + + // First erase the map record + command_id_map::iterator it = mButtonMap.find(commandId); + mButtonMap.erase(it); + + // Now iterate on the commands and buttons to identify the relevant records + 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; + } + + // Delete the button and erase the command and button records + delete (*it_button); + mButtonCommands.erase(it_command); + mButtons.erase(it_button); + + mNeedsLayout = true; + + return true; +} + +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); + 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); + if (it != mButtonMap.end()) + { + it->second->setEnabled(enabled); + } + } + + 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) + { + 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::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 + BOOST_FOREACH(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()); + } + } +} + +int LLToolBar::getRankFromPosition(S32 x, S32 y) +{ + int rank = 0; + + LLLayoutStack::ELayoutOrientation orientation = getOrientation(mSideType); + + // Simply compare the passed coord with the buttons outbound box + std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); + std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); + while (it_button != end_button) + { + LLRect button_rect = (*it_button)->getRect(); + if (((orientation == LLLayoutStack::HORIZONTAL) && (button_rect.mRight > x)) || + ((orientation == LLLayoutStack::VERTICAL) && (button_rect.mTop > y)) ) + { + llinfos << "Merov debug : rank compute: orientation = " << orientation << ", x = " << x << ", y = " << y << llendl; + llinfos << "Merov debug : rank compute: rect = " << button_rect.mLeft << ", " << button_rect.mTop << ", " << button_rect.mRight << ", " << button_rect.mBottom << llendl; + break; + } + rank++; + ++it_button; + } + llinfos << "Merov debug : rank = " << rank << llendl; + + return rank; +} + +void LLToolBar::updateLayoutAsNeeded() +{ + if (!mNeedsLayout) return; + + LLLayoutStack::ELayoutOrientation 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 max_total_girth; + 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; + max_total_girth = getRect().getHeight() - mPadTop - mPadBottom; + row_pad_start = mPadLeft; + row_pad_end = mPadRight; + cur_row = mPadTop; + girth_pad_end = mPadBottom; + } + else // VERTICAL + { + max_length = getRect().getHeight() - mPadTop - mPadBottom; + max_total_girth = getRect().getWidth() - mPadLeft - mPadRight; + 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; + + BOOST_FOREACH(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 + 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(); + + // don't clear flag until after we've resized ourselves, to avoid laying out every frame + mNeedsLayout = false; +} + + +void LLToolBar::draw() +{ + if (mButtons.empty()) return; + updateLayoutAsNeeded(); + // rect may have shifted during layout + LLUI::popMatrix(); + LLUI::pushMatrix(); + LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom, 0.f); + + LLUICtrl::draw(); +} + +void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLUICtrl::reshape(width, height, called_from_parent); + mNeedsLayout = true; +} + +void LLToolBar::createButtons() +{ + BOOST_FOREACH(LLToolBarButton* button, mButtons) + { + delete button; + } + mButtons.clear(); + mButtonMap.clear(); + + BOOST_FOREACH(LLCommandId& command_id, mButtonCommands) + { + LLToolBarButton* button = createButton(command_id); + mButtons.push_back(button); + mButtonPanel->addChild(button); + mButtonMap.insert(std::make_pair(command_id, button)); + } + mNeedsLayout = true; +} + +LLToolBarButton* LLToolBar::createButton(const LLCommandId& id) +{ + LLCommand* commandp = LLCommandManager::instance().getCommand(id); + if (!commandp) return NULL; + + std::string label = LLTrans::getString(commandp->labelRef()); + std::string tooltip = label + "\n" + LLTrans::getString(commandp->tooltipRef()); + + LLToolBarButton::Params button_p; + button_p.name = id.name(); + button_p.label = label; + button_p.tool_tip = tooltip; + button_p.image_overlay = LLUI::getUIImage(commandp->icon()); + button_p.overwriteFrom(mButtonParams[mButtonType]); + LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p); + + if (!mReadOnly) + { + LLUICtrl::CommitCallbackParam cbParam; + cbParam.function_name = commandp->executeFunctionName(); + cbParam.parameter = commandp->executeParameters(); + button->setCommitCallback(cbParam); + button->setStartDragCallback(mStartDragItemCallback); + button->setHandleDragCallback(mHandleDragItemCallback); + } + + button->setCommandId(id); + return button; + +} + +BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + llinfos << "Merov debug : handleDragAndDrop. drop = " << drop << ", x = " << x << ", y = " << y << llendl; + // If we have a drop callback, that means that we can handle the drop + BOOL handled = (mHandleDropCallback ? TRUE : FALSE); + + // 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 = handled; + + return handled; +} + +LLToolBarButton::LLToolBarButton(const Params& p) +: LLButton(p), + mMouseDownX(0), + mMouseDownY(0), + mWidthRange(p.button_width), + mDesiredHeight(p.desired_height), + mId("") +{ +} + +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) +{ +// llinfos << "Merov debug: handleHover, x = " << x << ", y = " << y << ", mouse = " << hasMouseCapture() << llendl; + BOOL handled = FALSE; + + if (hasMouseCapture() && mStartDragItemCallback && mHandleDragItemCallback) + { + if (!mIsDragged) + { + mStartDragItemCallback(x,y,mId.uuid()); + mIsDragged = true; + handled = TRUE; + } + else + { + handled = mHandleDragItemCallback(x,y,mId.uuid(),LLAssetType::AT_WIDGET); + } + } + else + { + handled = LLButton::handleHover(x, y, mask); + } + return handled; +} + diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h new file mode 100644 index 0000000000..a35f6d9db1 --- /dev/null +++ b/indra/llui/lltoolbar.h @@ -0,0 +1,218 @@ +/** + * @file lltoolbar.h + * @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$ + */ + +#ifndef LL_LLTOOLBAR_H +#define LL_LLTOOLBAR_H + +#include "llbutton.h" +#include "llcommandmanager.h" +#include "lllayoutstack.h" +#include "lluictrl.h" +#include "llcommandmanager.h" +#include "llassettype.h" + +class LLToolBar; + +typedef boost::function<void (S32 x, S32 y, const LLUUID& uuid)> tool_startdrag_callback_t; +typedef boost::function<BOOL (S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type)> tool_handledrag_callback_t; +typedef boost::function<BOOL (void* data, S32 x, S32 y, LLToolBar* toolbar)> tool_handledrop_callback_t; + +class LLToolBarButton : public LLButton +{ + friend class LLToolBar; +public: + struct Params : public LLInitParam::Block<Params, LLButton::Params> + { + Optional<LLUI::RangeS32> button_width; + Optional<S32> desired_height; + + Params() + : button_width("button_width"), + desired_height("desired_height", 20) + {} + + }; + + LLToolBarButton(const Params& p); + + BOOL handleMouseDown(S32 x, S32 y, MASK mask); + BOOL handleHover(S32 x, S32 y, MASK mask); + void setCommandId(const LLCommandId& id) { mId = id; } + + void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } + void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } +private: + LLCommandId mId; + S32 mMouseDownX; + S32 mMouseDownY; + LLUI::RangeS32 mWidthRange; + S32 mDesiredHeight; + bool mIsDragged; + tool_startdrag_callback_t mStartDragItemCallback; + tool_handledrag_callback_t mHandleDragItemCallback; +}; + + +namespace LLToolBarEnums +{ + enum ButtonType + { + BTNTYPE_ICONS_WITH_TEXT = 0, + BTNTYPE_ICONS_ONLY, + + BTNTYPE_COUNT + }; + + enum SideType + { + SIDE_BOTTOM, + SIDE_LEFT, + SIDE_RIGHT, + SIDE_TOP, + }; +} + +// NOTE: This needs to occur before Param block declaration for proper compilation. +namespace LLInitParam +{ + template<> + struct TypeValues<LLToolBarEnums::ButtonType> : public TypeValuesHelper<LLToolBarEnums::ButtonType> + { + static void declareValues(); + }; + + template<> + struct TypeValues<LLToolBarEnums::SideType> : public TypeValuesHelper<LLToolBarEnums::SideType> + { + static void declareValues(); + }; +} + + +class LLToolBar +: public LLUICtrl +{ +public: + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Mandatory<LLToolBarEnums::ButtonType> button_display_mode; + Mandatory<LLToolBarEnums::SideType> side; + + Optional<LLToolBarButton::Params> button_icon, + button_icon_and_text; + + Optional<bool> read_only, + wrap; + + Optional<S32> pad_left, + pad_top, + pad_right, + pad_bottom, + pad_between; + // get rid of this + Multiple<LLCommandId::Params> commands; + + Optional<LLPanel::Params> button_panel; + + Params(); + }; + + // virtuals + void draw(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + int getRankFromPosition(S32 x, S32 y); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + bool addCommand(const LLCommandId& commandId, int rank = -1); + bool removeCommand(const LLCommandId& commandId); + bool hasCommand(const LLCommandId& commandId) const; + bool enableCommand(const LLCommandId& commandId, bool enabled); + void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } + void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } + void setHandleDropCallback(tool_handledrop_callback_t cb) { mHandleDropCallback = cb; } + + LLToolBarButton* createButton(const LLCommandId& id); + +protected: + friend class LLUICtrlFactory; + LLToolBar(const Params&); + ~LLToolBar(); + + void initFromParams(const Params&); + tool_startdrag_callback_t mStartDragItemCallback; + tool_handledrag_callback_t mHandleDragItemCallback; + tool_handledrop_callback_t mHandleDropCallback; + bool mDragAndDropTarget; + +public: + // Methods used in loading and saving toolbar settings + void setButtonType(LLToolBarEnums::ButtonType button_type); + LLToolBarEnums::ButtonType getButtonType() { return mButtonType; } + command_id_list_t& getCommandsList() { return mButtonCommands; } + void clearCommandsList(); + +private: + void createContextMenu(); + void updateLayoutAsNeeded(); + void createButtons(); + void resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth); + BOOL isSettingChecked(const LLSD& userdata); + void onSettingEnable(const LLSD& userdata); + + const bool mReadOnly; + + std::list<LLToolBarButton*> mButtons; + command_id_list_t mButtonCommands; + typedef std::map<LLCommandId, LLToolBarButton*> command_id_map; + command_id_map mButtonMap; + + LLToolBarEnums::ButtonType mButtonType; + LLLayoutStack* mCenteringStack; + LLLayoutStack* mWrapStack; + LLPanel* mButtonPanel; + LLToolBarEnums::SideType mSideType; + + bool mWrap; + bool mNeedsLayout; + S32 mPadLeft, + mPadRight, + mPadTop, + mPadBottom, + mPadBetween; + + LLToolBarButton::Params mButtonParams[LLToolBarEnums::BTNTYPE_COUNT]; + + LLHandle<class LLContextMenu> mPopupMenuHandle; +}; + + +#endif // LL_LLTOOLBAR_H diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 58ba9e05f5..76a12e649b 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -41,6 +41,7 @@ #include "llgl.h" // Project includes +#include "llcommandmanager.h" #include "llcontrol.h" #include "llui.h" #include "lluicolortable.h" @@ -57,6 +58,7 @@ #include "llfiltereditor.h" #include "llflyoutbutton.h" #include "llsearcheditor.h" +#include "lltoolbar.h" // for XUIParse #include "llquaternion.h" @@ -94,6 +96,7 @@ static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor(" // register other widgets which otherwise may not be linked in static LLDefaultChildRegistry::Register<LLLoadingIndicator> register_loading_indicator("loading_indicator"); +static LLDefaultChildRegistry::Register<LLToolBar> register_toolbar("toolbar"); // // Functions @@ -1615,6 +1618,7 @@ void LLUI::initClass(const settings_map_t& settings, // Callbacks for associating controls with floater visibilty: reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2)); + reg.add("Floater.ToolbarToggle", boost::bind(&LLFloaterReg::toggleToolbarFloaterInstance, _2)); reg.add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2)); reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2)); reg.add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2)); @@ -1633,6 +1637,9 @@ void LLUI::initClass(const settings_map_t& settings, // Used by menus along with Floater.Toggle to display visibility as a checkmark LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2)); + + // Parse the master list of commands + LLCommandManager::load(); } void LLUI::cleanupClass() @@ -2100,7 +2107,7 @@ namespace LLInitParam void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock() { - if (control.isProvided()) + if (control.isProvided() && !control().empty()) { updateValue(LLUIColorTable::instance().getColor(control)); } @@ -2257,9 +2264,11 @@ namespace LLInitParam // in this case, that is left+width and bottom+height LLRect& value = getValue(); + right.set(value.mRight, false); left.set(value.mLeft, make_block_authoritative); width.set(value.getWidth(), make_block_authoritative); + top.set(value.mTop, false); bottom.set(value.mBottom, make_block_authoritative); height.set(value.getHeight(), make_block_authoritative); } diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 7801a01ace..28e84fa444 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -41,6 +41,7 @@ #include <boost/signals2.hpp> #include "lllazyvalue.h" #include "llframetimer.h" +#include <limits> // LLUIFactory #include "llsd.h" @@ -148,6 +149,122 @@ class LLUI LOG_CLASS(LLUI); public: // + // Classes + // + + struct RangeS32 + { + struct Params : public LLInitParam::Block<Params> + { + Optional<S32> minimum, + maximum; + + Params() + : minimum("min", 0), + maximum("max", S32_MAX) + {} + }; + + // correct for inverted params + RangeS32(const Params& p = Params()) + : mMin(p.minimum), + mMax(p.maximum) + { + sanitizeRange(); + } + + RangeS32(S32 minimum, S32 maximum) + : mMin(minimum), + mMax(maximum) + { + sanitizeRange(); + } + + S32 clamp(S32 input) + { + if (input < mMin) return mMin; + if (input > mMax) return mMax; + return input; + } + + void setRange(S32 minimum, S32 maximum) + { + mMin = minimum; + mMax = maximum; + sanitizeRange(); + } + + S32 getMin() { return mMin; } + S32 getMax() { return mMax; } + + bool operator==(const RangeS32& other) const + { + return mMin == other.mMin + && mMax == other.mMax; + } + private: + void sanitizeRange() + { + if (mMin > mMax) + { + llwarns << "Bad interval range (" << mMin << ", " << mMax << ")" << llendl; + // since max is usually the most dangerous one to ignore (buffer overflow, etc), prefer it + // in the case of a malformed range + mMin = mMax; + } + } + + + S32 mMin, + mMax; + }; + + struct ClampedS32 : public RangeS32 + { + struct Params : public LLInitParam::Block<Params, RangeS32::Params> + { + Mandatory<S32> value; + + Params() + : value("", 0) + { + addSynonym(value, "value"); + } + }; + + ClampedS32(const Params& p) + : RangeS32(p) + {} + + ClampedS32(const RangeS32& range) + : RangeS32(range) + { + // set value here, after range has been sanitized + mValue = clamp(0); + } + + ClampedS32(S32 value, const RangeS32& range = RangeS32()) + : RangeS32(range) + { + mValue = clamp(value); + } + + S32 get() + { + return mValue; + } + + void set(S32 value) + { + mValue = clamp(value); + } + + + private: + S32 mValue; + }; + + // // Methods // typedef std::map<std::string, LLControlGroup*> settings_map_t; @@ -365,7 +482,7 @@ template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister( template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass); // useful parameter blocks -struct TimeIntervalParam : public LLInitParam::Choice<TimeIntervalParam> +struct TimeIntervalParam : public LLInitParam::ChoiceBlock<TimeIntervalParam> { Alternative<F32> seconds; Alternative<S32> frames; diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index 76518789ec..6a7a681d57 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -44,7 +44,7 @@ LOG_CLASS(LLUIColorTable); typedef std::map<std::string, LLUIColor> string_color_map_t; public: - struct ColorParams : LLInitParam::Choice<ColorParams> + struct ColorParams : LLInitParam::ChoiceBlock<ColorParams> { Alternative<LLColor4> value; Alternative<std::string> reference; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index d58df5801b..5e8bf498c0 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -992,6 +992,16 @@ void LLUICtrl::setTransparencyType(ETypeTransparency type) mTransparencyType = type; } +boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb) +{ + return setCommitCallback(initCommitCallback(cb)); +} + +boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb) +{ + return setValidateCallback(initEnableCallback(cb)); +} + boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) { if (!mCommitSignal) mCommitSignal = new commit_signal_t(); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 09bed9b958..a8a4e3191d 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -76,14 +76,14 @@ public: Optional<enable_callback_t> function; }; - struct EnableControls : public LLInitParam::Choice<EnableControls> + struct EnableControls : public LLInitParam::ChoiceBlock<EnableControls> { Alternative<std::string> enabled; Alternative<std::string> disabled; EnableControls(); }; - struct ControlVisibility : public LLInitParam::Choice<ControlVisibility> + struct ControlVisibility : public LLInitParam::ChoiceBlock<ControlVisibility> { Alternative<std::string> visible; Alternative<std::string> invisible; @@ -235,6 +235,9 @@ public: // topic then put in help_topic_out bool findHelpTopic(std::string& help_topic_out); + boost::signals2::connection setCommitCallback(const CommitCallbackParam& cb); + boost::signals2::connection setValidateCallback(const EnableCallbackParam& cb); + boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ); diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index d345ad4cd0..d612ad5005 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -125,12 +125,12 @@ private: // base case for recursion, there are NO base classes of LLInitParam::BaseBlock template<int DUMMY> - class ParamDefaults<LLInitParam::BaseBlockWithFlags, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlockWithFlags, DUMMY> > + class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> > { public: - const LLInitParam::BaseBlockWithFlags& get() { return mBaseBlock; } + const LLInitParam::BaseBlock& get() { return mBaseBlock; } private: - LLInitParam::BaseBlockWithFlags mBaseBlock; + LLInitParam::BaseBlock mBaseBlock; }; public: @@ -172,7 +172,7 @@ public: static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry, LLXMLNodePtr output_node = NULL) { T* widget = NULL; - + std::string skinned_filename = findSkinnedFilename(filename); instance().pushFileName(filename); { @@ -201,10 +201,10 @@ public: // not of right type, so delete it if (!widget) { + llwarns << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << llendl; delete view; view = NULL; } - } } fail: diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 60452b9ae4..e10c2f0d1e 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1826,13 +1826,6 @@ LLView* LLView::findNextSibling(LLView* child) return (next_it != mChildList.end()) ? *next_it : NULL; } -void LLView::deleteViewByHandle(LLHandle<LLView> handle) -{ - LLView* viewp = handle.get(); - - delete viewp; -} - LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BOOL allow_partial_outside) { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 594a5eec6b..a1c46f3bf3 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -95,13 +95,10 @@ private: static std::vector<LLViewDrawContext*> sDrawContextStack; }; -class LLViewWidgetRegistry : public LLChildRegistry<LLViewWidgetRegistry> -{}; - class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElement { public: - struct Follows : public LLInitParam::Choice<Follows> + struct Follows : public LLInitParam::ChoiceBlock<Follows> { Alternative<std::string> string; Alternative<U32> flags; @@ -150,7 +147,8 @@ public: Params(); }; - typedef LLViewWidgetRegistry child_registry_t; + // most widgets are valid children of LLView + typedef LLDefaultChildRegistry child_registry_t; void initFromParams(const LLView::Params&); @@ -467,6 +465,20 @@ public: return dynamic_cast<T*>(widgetp); } + template <class T> T* getParentByType() const + { + LLView* parent = getParent(); + while(parent) + { + if (dynamic_cast<T*>(parent)) + { + return static_cast<T*>(parent); + } + parent = parent->getParent(); + } + return NULL; + } + ////////////////////////////////////////////// // statics ////////////////////////////////////////////// @@ -482,7 +494,6 @@ public: // return query for iterating over focus roots in tab order static const LLCtrlQuery & getFocusRootsQuery(); - static void deleteViewByHandle(LLHandle<LLView> handle); static LLWindow* getWindow(void) { return LLUI::sWindow; } // Set up params after XML load before calling new(), |