diff options
Diffstat (limited to 'indra/llui')
49 files changed, 3400 insertions, 1140 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index b3b2f4ae56..772f173f17 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 @@ -112,6 +116,7 @@ set(llui_SOURCE_FILES      llurlmatch.cpp      llurlregistry.cpp      llviewborder.cpp +    llviewinject.cpp      llviewmodel.cpp      llview.cpp      llviewquery.cpp @@ -131,6 +136,7 @@ set(llui_HEADER_FILES      llcheckboxctrl.h      llclipboard.h      llcombobox.h +    llcommandmanager.h      llconsole.h      llcontainerview.h      llctrlselectioninterface.h @@ -200,6 +206,7 @@ set(llui_HEADER_FILES      lltextvalidate.h      lltimectrl.h      lltoggleablemenu.h +    lltoolbar.h      lltooltip.h      lltransutil.h      lluicolortable.h @@ -216,6 +223,7 @@ set(llui_HEADER_FILES      llurlmatch.h      llurlregistry.h      llviewborder.h +    llviewinject.h      llviewmodel.h      llview.h      llviewquery.h @@ -245,6 +253,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..74b8885e1f 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -83,10 +83,11 @@ LLButton::Params::Params()  	label_color_selected("label_color_selected"),	// requires is_toggle true  	label_color_disabled("label_color_disabled"),  	label_color_disabled_selected("label_color_disabled_selected"), -	highlight_color("highlight_color"),  	image_color("image_color"),  	image_color_disabled("image_color_disabled"), -	image_overlay_color("image_overlay_color", LLColor4::white), +	image_overlay_color("image_overlay_color", LLColor4::white % 0.75f), +	image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), +	image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),  	flash_color("flash_color"),  	pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),  	pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), @@ -99,10 +100,13 @@ LLButton::Params::Params()  	scale_image("scale_image", true),  	hover_glow_amount("hover_glow_amount"),  	commit_on_return("commit_on_return", true), +	display_pressed_state("display_pressed_state", true),  	use_draw_context_alpha("use_draw_context_alpha", true),  	badge("badge"),  	handle_right_mouse("handle_right_mouse"), -	held_down_delay("held_down_delay") +	held_down_delay("held_down_delay"), +	button_flash_count("button_flash_count"), +	button_flash_rate("button_flash_rate")  {  	addSynonym(is_toggle, "toggle");  	changeDefault(initial_value, LLSD(false)); @@ -136,12 +140,13 @@ LLButton::LLButton(const LLButton::Params& p)  	mSelectedLabelColor(p.label_color_selected()),  	mDisabledLabelColor(p.label_color_disabled()),  	mDisabledSelectedLabelColor(p.label_color_disabled_selected()), -	mHighlightColor(p.highlight_color()),  	mImageColor(p.image_color()),  	mFlashBgColor(p.flash_color()),  	mDisabledImageColor(p.image_color_disabled()),  	mImageOverlay(p.image_overlay()),  	mImageOverlayColor(p.image_overlay_color()), +	mImageOverlayDisabledColor(p.image_overlay_disabled_color()), +	mImageOverlaySelectedColor(p.image_overlay_selected_color()),  	mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)),  	mImageOverlayTopPad(p.image_top_pad),  	mImageOverlayBottomPad(p.image_bottom_pad), @@ -159,12 +164,15 @@ LLButton::LLButton(const LLButton::Params& p)  	mCommitOnReturn(p.commit_on_return),  	mFadeWhenDisabled(FALSE),  	mForcePressedState(false), +	mDisplayPressedState(p.display_pressed_state),  	mLastDrawCharsCount(0),  	mMouseDownSignal(NULL),  	mMouseUpSignal(NULL),  	mHeldDownSignal(NULL),  	mUseDrawContextAlpha(p.use_draw_context_alpha), -	mHandleRightMouse(p.handle_right_mouse) +	mHandleRightMouse(p.handle_right_mouse), +	mButtonFlashCount(p.button_flash_count), +	mButtonFlashRate(p.button_flash_rate)  {  	static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);  	static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>()); @@ -292,6 +300,24 @@ void LLButton::onCommit()  	LLUICtrl::onCommit();  } +boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) +{ +	return setClickedCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb) +{ +	return setMouseDownCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb) +{ +	return setMouseUpCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) +{ +	return setHeldDownCallback(initCommitCallback(cb)); +} + +  boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )  {  	if (!mCommitSignal) mCommitSignal = new commit_signal_t(); @@ -314,7 +340,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)); @@ -511,15 +537,6 @@ BOOL	LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask)  	return TRUE;  } - -void LLButton::onMouseEnter(S32 x, S32 y, MASK mask) -{ -	LLUICtrl::onMouseEnter(x, y, mask); - -	if (isInEnabledChain()) -		mNeedsHighlight = TRUE; -} -  void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)  {  	LLUICtrl::onMouseLeave(x, y, mask); @@ -534,6 +551,10 @@ void LLButton::setHighlight(bool b)  BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)  { +	if (isInEnabledChain()  +		&& (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) +		mNeedsHighlight = TRUE; +  	if (!childrenHandleHover(x, y, mask))  	{  		if (mMouseDownTimer.getStarted()) @@ -554,21 +575,29 @@ 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()  {  	F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();  	bool flash = FALSE; -	static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0); -	static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);  	if( mFlashing )  	{  		F32 elapsed = mFlashingTimer.getElapsedTimeF32(); -		S32 flash_count = S32(elapsed * button_flash_rate * 2.f); +		S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f);  		// flash on or off? -		flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f); +		flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f);  	}  	bool pressed_by_keyboard = FALSE; @@ -597,7 +626,7 @@ void LLButton::draw()  	LLColor4 glow_color = LLColor4::white;  	LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;  	LLUIImage* imagep = NULL; -	if (pressed) +	if (pressed && mDisplayPressedState)  	{  		imagep = selected ? mImagePressedSelected : mImagePressed;  	} @@ -707,16 +736,7 @@ void LLButton::draw()  	}  	// Unselected label assignments -	LLWString label; - -	if( getToggleState() ) -	{ -		label = mSelectedLabel; -	} -	else -	{ -		label = mUnselectedLabel; -	} +	LLWString label = getCurrentLabel();  	// overlay with keyboard focus border  	if (hasFocus()) @@ -781,18 +801,16 @@ 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();  		//FUGLY HACK FOR "DEPRESSED" BUTTONS -		if (pressed) +		if (pressed && mDisplayPressedState)  		{  			center_y--;  			center_x++; @@ -803,7 +821,11 @@ void LLButton::draw()  		LLColor4 overlay_color = mImageOverlayColor.get();  		if (!enabled)  		{ -			overlay_color.mV[VALPHA] = 0.5f; +			overlay_color = mImageOverlayDisabledColor.get(); +		} +		else if (getToggleState()) +		{ +			overlay_color = mImageOverlaySelectedColor.get();  		}  		overlay_color.mV[VALPHA] *= alpha; @@ -811,6 +833,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 +851,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),  @@ -863,7 +887,7 @@ void LLButton::draw()  		S32 y_offset = 2 + (getRect().getHeight() - 20)/2; -		if (pressed) +		if (pressed && mDisplayPressedState)  		{  			y_offset--;  			x++; @@ -919,7 +943,7 @@ void LLButton::setToggleState(BOOL b)  void LLButton::setFlashing( BOOL b )	  {  -	if (b != mFlashing) +	if ((bool)b != mFlashing)  	{  		mFlashing = b;   		mFlashingTimer.reset(); @@ -959,6 +983,23 @@ void LLButton::setLabelSelected( const LLStringExplicit& label )  	mSelectedLabel = label;  } +bool LLButton::labelIsTruncated() const +{ +	return getCurrentLabel().getString().size() > mLastDrawCharsCount; +} + +const LLUIString& LLButton::getCurrentLabel() const +{ +	if( getToggleState() ) +	{ +		return mSelectedLabel; +	} +	else +	{ +		return mUnselectedLabel; +	} +} +  void LLButton::setImageUnselected(LLPointer<LLUIImage> image)  {  	mImageUnselected = image; @@ -970,16 +1011,7 @@ void LLButton::setImageUnselected(LLPointer<LLUIImage> image)  void LLButton::autoResize()  { -	LLUIString label; -	if(getToggleState()) -	{ -		label = mSelectedLabel; -	} -	else -	{ -		label = mUnselectedLabel; -	} -	resize(label); +	resize(getCurrentLabel());  }  void LLButton::resize(LLUIString label) @@ -989,11 +1021,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() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (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());  		}  	}   } @@ -1140,7 +1193,7 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)  	// Set the button control value (toggle state) to the floater visibility control (Sets the value as well)  	button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));  	// Set the clicked callback to toggle the floater -	button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname)); +	button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD()));  }  // static diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 5968916006..deaa0823c6 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -91,10 +91,11 @@ public:  								label_color_selected,  								label_color_disabled,  								label_color_disabled_selected, -								highlight_color,  								image_color,  								image_color_disabled,  								image_overlay_color, +								image_overlay_selected_color, +								image_overlay_disabled_color,  								flash_color;  		// layout @@ -120,7 +121,8 @@ public:  		// misc  		Optional<bool>			is_toggle,  								scale_image, -								commit_on_return; +								commit_on_return, +								display_pressed_state;  		Optional<F32>				hover_glow_amount;  		Optional<TimeIntervalParam>	held_down_delay; @@ -131,6 +133,9 @@ public:  		Optional<bool>				handle_right_mouse; +		Optional<S32>				button_flash_count; +		Optional<F32>				button_flash_rate; +  		Params();  	}; @@ -157,7 +162,6 @@ public:  	virtual void	draw();  	/*virtual*/ BOOL postBuild(); -	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);  	virtual void	onMouseLeave(S32 x, S32 y, MASK mask);  	virtual void	onMouseCaptureLost(); @@ -168,6 +172,11 @@ public:  	void			setUseEllipses( BOOL use_ellipses )					{ mUseEllipses = use_ellipses; } +	boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); +	boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); +	boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); +	boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb); +  	boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button  	boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );  	boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON @@ -235,6 +244,8 @@ public:  	S32				getLastDrawCharsCount() const { return mLastDrawCharsCount; } +	bool			labelIsTruncated() const; +	const LLUIString&	getCurrentLabel() const;  	void			setScaleImage(BOOL scale)			{ mScaleImage = scale; }  	BOOL			getScaleImage() const				{ return mScaleImage; } @@ -270,14 +281,16 @@ public:  protected:  	LLPointer<LLUIImage> getImageUnselected() const	{ return mImageUnselected; }  	LLPointer<LLUIImage> getImageSelected() const	{ return mImageSelected; } +	void getOverlayImageSize(S32& overlay_width, S32& overlay_height);  	LLFrameTimer	mMouseDownTimer; +	bool			mNeedsHighlight; +	S32				mButtonFlashCount; +	F32				mButtonFlashRate; -private:  	void			drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size);  	void			resetMouseDownTimer(); -private:  	commit_signal_t* 			mMouseDownSignal;  	commit_signal_t* 			mMouseUpSignal;  	commit_signal_t* 			mHeldDownSignal; @@ -293,6 +306,8 @@ private:  	LLPointer<LLUIImage>		mImageOverlay;  	LLFontGL::HAlign			mImageOverlayAlignment;  	LLUIColor					mImageOverlayColor; +	LLUIColor					mImageOverlaySelectedColor; +	LLUIColor					mImageOverlayDisabledColor;  	LLPointer<LLUIImage>		mImageUnselected;  	LLUIString					mUnselectedLabel; @@ -321,21 +336,19 @@ private:  	   flash icon name is set in attributes(by default it isn't). First way is used otherwise. */  	LLPointer<LLUIImage>		mImageFlash; -	LLUIColor					mHighlightColor;  	LLUIColor					mFlashBgColor;  	LLUIColor					mImageColor;  	LLUIColor					mDisabledImageColor; -	BOOL						mIsToggle; -	BOOL						mScaleImage; - -	BOOL						mDropShadowedText; -	BOOL						mAutoResize; -	BOOL						mUseEllipses; -	BOOL						mBorderEnabled; +	bool						mIsToggle; +	bool						mScaleImage; -	BOOL						mFlashing; +	bool						mDropShadowedText; +	bool						mAutoResize; +	bool						mUseEllipses; +	bool						mBorderEnabled; +	bool						mFlashing;  	LLFontGL::HAlign			mHAlign;  	S32							mLeftHPad; @@ -355,10 +368,10 @@ private:  	F32							mHoverGlowStrength;  	F32							mCurGlowStrength; -	BOOL						mNeedsHighlight; -	BOOL						mCommitOnReturn; -	BOOL						mFadeWhenDisabled; +	bool						mCommitOnReturn; +	bool						mFadeWhenDisabled;  	bool						mForcePressedState; +	bool						mDisplayPressedState;  	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..0e2f3f1961 --- /dev/null +++ b/indra/llui/llcommandmanager.cpp @@ -0,0 +1,172 @@ +/**  + * @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 = LLCommandId("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") +	, execute_stop_function("execute_stop_function") +	, execute_stop_parameters("execute_stop_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) +	: mIdentifier(p.name) +	, mAvailableInToybox(p.available_in_toybox) +	, mIcon(p.icon) +	, mLabelRef(p.label_ref) +	, mName(p.name) +	, mTooltipRef(p.tooltip_ref) +	, mExecuteFunction(p.execute_function) +	, mExecuteParameters(p.execute_parameters) +	, mExecuteStopFunction(p.execute_stop_function) +	, mExecuteStopParameters(p.execute_stop_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.uuid()); +	 +	if (found != mCommandIndices.end()) +	{ +		command_match = mCommands[found->second]; +	} + +	return command_match; +} + +void LLCommandManager::addCommand(LLCommand * command) +{ +	LLCommandId command_id = command->id(); +	mCommandIndices[command_id.uuid()] = mCommands.size(); +	mCommands.push_back(command); + +	lldebugs << "Successfully added command: " << command->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 << "Invalid commands 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..a7276a48aa --- /dev/null +++ b/indra/llui/llcommandmanager.h @@ -0,0 +1,202 @@ +/**  + * @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) +	{ +		mUUID = LLUUID::generateNewID(name); +	} + +	LLCommandId(const Params& p) +	{ +		mUUID = LLUUID::generateNewID(p.name); +	} + +	LLCommandId(const LLUUID& uuid) +	:	mUUID(uuid) +	{} +	 +	const LLUUID& uuid() const { return mUUID; } + +	bool operator!=(const LLCommandId& command) const +	{ +		return (mUUID != command.mUUID); +	} + +	bool operator==(const LLCommandId& command) const +	{ +		return (mUUID == command.mUUID); +	} + +	static const LLCommandId null; + +private: +	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>	execute_stop_function; +		Optional<LLSD>			execute_stop_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& name() const { return mName; } +	const std::string& tooltipRef() const { return mTooltipRef; } + +	const std::string& executeFunctionName() const { return mExecuteFunction; } +	const LLSD& executeParameters() const { return mExecuteParameters; } + +	const std::string& executeStopFunctionName() const { return mExecuteStopFunction; } +	const LLSD& executeStopParameters() const { return mExecuteStopParameters; } +	 +	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 mName; +	std::string mTooltipRef; + +	std::string mExecuteFunction; +	LLSD        mExecuteParameters; + +	std::string mExecuteStopFunction; +	LLSD        mExecuteStopParameters; +	 +	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); + +	static bool load(); + +protected: +	void addCommand(LLCommand * command); + +private: +	typedef std::map<LLUUID, U32>		CommandIndexMap; +	typedef std::vector<LLCommand *>	CommandVector; +	 +	CommandVector	mCommands; +	CommandIndexMap	mCommandIndices; +}; + + +#endif // LL_LLCOMMANDMANAGER_H diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index ca2dc644a4..0fcd937361 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -162,10 +162,15 @@ void LLDockableFloater::setVisible(BOOL visible)  void LLDockableFloater::setMinimized(BOOL minimize)  { -	if(minimize) +	if(minimize && isDocked())  	{ +		// minimizing a docked floater just hides it  		setVisible(FALSE);  	} +	else +	{ +		LLFloater::setMinimized(minimize); +	}  }  LLView * LLDockableFloater::getDockWidget() @@ -234,8 +239,21 @@ void LLDockableFloater::setDockControl(LLDockControl* dockControl)  	setDocked(isDocked());  } -const LLUIImagePtr& LLDockableFloater::getDockTongue() +const LLUIImagePtr& LLDockableFloater::getDockTongue(LLDockControl::DocAt dock_side)  { +	switch(dock_side) +	{ +	case LLDockControl::LEFT: +		mDockTongue = LLUI::getUIImage("windows/Flyout_Left.png"); +		break; +	case LLDockControl::RIGHT: +		mDockTongue = LLUI::getUIImage("windows/Flyout_Right.png"); +		break; +	default: +		mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); +		break; +	} +  	return mDockTongue;  } diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 8deb6c1159..89c9852f4a 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -113,6 +113,8 @@ public:  	bool getUniqueDocking() { return mUniqueDocking;	}  	bool getUseTongue() { return mUseTongue; } + +	void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;}  private:  	/**  	 * Provides unique of dockable floater. @@ -122,7 +124,7 @@ private:  protected:  	void setDockControl(LLDockControl* dockControl); -	const LLUIImagePtr& getDockTongue(); +	const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP);  	// Checks if docking should be forced.  	// It may be useful e.g. if floater created in mouselook mode (see EXT-5609) diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index b1c27126d9..af39e41fa6 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -92,19 +92,24 @@ void LLDockControl::setDock(LLView* dockWidget)  void LLDockControl::getAllowedRect(LLRect& rect)  { -	rect = mDockableFloater->getRootView()->getRect(); +	rect = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getRect();  }  void LLDockControl::repositionDockable()  { +	if (!mDockWidget) return;  	LLRect dockRect = mDockWidget->calcScreenRect();  	LLRect rootRect; +	LLRect floater_rect = mDockableFloater->calcScreenRect();  	mGetAllowedRectCallback(rootRect); -	// recalculate dockable position if dock position changed, dock visibility changed, -	// root view rect changed or recalculation is forced -	if (mPrevDockRect != dockRect  || mDockWidgetVisible != isDockVisible() -			|| mRootRect != rootRect || mRecalculateDocablePosition) +	// recalculate dockable position if: +	if (mPrevDockRect != dockRect					//dock position   changed +		|| mDockWidgetVisible != isDockVisible()	//dock visibility changed +		|| mRootRect != rootRect					//root view rect  changed +		|| mFloaterRect != floater_rect				//floater rect    changed +		|| mRecalculateDockablePosition				//recalculation is forced +	)  	{  		// undock dockable and off() if dock not visible  		if (!isDockVisible()) @@ -135,7 +140,8 @@ void LLDockControl::repositionDockable()  		mPrevDockRect = dockRect;  		mRootRect = rootRect; -		mRecalculateDocablePosition = false; +		mFloaterRect = floater_rect; +		mRecalculateDockablePosition = false;  		mDockWidgetVisible = isDockVisible();  	}  } @@ -160,7 +166,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(); @@ -202,21 +208,33 @@ void LLDockControl::moveDockable()  	switch (mDockAt)  	{  	case LEFT: -		x = dockRect.mLeft; -		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight(); -		// check is dockable inside root view rect -		if (x < rootRect.mLeft) + +		x = dockRect.mLeft - dockableRect.getWidth(); +		y = dockRect.getCenterY() + dockableRect.getHeight() / 2; +		 +		if (use_tongue)  		{ -			x = rootRect.mLeft; +			x -= mDockTongue->getWidth();  		} -		if (x + dockableRect.getWidth() > rootRect.mRight) + +		mDockTongueX = dockableRect.mRight; +		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; +		 +		break; + +	case RIGHT: + +		x = dockRect.mRight; +		y = dockRect.getCenterY() + dockableRect.getHeight() / 2; + +		if (use_tongue)  		{ -			x = rootRect.mRight - dockableRect.getWidth(); +			x += mDockTongue->getWidth();  		} -		 -		mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2; -		 -		mDockTongueY = dockRect.mTop; + +		mDockTongueX = dockRect.mRight; +		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; +  		break;  	case TOP: @@ -314,13 +332,12 @@ void LLDockControl::moveDockable()  		dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),  				dockableRect.getHeight());  	} +  	LLRect localDocableParentRect; -	mDockableFloater->getParent()->screenRectToLocal(dockableRect, -			&localDocableParentRect); -	mDockableFloater->setRect(localDocableParentRect); -	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, -			&mDockTongueX, &mDockTongueY); +	mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect); +	mDockableFloater->setRect(localDocableParentRect); +	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY);  } @@ -329,7 +346,7 @@ void LLDockControl::on()  	 if (isDockVisible())  	{  		mEnabled = true; -		mRecalculateDocablePosition = true; +		mRecalculateDockablePosition = true;  	}  } @@ -340,7 +357,7 @@ void LLDockControl::off()  void LLDockControl::forceRecalculatePosition()  { -	mRecalculateDocablePosition = true; +	mRecalculateDockablePosition = true;  }  void LLDockControl::drawToungue() diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 2e7359245f..c9602011f6 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -43,6 +43,7 @@ public:  	{  		TOP,  		LEFT, +		RIGHT,  		BOTTOM  	}; @@ -79,12 +80,13 @@ private:  private:  	get_allowed_rect_callback_t mGetAllowedRectCallback;  	bool mEnabled; -	bool mRecalculateDocablePosition; +	bool mRecalculateDockablePosition;  	bool mDockWidgetVisible;  	DocAt mDockAt;  	LLView* mDockWidget;  	LLRect mPrevDockRect;  	LLRect mRootRect; +	LLRect mFloaterRect;  	LLFloater* mDockableFloater;  	LLUIImagePtr mDockTongue;  	S32 mDockTongueX; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index bc494e97f5..432397d3e9 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -62,6 +62,17 @@  // use this to control "jumping" behavior when Ctrl-Tabbing  const S32 TABBED_FLOATER_OFFSET = 0; +namespace LLInitParam +{ +	void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() +	{ +		declare("none",       LLFloaterEnums::OPEN_POSITIONING_NONE); +		declare("cascading",  LLFloaterEnums::OPEN_POSITIONING_CASCADING); +		declare("centered",   LLFloaterEnums::OPEN_POSITIONING_CENTERED); +		declare("specified",  LLFloaterEnums::OPEN_POSITIONING_SPECIFIED); +	} +} +  std::string	LLFloater::sButtonNames[BUTTON_COUNT] =   {  	"llfloater_close_btn",		//BUTTON_CLOSE @@ -154,7 +165,7 @@ LLFloater::Params::Params()  :	title("title"),  	short_title("short_title"),  	single_instance("single_instance", false), -	auto_tile("auto_tile", false), +	reuse_instance("reuse_instance", false),  	can_resize("can_resize", false),  	can_minimize("can_minimize", true),  	can_close("can_close", true), @@ -164,7 +175,10 @@ LLFloater::Params::Params()  	save_rect("save_rect", false),  	save_visibility("save_visibility", false),  	can_dock("can_dock", false), -	open_centered("open_centered", false), +	show_title("show_title", true), +	open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE), +	specified_left("specified_left"), +	specified_bottom("specified_bottom"),  	header_height("header_height", 0),  	legacy_header_height("legacy_header_height", 0),  	close_image("close_image"), @@ -226,13 +240,16 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)  	mTitle(p.title),  	mShortTitle(p.short_title),  	mSingleInstance(p.single_instance), +	mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default  	mKey(key), -	mAutoTile(p.auto_tile),  	mCanTearOff(p.can_tear_off),  	mCanMinimize(p.can_minimize),  	mCanClose(p.can_close),  	mDragOnLeft(p.can_drag_on_left),  	mResizable(p.can_resize), +	mOpenPositioning(p.open_positioning), +	mSpecifiedLeft(p.specified_left), +	mSpecifiedBottom(p.specified_bottom),  	mMinWidth(p.min_width),  	mMinHeight(p.min_height),  	mHeaderHeight(p.header_height), @@ -459,15 +476,24 @@ void LLFloater::layoutResizeCtrls()  	mResizeHandle[3]->setRect(rect);  } -void LLFloater::enableResizeCtrls(bool enable) +void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)  { +	mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width); +	mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width); + +	mResizeBar[LLResizeBar::TOP]->setVisible(enable && height); +	mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height); +	 +	mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width); +	mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width); +	 +	mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height); +	mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height); +  	for (S32 i = 0; i < 4; ++i)  	{ -		mResizeBar[i]->setVisible(enable); -		mResizeBar[i]->setEnabled(enable); - -		mResizeHandle[i]->setVisible(enable); -		mResizeHandle[i]->setEnabled(enable); +		mResizeHandle[i]->setVisible(enable && width && height); +		mResizeHandle[i]->setEnabled(enable && width && height);  	}  } @@ -515,7 +541,6 @@ LLFloater::~LLFloater()  		delete mResizeHandle[i];  	} -	storeRectControl();  	setVisible(false); // We're not visible if we're destroyed  	storeVisibilityControl();  	storeDockStateControl(); @@ -660,6 +685,12 @@ void LLFloater::openFloater(const LLSD& key)  	}  	else  	{ +		LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName); +		if (!floater_to_stack) +		{ +			floater_to_stack = LLFloaterReg::getLastFloaterCascading(); +		} +		applyControlsAndPosition(floater_to_stack);  		setMinimized(FALSE);  		setVisibleAndFrontmost(mAutoFocus);  	} @@ -752,12 +783,19 @@ void LLFloater::closeFloater(bool app_quitting)  			else  			{  				setVisible(FALSE); +				if (!mReuseInstance) +				{ +					destroy(); +				}  			}  		}  		else  		{  			setVisible(FALSE); // hide before destroying (so handleVisibilityChange() gets called) -			destroy(); +			if (!mReuseInstance) +			{ +				destroy(); +			}  		}  	}  } @@ -822,43 +860,108 @@ LLMultiFloater* LLFloater::getHost()  	return (LLMultiFloater*)mHostHandle.get();   } -void    LLFloater::applySavedVariables() +void LLFloater::applyControlsAndPosition(LLFloater* other)  { -	applyRectControl(); -	applyDockState(); +	if (!applyDockState()) +	{ +		if (!applyRectControl()) +		{ +			applyPositioning(other); +		} +	}  } -void LLFloater::applyRectControl() +bool LLFloater::applyRectControl()  { -	// first, center on screen if requested	 -	if (mOpenCentered) +	bool saved_rect = false; + +	LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName); +	if (last_in_group && last_in_group != this)  	{ -		center(); +		// other floaters in our group, position ourselves relative to them and don't save the rect +		mRectControl.clear(); +		mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP;  	} - -	// override center if we have saved rect control -	if (mRectControl.size() > 1) +	else if (mRectControl.size() > 1)  	{ +		// If we have a saved rect, use it  		const LLRect& rect = getControlGroup()->getRect(mRectControl); -		if (rect.getWidth() > 0 && rect.getHeight() > 0) +		saved_rect = rect.notEmpty(); +		if (saved_rect)  		{ -			translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); +			setOrigin(rect.mLeft, rect.mBottom); +  			if (mResizable)  			{  				reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));  			}  		}  	} + +	return saved_rect;  } -void LLFloater::applyDockState() +bool LLFloater::applyDockState()  { +	bool docked = false; +  	if (mDocStateControl.size() > 1)  	{ -		bool dockState = getControlGroup()->getBOOL(mDocStateControl); -		setDocked(dockState); +		docked = getControlGroup()->getBOOL(mDocStateControl); +		setDocked(docked);  	} +	return docked; +} + +void LLFloater::applyPositioning(LLFloater* other) +{ +	// Otherwise position according to the positioning code +	switch (mOpenPositioning) +	{ +	case LLFloaterEnums::OPEN_POSITIONING_CENTERED: +		center(); +		break; + +	case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED: +		{ +			// Translate relative to snap rect +			setOrigin(mSpecifiedLeft, mSpecifiedBottom); +			const LLRect& snap_rect = gFloaterView->getSnapRect(); +			translate(snap_rect.mLeft, snap_rect.mBottom); +			translateIntoRect(snap_rect, FALSE); +		} +		break; + +	case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP: +	case LLFloaterEnums::OPEN_POSITIONING_CASCADING: +		if (other != NULL && other != this) +		{ +			stackWith(*other); +		} +		else +		{ +			static const U32 CASCADING_FLOATER_HOFFSET = 0; +			static const U32 CASCADING_FLOATER_VOFFSET = 0; +			 +			const LLRect& snap_rect = gFloaterView->getSnapRect(); + +			const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET; +			const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET; + +			S32 rect_height = getRect().getHeight(); +			setOrigin(horizontal_offset, vertical_offset - rect_height); + +			translate(snap_rect.mLeft, snap_rect.mBottom); +			translateIntoRect(snap_rect, FALSE); +		} +		break; + +	case LLFloaterEnums::OPEN_POSITIONING_NONE: +	default: +		// Do nothing +		break; +	}  }  void LLFloater::applyTitle() @@ -967,9 +1070,10 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)  	const LLRect old_rect = getRect();  	LLView::handleReshape(new_rect, by_user); -	if (by_user) +	if (by_user && !isMinimized())  	{  		storeRectControl(); +		mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;  	}  	// if not minimized, adjust all snapped dependents to new shape @@ -1029,7 +1133,7 @@ void LLFloater::setMinimized(BOOL minimize)  	if (minimize == mMinimized) return; -	if(mMinimizeSignal) +	if (mMinimizeSignal)  	{  		(*mMinimizeSignal)(this, LLSD(minimize));  	} @@ -1061,10 +1165,6 @@ void LLFloater::setMinimized(BOOL minimize)  			mButtonsEnabled[BUTTON_RESTORE] = TRUE;  		} -		if (mDragHandle) -		{ -			mDragHandle->setVisible(TRUE); -		}  		setBorderVisible(TRUE);  		for(handle_set_iter_t dependent_it = mDependents.begin(); @@ -1215,19 +1315,9 @@ void LLFloater::setIsChrome(BOOL is_chrome)  		mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome)));  	} -	// no titles displayed on "chrome" floaters -	if (mDragHandle) -		mDragHandle->setTitleVisible(!is_chrome); -	  	LLPanel::setIsChrome(is_chrome);  } -void LLFloater::setTitleVisible(bool visible) -{ -	if (mDragHandle) -		mDragHandle->setTitleVisible(visible); -} -  // Change the draw style to account for the foreground state.  void LLFloater::setForeground(BOOL front)  { @@ -1315,7 +1405,10 @@ void LLFloater::moveResizeHandlesToFront()  BOOL LLFloater::isFrontmost()  { -	return gFloaterView && gFloaterView->getFrontmost() == this && getVisible(); +	LLFloaterView* floater_view = getParentByType<LLFloaterView>(); +	return getVisible() +			&& (floater_view  +				&& floater_view->getFrontmost() == this);  }  void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition) @@ -1388,6 +1481,7 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)  		if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return TRUE;  		if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return TRUE;  		if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE; +		if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE;  		// Otherwise pass to drag handle for movement  		return mDragHandle->handleMouseDown(x, y, mask); @@ -1493,6 +1587,13 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)  	{  		mDocked = docked;  		mButtonsEnabled[BUTTON_DOCK] = !mDocked; + +		if (mDocked) +		{ +			setMinimized(FALSE); +			mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; +		} +  		updateTitleButtons();  		storeDockStateControl(); @@ -1731,7 +1832,7 @@ void LLFloater::draw()  		{  			drawChild(mButtons[i]);  		} -		drawChild(mDragHandle); +		drawChild(mDragHandle, 0, 0, TRUE);  	}  	else  	{ @@ -2451,6 +2552,52 @@ void LLFloaterView::closeAllChildren(bool app_quitting)  	}  } +void LLFloaterView::hiddenFloaterClosed(LLFloater* floater) +{ +	for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); +		it != end_it; +		++it) +	{ +		if (it->first.get() == floater) +		{ +			it->second.disconnect(); +			mHiddenFloaters.erase(it); +			break; +		} +	} +} + +void LLFloaterView::hideAllFloaters() +{ +	child_list_t child_list = *(getChildList()); + +	for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it) +	{ +		LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); +		if (floaterp && floaterp->getVisible()) +		{ +			floaterp->setVisible(false); +			boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp)); +			mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection)); +		} +	} +} + +void LLFloaterView::showHiddenFloaters() +{ +	for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); +		it != end_it; +		++it) +	{ +		LLFloater* floaterp = it->first.get(); +		if (floaterp) +		{ +			floaterp->setVisible(true); +		} +		it->second.disconnect(); +	} +	mHiddenFloaters.clear(); +}  BOOL LLFloaterView::allChildrenClosed()  { @@ -2549,7 +2696,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out  	}  	// move window fully onscreen -	if (floater->translateIntoRect( getLocalRect(), allow_partial_outside )) +	if (floater->translateIntoRect( getSnapRect(), allow_partial_outside ))  	{  		floater->clearSnapTarget();  	} @@ -2775,7 +2922,6 @@ void LLFloater::setInstanceName(const std::string& name)  		{  			mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);  		} -  	}  } @@ -2837,8 +2983,11 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	mHeaderHeight = p.header_height;  	mLegacyHeaderHeight = p.legacy_header_height;  	mSingleInstance = p.single_instance; -	mAutoTile = p.auto_tile; -	mOpenCentered = p.open_centered; +	mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; + +	mOpenPositioning = p.open_positioning; +	mSpecifiedLeft = p.specified_left; +	mSpecifiedBottom = p.specified_bottom;  	if (p.save_rect && mRectControl.empty())  	{ @@ -2848,7 +2997,6 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	{  		mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set  	} -  	if(p.save_dock_state)  	{  		mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set @@ -2857,13 +3005,18 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	// open callback   	if (p.open_callback.isProvided())  	{ -		mOpenSignal.connect(initCommitCallback(p.open_callback)); +		setOpenCallback(initCommitCallback(p.open_callback));  	}  	// close callback   	if (p.close_callback.isProvided())  	{  		setCloseCallback(initCommitCallback(p.close_callback));  	} + +	if (mDragHandle) +	{ +		mDragHandle->setTitleVisible(p.show_title); +	}  }  boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )  @@ -2872,6 +3025,11 @@ boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_  	return mMinimizeSignal->connect(cb);   } +boost::signals2::connection LLFloater::setOpenCallback( const commit_signal_t::slot_type& cb ) +{ +	return mOpenSignal.connect(cb); +} +  boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )  {  	return mCloseSignal.connect(cb); @@ -2916,7 +3074,9 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str  			return FALSE;  		} -		parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); +		Params referenced_params; +		parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName()); +		params.fillFrom(referenced_params);  		// add children using dimensions from referenced xml for consistent layout  		setShape(params.rect); @@ -3105,7 +3265,6 @@ void LLFloater::stackWith(LLFloater& other)  	next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); -	mRectControl.clear(); // don't save rect of stacked floaters  	setShape(next_rect);  } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 58c2d34253..73e9c9e831 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -35,6 +35,7 @@  #include "lluuid.h"  //#include "llnotificationsutil.h"  #include <set> +#include <boost/signals2.hpp>  class LLDragHandle;  class LLResizeHandle; @@ -59,11 +60,35 @@ const BOOL CLOSE_NO = FALSE;  const BOOL ADJUST_VERTICAL_YES = TRUE;  const BOOL ADJUST_VERTICAL_NO = FALSE; +namespace LLFloaterEnums +{ +	enum EOpenPositioning +	{ +		OPEN_POSITIONING_NONE, +		OPEN_POSITIONING_CASCADING, +		OPEN_POSITIONING_CASCADE_GROUP, +		OPEN_POSITIONING_CENTERED, +		OPEN_POSITIONING_SPECIFIED, +		OPEN_POSITIONING_COUNT +	}; +} + +namespace LLInitParam +{ +	template<> +	struct TypeValues<LLFloaterEnums::EOpenPositioning> : public TypeValuesHelper<LLFloaterEnums::EOpenPositioning> +	{ +		static void declareValues(); +	}; +} + +  class LLFloater : public LLPanel  { -friend class LLFloaterView; -friend class LLFloaterReg; -friend class LLMultiFloater; +	friend class LLFloaterView; +	friend class LLFloaterReg; +	friend class LLMultiFloater; +  public:  	struct KeyCompare  	{ @@ -95,7 +120,7 @@ public:  								short_title;  		Optional<bool>			single_instance, -								auto_tile, +								reuse_instance,  								can_resize,  								can_minimize,  								can_close, @@ -105,7 +130,13 @@ public:  								save_visibility,  								save_dock_state,  								can_dock, -								open_centered; +								show_title; +		 +		Optional<LLFloaterEnums::EOpenPositioning>	open_positioning; +		Optional<S32>								specified_left; +		Optional<S32>								specified_bottom; + +		  		Optional<S32>			header_height,  								legacy_header_height; // HACK see initFromXML() @@ -144,6 +175,7 @@ public:  	bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);  	boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb ); +	boost::signals2::connection setOpenCallback( const commit_signal_t::slot_type& cb );  	boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb );  	void initFromParams(const LLFloater::Params& p); @@ -179,7 +211,6 @@ public:  	std::string		getTitle() const;  	void			setShortTitle( const std::string& short_title );  	std::string		getShortTitle() const; -	void			setTitleVisible(bool visible);  	virtual void	setMinimized(BOOL b);  	void			moveResizeHandlesToFront();  	void			addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE); @@ -265,8 +296,6 @@ public:  	virtual void    setTornOff(bool torn_off) { mTornOff = torn_off; } -	void			stackWith(LLFloater& other); -  	// Return a closeable floater, if any, given the current focus.  	static LLFloater* getClosableFloaterFromFocus();  @@ -290,11 +319,17 @@ public:  	void			updateTransparency(ETypeTransparency transparency_type); +	void			enableResizeCtrls(bool enable, bool width = true, bool height = true); + +	bool			isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mOpenPositioning); }  protected: -	virtual void    applySavedVariables(); +	void			applyControlsAndPosition(LLFloater* other); + +	void			stackWith(LLFloater& other); -	void			applyRectControl(); -	void			applyDockState(); +	virtual bool	applyRectControl(); +	bool			applyDockState(); +	void			applyPositioning(LLFloater* other);  	void			storeRectControl();  	void			storeVisibilityControl();  	void			storeDockStateControl(); @@ -339,7 +374,6 @@ private:  	BOOL			offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index);  	void			addResizeCtrls();  	void			layoutResizeCtrls(); -	void			enableResizeCtrls(bool enable);  	void 			addDragHandle();  	void			layoutDragHandle();		// repair layout @@ -376,15 +410,18 @@ private:  	LLUIString		mShortTitle;  	BOOL			mSingleInstance;	// TRUE if there is only ever one instance of the floater +	bool			mReuseInstance;		// true if we want to hide the floater when we close it instead of destroying it  	std::string		mInstanceName;		// Store the instance name so we can remove ourselves from the list -	BOOL			mAutoTile;			// TRUE if placement of new instances tiles  	BOOL			mCanTearOff;  	BOOL			mCanMinimize;  	BOOL			mCanClose;  	BOOL			mDragOnLeft;  	BOOL			mResizable; -	bool			mOpenCentered; + +	LLFloaterEnums::EOpenPositioning	mOpenPositioning; +	S32									mSpecifiedLeft; +	S32									mSpecifiedBottom;  	S32				mMinWidth;  	S32				mMinHeight; @@ -427,8 +464,6 @@ private:  	typedef std::map<LLHandle<LLFloater>, LLFloater*>::iterator handle_map_iter_t;  	static handle_map_t	sFloaterMap; -	std::vector<LLHandle<LLView> > mMinimizedHiddenChildren; -  	BOOL			mHasBeenDraggedWhileMinimized;  	S32				mPreviousMinimizedBottom;  	S32				mPreviousMinimizedLeft; @@ -482,6 +517,10 @@ public:  	BOOL			allChildrenClosed();  	void			shiftFloaters(S32 x_offset, S32 y_offset); +	void			hideAllFloaters(); +	void			showHiddenFloaters(); + +  	LLFloater* getFrontmost() const;  	LLFloater* getBackmost() const;  	LLFloater* getParentFloater(LLView* viewp) const; @@ -496,11 +535,15 @@ public:  	void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; }  private: +	void hiddenFloaterClosed(LLFloater* floater); +  	LLHandle<LLView>	mSnapView;  	BOOL			mFocusCycleMode;  	S32				mSnapOffsetBottom;  	S32				mSnapOffsetRight;  	S32				mMinimizePositionVOffset; +	typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t; +	hidden_floaters_t mHiddenFloaters;  };  // diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index fc7dcfcc4e..e144b68f5e 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -59,19 +59,57 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con  //static  LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)  { -	LLRect rect;  	const std::string& groupname = sGroupMap[name];  	if (!groupname.empty())  	{  		instance_list_t& list = sInstanceMap[groupname];  		if (!list.empty())  		{ -			return list.back(); +			for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter) +			{ +				LLFloater* inst = *iter; + +				if (inst->getVisible() && !inst->isMinimized()) +				{ +					return inst; +				} +			}  		}  	}  	return NULL;  } +LLFloater* LLFloaterReg::getLastFloaterCascading() +{ +	LLRect candidate_rect; +	candidate_rect.mTop = 100000; +	LLFloater* candidate_floater = NULL; + +	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); +	for( ; it != it_end; ++it) +	{ +		const std::string& group_name = it->second; + +		instance_list_t& instances = sInstanceMap[group_name]; + +		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) +		{ +			LLFloater* inst = *iter; + +			if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING)) +			{ +				if (candidate_rect.mTop > inst->getRect().mTop) +				{ +					candidate_floater = inst; +					candidate_rect = inst->getRect(); +				} +			} +		} +	} + +	return candidate_floater; +} +  //static  LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)  { @@ -107,37 +145,33 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)  			if (!groupname.empty())  			{  				instance_list_t& list = sInstanceMap[groupname]; -				int index = list.size();  				res = build_func(key); -				 +				if (!res) +				{ +					llwarns << "Failed to build floater type: '" << name << "'." << llendl; +					return NULL; +				}  				bool success = res->buildFromFile(xui_file, NULL);  				if (!success)  				{  					llwarns << "Failed to build floater type: '" << name << "'." << llendl;  					return NULL;  				} -					 +  				// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe  				if (res->mKey.isUndefined())   				{ -						res->mKey = key; +					res->mKey = key;  				}  				res->setInstanceName(name); -				res->applySavedVariables(); // Can't apply rect and dock state until setting instance name -				if (res->mAutoTile && !res->getHost() && index > 0) -				{ -					LLFloater* last_floater = getLastFloaterInGroup(groupname); -					if (last_floater) -					{ -						res->stackWith(*last_floater); -						gFloaterView->adjustToFitScreen(res, true); -					} -				} -				else -				{ -					gFloaterView->adjustToFitScreen(res, false); -				} + +				LLFloater *last_floater = (list.empty() ? NULL : list.back()); + +				res->applyControlsAndPosition(last_floater); + +				gFloaterView->adjustToFitScreen(res, false); +  				list.push_back(res);  			}  		} @@ -403,70 +437,71 @@ void LLFloaterReg::registerControlVariables()  	}  } -// Callbacks - -// static -// Call once (i.e use for init callbacks) -void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname) +//static +void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)  { -	// Get the visibility control name for the floater -	std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); -	// Set the control value to the floater visibility control (Sets the value as well) -	ctrl->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); -} +	// +	// 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. +	//  -// callback args may use "floatername.key" format -static void parse_name_key(std::string& name, LLSD& key) -{ -	std::string instname = name; -	std::size_t dotpos = instname.find("."); -	if (dotpos != std::string::npos) +	std::string name = sdname.asString(); +	LLFloater* instance = getInstance(name, key);  + +	if (!instance) +	{ +		lldebugs << "Unable to get instance of floater '" << name << "'" << llendl; +	} +	else if (instance->isMinimized()) +	{ +		instance->setMinimized(FALSE); +		instance->setVisibleAndFrontmost(); +	} +	else if (!instance->isShown()) +	{ +		instance->openFloater(key); +		instance->setVisibleAndFrontmost(); +	} +	else if (!instance->isFrontmost()) +	{ +		instance->setVisibleAndFrontmost(); +	} +	else  	{ -		name = instname.substr(0, dotpos); -		key = LLSD(instname.substr(dotpos+1, std::string::npos)); +		instance->closeFloater();  	}  } -//static -void LLFloaterReg::showFloaterInstance(const LLSD& sdname) -{ -	LLSD key; -	std::string name = sdname.asString(); -	parse_name_key(name, key); -	showInstance(name, key, TRUE); -} -//static -void LLFloaterReg::hideFloaterInstance(const LLSD& sdname) -{ -	LLSD key; -	std::string name = sdname.asString(); -	parse_name_key(name, key); -	hideInstance(name, key); -} -//static -void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname) +// static +U32 LLFloaterReg::getVisibleFloaterInstanceCount()  { -	LLSD key; -	std::string name = sdname.asString(); -	parse_name_key(name, key); -	toggleInstance(name, key); -} +	U32 count = 0; -//static -bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname) -{ -	LLSD key; -	std::string name = sdname.asString(); -	parse_name_key(name, key); -	return instanceVisible(name, key); -} +	std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); +	for( ; it != it_end; ++it) +	{ +		const std::string& group_name = it->second; -//static -bool LLFloaterReg::floaterInstanceMinimized(const LLSD& sdname) -{ -	LLSD key; -	std::string name = sdname.asString(); -	parse_name_key(name, key); -	LLFloater* instance = findInstance(name, key);  -	return LLFloater::isShown(instance); +		instance_list_t& instances = sInstanceMap[group_name]; + +		for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) +		{ +			LLFloater* inst = *iter; + +			if (inst->getVisible() && !inst->isMinimized()) +			{ +				count++; +			} +		} +	} + +	return count;  } diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index a2027a77a0..534cf8b40a 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -87,6 +87,7 @@ public:  	// Helpers  	static LLFloater* getLastFloaterInGroup(const std::string& name); +	static LLFloater* getLastFloaterCascading();  	// Find / get (create) / remove / destroy  	static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD()); @@ -123,12 +124,7 @@ public:  	static void registerControlVariables();  	// Callback wrappers -	static void initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname); -	static void showFloaterInstance(const LLSD& sdname); -	static void hideFloaterInstance(const LLSD& sdname); -	static void toggleFloaterInstance(const LLSD& sdname); -	static bool floaterInstanceVisible(const LLSD& sdname); -	static bool floaterInstanceMinimized(const LLSD& sdname); +	static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());  	// Typed find / get / show  	template <class T> @@ -151,6 +147,7 @@ public:  	static void blockShowFloaters(bool value) { sBlockShowFloaters = value;} +	static U32 getVisibleFloaterInstanceCount();  };  #endif diff --git a/indra/llui/llhelp.h b/indra/llui/llhelp.h index 83317bd03c..1726347a78 100644 --- a/indra/llui/llhelp.h +++ b/indra/llui/llhelp.h @@ -32,6 +32,7 @@ class LLHelp  {   public:  	virtual void showTopic(const std::string &topic) = 0; +	virtual std::string getURL(const std::string &topic) = 0;  	// return default (fallback) topic name suitable for showTopic()  	virtual std::string defaultTopic() = 0;  	// return topic to use before the user logs in diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index a250404292..0e7060e22c 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -47,6 +47,19 @@ void LLLayoutStack::OrientationNames::declareValues()  //  // LLLayoutPanel  // +LLLayoutPanel::Params::Params()	 +:	expanded_min_dim("expanded_min_dim", 0), +	min_dim("min_dim", 0), +	max_dim("max_dim", S32_MAX), +	user_resize("user_resize", true), +	auto_resize("auto_resize", true) +{ +	addSynonym(min_dim, "min_width"); +	addSynonym(min_dim, "min_height"); +	addSynonym(max_dim, "max_width"); +	addSynonym(max_dim, "max_height"); +} +  LLLayoutPanel::LLLayoutPanel(const Params& p)	  :	LLPanel(p),  	mExpandedMinDimSpecified(false), @@ -58,7 +71,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 +103,22 @@ LLLayoutPanel::~LLLayoutPanel()  	mResizeBar = NULL;  } -F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation) +void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	if (mOrientation == LLLayoutStack::HORIZONTAL) +	{ +		mFractionalSize += width - llround(mFractionalSize); +	} +	else +	{ +		mFractionalSize += height - llround(mFractionalSize); +	} +	LLPanel::reshape(width, height, called_from_parent); +} + +F32 LLLayoutPanel::getCollapseFactor()  { -	if (orientation == LLLayoutStack::HORIZONTAL) +	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 +177,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 +221,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 +324,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 +370,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) +        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().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 -		{ -			// 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 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); -			} -			else +			if (pixels_to_distribute < 0.f)  			{ -				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); +				// 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_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 +489,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 +511,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 @@ -599,8 +540,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	// not enough room to fit existing contents  	if (force_resize == FALSE  		// layout did not complete by reaching target position -		&& ((mOrientation == VERTICAL && cur_y != -mPanelSpacing) -			|| (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing))) +		&& ((mOrientation == VERTICAL && llround(cur_y) != -mPanelSpacing) +			|| (mOrientation == HORIZONTAL && llround(cur_x) != getRect().getWidth() + mPanelSpacing)))  	{  		// do another layout pass with all stacked elements contributing  		// even those that don't usually resize diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index d8ef0aeaca..ede6149a80 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; @@ -163,24 +161,15 @@ public:  		Optional<bool>			user_resize,  								auto_resize; -		Params() -		:	expanded_min_dim("expanded_min_dim", 0), -			min_dim("min_dim", 0), -			max_dim("max_dim", 0), -			user_resize("user_resize", true), -			auto_resize("auto_resize", true) -		{ -			addSynonym(min_dim, "min_width"); -			addSynonym(min_dim, "min_height"); -			addSynonym(max_dim, "max_width"); -			addSynonym(max_dim, "max_height"); -		} +		Params();  	};  	~LLLayoutPanel();  	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 +191,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..3ef8d8ff35 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 @@ -1731,7 +1731,7 @@ void LLMenuGL::setCanTearOff(BOOL tear_off)  	{  		LLMenuItemTearOffGL::Params p;  		mTearOffItem = LLUICtrlFactory::create<LLMenuItemTearOffGL>(p); -		addChildInBack(mTearOffItem); +		addChild(mTearOffItem);  	}  	else if (!tear_off && mTearOffItem != NULL)  	{ diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index ffe5908a9d..8f7025a9a6 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -46,6 +46,7 @@  #include <algorithm>  #include <boost/regex.hpp> +#include <boost/foreach.hpp>  const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; @@ -416,23 +417,17 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par  		mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound));  	} -	for(LLInitParam::ParamIterator<LLNotificationTemplate::UniquenessContext>::const_iterator it = p.unique.contexts.begin(), -			end_it = p.unique.contexts.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(const LLNotificationTemplate::UniquenessContext& context, p.unique.contexts)  	{ -		mUniqueContext.push_back(it->value); +		mUniqueContext.push_back(context.value);  	}  	lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl; -	for(LLInitParam::ParamIterator<LLNotificationTemplate::Tag>::const_iterator it = p.tags.begin(), -			end_it = p.tags.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags)  	{ -		lldebugs << "    tag \"" << std::string(it->value) << "\"" << llendl; -		mTags.push_back(it->value); +		lldebugs << "    tag \"" << std::string(tag.value) << "\"" << llendl; +		mTags.push_back(tag.value);  	}  	mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); @@ -1397,14 +1392,12 @@ void replaceFormText(LLNotificationForm::Params& form, const std::string& patter  	{  		form.ignore.text = replace;  	} -	for (LLInitParam::ParamIterator<LLNotificationForm::FormElement>::iterator it = form.form_elements.elements.begin(), -			end_it = form.form_elements.elements.end(); -		it != end_it; -		++it) + +	BOOST_FOREACH(LLNotificationForm::FormElement& element, form.form_elements.elements)  	{ -		if (it->button.isChosen() && it->button.text() == pattern) +		if (element.button.isChosen() && element.button.text() == pattern)  		{ -			it->button.text = replace; +			element.button.text = replace;  		}  	}  } @@ -1453,48 +1446,42 @@ bool LLNotifications::loadTemplates()  	mTemplates.clear(); -	for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings.begin(), end_it = params.strings.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(LLNotificationTemplate::GlobalString& string, params.strings)  	{ -		mGlobalStrings[it->name] = it->value; +		mGlobalStrings[string.name] = string.value;  	}  	std::map<std::string, LLNotificationForm::Params> form_templates; -	for(LLInitParam::ParamIterator<LLNotificationTemplate::Template>::const_iterator it = params.templates.begin(), end_it = params.templates.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(LLNotificationTemplate::Template& notification_template, params.templates)  	{ -		form_templates[it->name] = it->form; +		form_templates[notification_template.name] = notification_template.form;  	} -	for(LLInitParam::ParamIterator<LLNotificationTemplate::Params>::iterator it = params.notifications.begin(), end_it = params.notifications.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(LLNotificationTemplate::Params& notification, params.notifications)  	{ -		if (it->form_ref.form_template.isChosen()) +		if (notification.form_ref.form_template.isChosen())  		{  			// replace form contents from template -			it->form_ref.form = form_templates[it->form_ref.form_template.name]; -			if(it->form_ref.form_template.yes_text.isProvided()) +			notification.form_ref.form = form_templates[notification.form_ref.form_template.name]; +			if(notification.form_ref.form_template.yes_text.isProvided())  			{ -				replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text); +				replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text);  			} -			if(it->form_ref.form_template.no_text.isProvided()) +			if(notification.form_ref.form_template.no_text.isProvided())  			{ -				replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text); +				replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text);  			} -			if(it->form_ref.form_template.cancel_text.isProvided()) +			if(notification.form_ref.form_template.cancel_text.isProvided())  			{ -				replaceFormText(it->form_ref.form, "$canceltext", it->form_ref.form_template.cancel_text); +				replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text);  			} -			if(it->form_ref.form_template.ignore_text.isProvided()) +			if(notification.form_ref.form_template.ignore_text.isProvided())  			{ -				replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text); +				replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text);  			}  		} -		mTemplates[it->name] = LLNotificationTemplatePtr(new LLNotificationTemplate(*it)); +		mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification));  	}  	return true; @@ -1517,12 +1504,9 @@ bool LLNotifications::loadVisibilityRules()  	mVisibilityRules.clear(); -	for(LLInitParam::ParamIterator<LLNotificationVisibilityRule::Rule>::iterator it = params.rules.begin(),  -			end_it = params.rules.end(); -		it != end_it; -		++it) +	BOOST_FOREACH(LLNotificationVisibilityRule::Rule& rule, params.rules)  	{ -		mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(*it))); +		mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule)));  	}  	return true; 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.h b/indra/llui/llresizehandle.h index 531eb1db61..7541b9e6c0 100644 --- a/indra/llui/llresizehandle.h +++ b/indra/llui/llresizehandle.h @@ -55,7 +55,7 @@ public:  	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);  	void			setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } - +	  private:  	BOOL			pointInHandle( S32 x, S32 y ); 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..6fa90933a4 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -34,6 +34,7 @@  static 	LLInitParam::Parser::parser_read_func_map_t sReadFuncs;  static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;  static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; +static const LLSD NO_VALUE_MARKER;  //  // LLParamSDParser @@ -45,7 +46,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>); @@ -60,29 +61,34 @@ LLParamSDParser::LLParamSDParser()  }  // special case handling of U32 due to ambiguous LLSD::assign overload -bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) +bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack)  {  	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);  	if (!sdparser.mWriteRootSD) return false; -	LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); -	if (!sd_to_write) return false; +	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); +	LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); +	sd_to_write.assign((S32)*((const U32*)val_ptr)); -	sd_to_write->assign((S32)*((const U32*)val_ptr));  	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, parser_t::name_stack_t& name_stack)  {  	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);  	if (!sdparser.mWriteRootSD) return false; -	LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); -	if (!sd_to_write) return false; +	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); +	LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range);  	return true;  } +void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) +{ +	mCurReadSD = &sd; +	block.submitValue(name_stack, *this); +}  void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)  { @@ -90,51 +96,17 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool  	mNameStack.clear();  	setParseSilently(silent); -	readSDValues(sd, block); +	LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); +	//readSDValues(sd, block);  }  void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)  {  	mNameStack.clear();  	mWriteRootSD = &sd; -	block.serializeBlock(*this); -} -const LLSD NO_VALUE_MARKER; - -void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block) -{ -	if (sd.isMap()) -	{ -		for (LLSD::map_const_iterator it = sd.beginMap(); -			it != sd.endMap(); -			++it) -		{ -			mNameStack.push_back(make_pair(it->first, newParseGeneration())); -			readSDValues(it->second, block); -			mNameStack.pop_back(); -		} -	} -	else if (sd.isArray()) -	{ -		for (LLSD::array_const_iterator it = sd.beginArray(); -			it != sd.endArray(); -			++it) -		{ -			mNameStack.back().second = newParseGeneration(); -			readSDValues(*it, block); -		} -	} -	else if (sd.isUndefined()) -	{ -		mCurReadSD = &NO_VALUE_MARKER; -		block.submitValue(mNameStack, *this); -	} -	else -	{ -		mCurReadSD = &sd; -		block.submitValue(mNameStack, *this); -	} +	name_stack_t name_stack; +	block.serializeBlock(*this, name_stack);  }  /*virtual*/ std::string LLParamSDParser::getCurrentElementName() @@ -150,83 +122,8 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block  	return full_name;  } -LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack) -{ -	//TODO: implement nested LLSD writing -	LLSD* sd_to_write = mWriteRootSD; -	bool new_traversal = false; -	for (name_stack_t::const_iterator it = name_stack.begin(), prev_it = mNameStack.begin(); -		it != name_stack.end(); -		++it) -	{ -		bool new_array_entry = false; -		if (prev_it == mNameStack.end()) -		{ -			new_traversal = true; -		} -		else -		{ -			if (!new_traversal						// have not diverged yet from previous trace -				&& prev_it->first == it->first		// names match -				&& prev_it->second != it->second)	// versions differ -			{ -				// name stacks match, but version numbers differ in last place. -				// create a different entry at this point using an LLSD array -				new_array_entry = true; -			} -			if (prev_it->first != it->first			// names differ -				|| prev_it->second != it->second)	// versions differ -			{ -				// at this point we have diverged from our last trace -				// so any elements referenced here are new -				new_traversal = true; -			} -		} - -		LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; -		if (child_sd->isArray()) -		{ -			if (new_traversal) -			{ -				// write to new element at end -				sd_to_write = &(*child_sd)[child_sd->size()]; -			} -			else -			{ -				// write to last of existing elements, or first element if empty -				sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; -			} -		} -		else -		{ -			if (new_array_entry && !child_sd->isArray()) -			{ -				// copy child contents into first element of an array -				LLSD new_array = LLSD::emptyArray(); -				new_array.append(*child_sd); -				// assign array to slot that previously held the single value -				*child_sd = new_array; -				// return next element in that array -				sd_to_write = &((*child_sd)[1]); -			} -			else -			{ -				sd_to_write = child_sd; -			} -		} -		if (prev_it != mNameStack.end()) -		{ -			++prev_it; -		} -	} -	mNameStack = name_stack; -	 -	//llinfos << ll_pretty_print_sd(*mWriteRootSD) << llendl; -	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; @@ -312,3 +209,132 @@ bool LLParamSDParser::readSD(Parser& parser, void* val_ptr)  	*((LLSD*)val_ptr) = *self.mCurReadSD;      return true;  } + +// static +LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) +{ +	LLSD* sd_to_write = &input; +	 +	for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; +		it != name_stack_range.second; +		++it) +	{ +		bool new_traversal = it->second; + +		LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; + +		if (child_sd->isArray()) +		{ +			if (new_traversal) +			{ +				// write to new element at end +				sd_to_write = &(*child_sd)[child_sd->size()]; +			} +			else +			{ +				// write to last of existing elements, or first element if empty +				sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; +			} +		} +		else +		{ +			if (new_traversal  +				&& child_sd->isDefined()  +				&& !child_sd->isArray()) +			{ +				// copy child contents into first element of an array +				LLSD new_array = LLSD::emptyArray(); +				new_array.append(*child_sd); +				// assign array to slot that previously held the single value +				*child_sd = new_array; +				// return next element in that array +				sd_to_write = &((*child_sd)[1]); +			} +			else +			{ +				sd_to_write = child_sd; +			} +		} +		it->second = false; +	} +	 +	return *sd_to_write; +} + +//static +void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) +{ +	if (sd.isMap()) +	{ +		for (LLSD::map_const_iterator it = sd.beginMap(); +			it != sd.endMap(); +			++it) +		{ +			stack.push_back(make_pair(it->first, true)); +			readSDValues(cb, it->second, stack); +			stack.pop_back(); +		} +	} +	else if (sd.isArray()) +	{ +		for (LLSD::array_const_iterator it = sd.beginArray(); +			it != sd.endArray(); +			++it) +		{ +			stack.back().second = true; +			readSDValues(cb, *it, stack); +		} +	} +	else if (sd.isUndefined()) +	{ +		if (!cb.empty()) +		{ +			cb(NO_VALUE_MARKER, stack); +		} +	} +	else +	{ +		if (!cb.empty()) +		{ +			cb(sd, stack); +		} +	} +} + +//static +void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) +{ +	LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); +	readSDValues(cb, sd, stack); +} +namespace LLInitParam +{ +	// LLSD specialization +	// block param interface +	bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) +	{ +		LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); + +		LLSD::String string; + +		if (p.readValue<LLSD::String>(string)) +		{ +			sd = string; +			return true; +		} +		return false; +	} + +	//static +	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) +	{ +		p.writeValue<LLSD::String>(sd.asString(), name_stack); +	} + +	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const +	{ +		// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) +		Parser::name_stack_t stack; +		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); +	} +} diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h index f776c781b3..c1cfa98399 100644 --- a/indra/llui/llsdparam.h +++ b/indra/llui/llsdparam.h @@ -29,6 +29,16 @@  #define LL_LLSDPARAM_H  #include "llinitparam.h" +#include "boost/function.hpp" + +struct LLParamSDParserUtilities +{ +	static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); + +	typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t; +	static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); +	static void readSDValues(read_sd_cb_t cb, const LLSD& sd); +};  class LLParamSDParser   :	public LLInitParam::Parser @@ -45,27 +55,25 @@ public:  	/*virtual*/ std::string getCurrentElementName();  private: -	void readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block); +	void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack);  	template<typename T> -	static bool writeTypedValue(Parser& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) +	static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack)  	{  		LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);  		if (!sdparser.mWriteRootSD) return false; -		LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); -		if (!sd_to_write) return false; +		LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); +		LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); -		sd_to_write->assign(*((const T*)val_ptr)); +		sd_to_write.assign(*((const T*)val_ptr));  		return true;  	} -	LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack); +	static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); +	static bool writeFlag(Parser& parser, const void* value_ptr, 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 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); @@ -85,29 +93,29 @@ private:  template<typename T>  class LLSDParamAdapter : public T +{ +public: +	LLSDParamAdapter() {} +	LLSDParamAdapter(const LLSD& sd)  	{ -	public: -		LLSDParamAdapter() {} -		LLSDParamAdapter(const LLSD& sd) -		{ -			LLParamSDParser parser; -			parser.readSD(sd, *this); -		} - -		operator LLSD() const -		{ -			LLParamSDParser parser; -			LLSD sd; -			parser.writeSD(sd, *this); -			return sd; -		} +		LLParamSDParser parser; +		parser.readSD(sd, *this); +	} + +	operator LLSD() const +	{ +		LLParamSDParser parser; +		LLSD sd; +		parser.writeSD(sd, *this); +		return sd; +	} -		LLSDParamAdapter(const T& val) -		: T(val) -		{ -			T::operator=(val); -		} -	}; +	LLSDParamAdapter(const T& val) +	: T(val) +	{ +		T::operator=(val); +	} +};  #endif // LL_LLSDPARAM_H diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 9c6a76822c..ad1f3c504d 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -548,23 +548,23 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )  	}  	S32 tab_count = getTabCount(); -	if (tab_count > 0) +	if (tab_count > 0 && !getTabsHidden())  	{  		LLTabTuple* firsttuple = getTab(0);  		LLRect tab_rect;  		if (mIsVertical)  		{  			tab_rect = LLRect(firsttuple->mButton->getRect().mLeft, -							  has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, -							  firsttuple->mButton->getRect().mRight, -							  has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); +								has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, +								firsttuple->mButton->getRect().mRight, +								has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom );  		}  		else  		{  			tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, -							  firsttuple->mButton->getRect().mTop, -							  has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, -							  firsttuple->mButton->getRect().mBottom ); +								firsttuple->mButton->getRect().mTop, +								has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, +								firsttuple->mButton->getRect().mBottom );  		}  		if( tab_rect.pointInRect( x, y ) )  		{ @@ -681,7 +681,7 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)  {  	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);  	BOOL handled = LLPanel::handleToolTip( x, y, mask); -	if (!handled && getTabCount() > 0)  +	if (!handled && getTabCount() > 0 && !getTabsHidden())   	{  		LLTabTuple* firsttuple = getTab(0); @@ -812,7 +812,9 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,	EDrag  {  	BOOL has_scroll_arrows = (getMaxScrollPos() > 0); -	if( mDragAndDropDelayTimer.getStarted() && mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME ) +	if( !getTabsHidden() +		&& mDragAndDropDelayTimer.getStarted()  +		&& mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME )  	{  		if (has_scroll_arrows)  		{ 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..287e3e2b41 --- /dev/null +++ b/indra/llui/lltoolbar.cpp @@ -0,0 +1,1188 @@ +/**  + * @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" +#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 +{ +	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"), +	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(), +	mStartDragItemCallback(NULL), +	mHandleDragItemCallback(NULL), +	mHandleDropCallback(NULL), +	mButtonAddSignal(NULL), +	mButtonEnterSignal(NULL), +	mButtonLeaveSignal(NULL), +	mButtonRemoveSignal(NULL), +	mDragAndDropTarget(false) +{ +	mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; +	mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; +} + +LLToolBar::~LLToolBar() +{ +	delete mPopupMenuHandle.get(); +	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)); + +		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; +	center_panel_p.mouse_opaque = 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 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) +{ +	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(flash ? TRUE : FALSE); +		} +	} + +	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()); +		} +	} +} + +// 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 +	LLLayoutStack::ELayoutOrientation 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; + +	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 +	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(); + +	// 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, 0.f); + +	// Position the caret  +	LLIconCtrl* caret = getChild<LLIconCtrl>("caret"); +	caret->setVisible(FALSE); +	if (mDragAndDropTarget && !mButtonCommands.empty()) +	{ +		LLRect caret_rect = caret->getRect(); +		LLRect toolbar_rect = 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() +{ +	BOOST_FOREACH(LLToolBarButton* button, mButtons) +	{ +		if (mButtonRemoveSignal) +		{ +			(*mButtonRemoveSignal)(button); +		} +		 +		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.uuid(), button)); +		 +		if (mButtonAddSignal) +		{ +			(*mButtonAddSignal)(button); +		} +	} +	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.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); +			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->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 ? 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 = false; +	 +	// Convert drag position into insert position and rank  +	if (!isReadOnly() && handled && !drop) +	{ +		LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; +		LLAssetType::EType type = inv_item->getType(); +		if (type == LLAssetType::AT_WIDGET) +		{ +			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)) ? false : true); +			//llinfos << "Merov debug : DaD, rank = " << mDragRank << ", dragged uui = " << inv_item->getUUID() << llendl;  +			/* 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); +	S32 drag_threshold = LLUI::sSettingGroups["config"]->getS32("DragAndDropDistanceThreshold"); +	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; +} + diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h new file mode 100644 index 0000000000..f10f39adc3 --- /dev/null +++ b/indra/llui/lltoolbar.h @@ -0,0 +1,282 @@ +/**  + * @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; +class LLToolBarButton; + +typedef boost::function<void (S32 x, S32 y, LLToolBarButton* button)> 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::Params>	button_width; +		Optional<S32>						desired_height; + +		Params() +		:	button_width("button_width"), +			desired_height("desired_height", 20) +		{} + +	}; + +	LLToolBarButton(const Params& p); +	~LLToolBarButton(); + +	BOOL handleMouseDown(S32 x, S32 y, MASK mask); +	BOOL handleHover(S32 x, S32 y, MASK mask); +	void reshape(S32 width, S32 height, BOOL called_from_parent = true); +	void setEnabled(BOOL enabled); +	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; } + +	void onMouseEnter(S32 x, S32 y, MASK mask); +	void onMouseLeave(S32 x, S32 y, MASK mask); +	void onMouseCaptureLost(); + +	void onCommit(); + +	virtual const std::string getToolTip() const;		 + +private: +	void callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param ); + +	LLCommandId		mId; +	S32				mMouseDownX; +	S32				mMouseDownY; +	LLUI::RangeS32	mWidthRange; +	S32				mDesiredHeight; +	bool							mIsDragged; +	tool_startdrag_callback_t		mStartDragItemCallback; +	tool_handledrag_callback_t		mHandleDragItemCallback; + +	enable_signal_t*	mIsEnabledSignal; +	enable_signal_t*	mIsRunningSignal; +	enable_signal_t*	mIsStartingSignal; +	LLPointer<LLUIImage>	mOriginalImageSelected, +							mOriginalImageUnselected, +							mOriginalImagePressed, +							mOriginalImagePressedSelected; +	LLUIColor				mOriginalLabelColor, +							mOriginalLabelColorSelected, +							mOriginalImageOverlayColor, +							mOriginalImageOverlaySelectedColor; +}; + + +namespace LLToolBarEnums +{ +	enum ButtonType +	{ +		BTNTYPE_ICONS_WITH_TEXT = 0, +		BTNTYPE_ICONS_ONLY, + +		BTNTYPE_COUNT +	}; + +	enum SideType +	{ +		SIDE_BOTTOM, +		SIDE_LEFT, +		SIDE_RIGHT, +		SIDE_TOP, +	}; + +	LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType); +} + +// 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 +{ +	friend class LLToolBarButton; +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, +												min_girth; +		// 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);	 +	int  getRankFromPosition(const LLCommandId& id);	 +	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); +	 +	static const int RANK_NONE = -1; +	 +	bool addCommand(const LLCommandId& commandId, int rank = RANK_NONE); +	int  removeCommand(const LLCommandId& commandId);		// Returns the rank the removed command was at, RANK_NONE if not found +	bool hasCommand(const LLCommandId& commandId) const; +	bool enableCommand(const LLCommandId& commandId, bool enabled); +	bool stopCommandInProgress(const LLCommandId& commandId); +	bool flashCommand(const LLCommandId& commandId, bool flash); + +	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; } +	bool isReadOnly() const { return mReadOnly; } + +	LLToolBarButton* createButton(const LLCommandId& id); + +	typedef boost::signals2::signal<void (LLView* button)> button_signal_t; +	boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb); +	boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb); +	boost::signals2::connection setButtonLeaveCallback(const button_signal_t::slot_type& cb); +	boost::signals2::connection setButtonRemoveCallback(const button_signal_t::slot_type& cb); + +	void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; } + +	LLToolBarEnums::SideType getSideType() const { return mSideType; } +	bool hasButtons() const { return !mButtons.empty(); } +	bool isModified() const { return mModified; } + +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; +	int								mDragRank; +	S32								mDragx, +									mDragy, +									mDragGirth; + +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; + +	typedef std::list<LLToolBarButton*> toolbar_button_list; +	toolbar_button_list				mButtons; +	command_id_list_t				mButtonCommands; +	typedef std::map<LLUUID, LLToolBarButton*> command_id_map; +	command_id_map					mButtonMap; + +	LLToolBarEnums::ButtonType		mButtonType; +	LLLayoutStack*					mCenteringStack; +	LLLayoutStack*					mWrapStack; +	LLPanel*						mButtonPanel; +	LLToolBarEnums::SideType		mSideType; +	 +	bool							mWrap; +	bool							mNeedsLayout; +	bool							mModified; +	S32								mPadLeft, +									mPadRight, +									mPadTop, +									mPadBottom, +									mPadBetween, +									mMinGirth; + +	LLToolBarButton::Params			mButtonParams[LLToolBarEnums::BTNTYPE_COUNT]; + +	LLHandle<class LLContextMenu>	mPopupMenuHandle; + +	button_signal_t*				mButtonAddSignal; +	button_signal_t*				mButtonEnterSignal; +	button_signal_t*				mButtonLeaveSignal; +	button_signal_t*				mButtonRemoveSignal; + +	std::string						mButtonTooltipSuffix; +}; + + +#endif  // LL_LLTOOLBAR_H diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index bc6461a0c2..23cdd9ad9a 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -200,7 +200,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  		icon_params.image_selected(imagep);  		icon_params.scale_image(true); -		icon_params.flash_color(icon_params.highlight_color()); +		icon_params.flash_color.control = "ButtonUnselectedFgColor";  		mInfoButton  = LLUICtrlFactory::create<LLButton>(icon_params);  		if (p.click_callback.isProvided())  		{ diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 58ba9e05f5..79ad99a770 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" @@ -87,13 +89,14 @@ std::list<std::string> gUntranslated;  /*static*/ LLUI::remove_popup_t	LLUI::sRemovePopupFunc;  /*static*/ LLUI::clear_popups_t	LLUI::sClearPopupsFunc; -// register filtereditor here +// register filter editor here  static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");  static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");  static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("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 @@ -103,7 +106,7 @@ void make_ui_sound(const char* namep)  	std::string name = ll_safe_string(namep);  	if (!LLUI::sSettingGroups["config"]->controlExists(name))  	{ -		llwarns << "tried to make ui sound for unknown sound name: " << name << llendl;	 +		llwarns << "tried to make UI sound for unknown sound name: " << name << llendl;	  	}  	else  	{ @@ -114,12 +117,12 @@ void make_ui_sound(const char* namep)  			{  				if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))  				{ -					llinfos << "ui sound name: " << name << " triggered but silent (null uuid)" << llendl;	 +					llinfos << "UI sound name: " << name << " triggered but silent (null uuid)" << llendl;	  				}				  			}  			else  			{ -				llwarns << "ui sound named: " << name << " does not translate to a valid uuid" << llendl;	 +				llwarns << "UI sound named: " << name << " does not translate to a valid uuid" << llendl;	  			}  		} @@ -127,7 +130,7 @@ void make_ui_sound(const char* namep)  		{  			if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))  			{ -				llinfos << "ui sound name: " << name << llendl;	 +				llinfos << "UI sound name: " << name << llendl;	  			}  			LLUI::sAudioCallback(uuid);  		} @@ -471,7 +474,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex  		return;  	} -	// add in offset of current image to current ui translation +	// add in offset of current image to current UI translation  	const LLVector3 ui_scale = gGL.getUIScale();  	const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale); @@ -1613,16 +1616,16 @@ void LLUI::initClass(const settings_map_t& settings,  	LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); -	// Callbacks for associating controls with floater visibilty: -	reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _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)); +	// Callbacks for associating controls with floater visibility: +	reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD())); +	reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD())); +	reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE)); +	reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD()));  	// Button initialization callback for toggle buttons  	reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); -	// Button initialization callback for toggle buttons on dockale floaters +	// Button initialization callback for toggle buttons on dockable floaters  	reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));  	// Display the help topic for the current context @@ -1631,8 +1634,12 @@ void LLUI::initClass(const settings_map_t& settings,  	// Currently unused, but kept for reference:  	reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); -	// Used by menus along with Floater.Toggle to display visibility as a checkmark -	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2)); +	// Used by menus along with Floater.Toggle to display visibility as a check-mark +	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); +	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); + +	// Parse the master list of commands +	LLCommandManager::load();  }  void LLUI::cleanupClass() @@ -2026,12 +2033,12 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)  								CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);  	S32 local_x, local_y; -	// convert screen coordinates to tooltipview-local coordinates +	// convert screen coordinates to tooltip view-local coordinates  	parent->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y);  	// Start at spawn position (using left/top)  	view->setOrigin( local_x, local_y - view->getRect().getHeight()); -	// Make sure we're onscreen and not overlapping the mouse +	// Make sure we're on-screen and not overlapping the mouse  	view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE );  } @@ -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..2fa260ded1 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(); @@ -1045,3 +1055,9 @@ boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal  	if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();  	return mDoubleClickSignal->connect(cb);   } + +void LLUICtrl::addInfo(LLSD & info) +{ +	LLView::addInfo(info); +	info["value"] = getValue(); +} diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 09bed9b958..3e055a9d06 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 ); @@ -301,7 +304,9 @@ protected:  	static F32 sActiveControlTransparency;  	static F32 sInactiveControlTransparency; - +	 +	virtual void addInfo(LLSD & info); +	  private:  	BOOL			mIsChrome; diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index d345ad4cd0..71c38237c1 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -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..3fd7e48428 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -31,7 +31,10 @@  #include "llview.h"  #include <cassert> +#include <sstream>  #include <boost/tokenizer.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp>  #include "llrender.h"  #include "llevent.h" @@ -44,6 +47,7 @@  #include "v3color.h"  #include "lluictrlfactory.h"  #include "lltooltip.h" +#include "llsdutil.h"  // for ui edit hack  #include "llbutton.h" @@ -66,6 +70,8 @@ S32		LLView::sLastLeftXML = S32_MIN;  S32		LLView::sLastBottomXML = S32_MIN;  std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack; +LLView::DrilldownFunc LLView::sDrilldown = +	boost::bind(&LLView::pointInView, _1, _2, _3, HIT_TEST_USE_BOUNDING_RECT);  //#if LL_DEBUG  BOOL LLView::sIsDrawing = FALSE; @@ -346,13 +352,11 @@ void LLView::removeChild(LLView* child)  LLView::ctrl_list_t LLView::getCtrlList() const  {  	ctrl_list_t controls; -	for(child_list_const_iter_t iter = mChildList.begin(); -		iter != mChildList.end(); -		iter++) +	BOOST_FOREACH(LLView* viewp, mChildList)  	{ -		if((*iter)->isCtrl()) +		if(viewp->isCtrl())  		{ -			controls.push_back(static_cast<LLUICtrl*>(*iter)); +			controls.push_back(static_cast<LLUICtrl*>(viewp));  		}  	}  	return controls; @@ -428,6 +432,36 @@ BOOL LLView::isInEnabledChain() const  	return enabled;  } +static void buildPathname(std::ostream& out, const LLView* view) +{ +	if (! (view && view->getParent())) +	{ +		return; // Don't include root in the path. +	} + +	buildPathname(out, view->getParent()); + +	// Build pathname into ostream on the way back from recursion. +	out << '/' << view->getName(); +} + +std::string LLView::getPathname() const +{ +	std::ostringstream out; +	buildPathname(out, this); +	return out.str(); +} + +//static +std::string LLView::getPathname(const LLView* view) +{ +    if (! view) +    { +        return "NULL"; +    } +    return view->getPathname(); +} +  // virtual  BOOL LLView::canFocusChildren() const  { @@ -574,9 +608,8 @@ void LLView::deleteAllChildren()  void LLView::setAllChildrenEnabled(BOOL b)  { -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* viewp, mChildList)  	{ -		LLView* viewp = *child_it;  		viewp->setEnabled(b);  	}  } @@ -602,9 +635,8 @@ void LLView::setVisible(BOOL visible)  // virtual  void LLView::handleVisibilityChange ( BOOL new_visibility )  { -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* viewp, mChildList)  	{ -		LLView* viewp = *child_it;  		// only views that are themselves visible will have their overall visibility affected by their ancestors  		if (viewp->getVisible())  		{ @@ -646,56 +678,178 @@ void LLView::onMouseLeave(S32 x, S32 y, MASK mask)  	//llinfos << "Mouse left " << getName() << llendl;  } +bool LLView::visibleAndContains(S32 local_x, S32 local_y) +{ +	return sDrilldown(this, local_x, local_y) +		&& getVisible(); +} + +bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y) +{ +	return visibleAndContains(local_x, local_y) +		&& getEnabled(); +} + +void LLView::logMouseEvent() +{ +	if (sDebugMouseHandling) +	{ +		sMouseHandlerMessage = std::string("/") + mName + sMouseHandlerMessage; +	} +} + +template <typename METHOD, typename CHARTYPE> +LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& method, +										CHARTYPE c, MASK mask) +{ +	if ( getVisible() && getEnabled() ) +	{ +		BOOST_FOREACH(LLView* viewp, mChildList) +		{ +			if ((viewp->*method)(c, mask, TRUE)) +			{ +				if (LLView::sDebugKeys) +				{ +					llinfos << desc << " handled by " << viewp->getName() << llendl; +				} +				return viewp; +			} +		} +	} +    return NULL; +} + +// XDATA might be MASK, or S32 clicks +template <typename METHOD, typename XDATA> +LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block) +{ +	BOOST_FOREACH(LLView* viewp, mChildList) +	{ +		S32 local_x = x - viewp->getRect().mLeft; +		S32 local_y = y - viewp->getRect().mBottom; + +		if (!viewp->visibleEnabledAndContains(local_x, local_y)) +		{ +			continue; +		} + +		if ((viewp->*method)( local_x, local_y, extra ) +			|| (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y ))) +		{ +			viewp->logMouseEvent(); +			return viewp; +		} +	} +	return NULL; +}  LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* viewp, mChildList)  	{ -		LLView* viewp = *child_it;  		S32 local_x = x - viewp->getRect().mLeft;  		S32 local_y = y - viewp->getRect().mBottom; -		if(!viewp->pointInView(local_x, local_y)  -			|| !viewp->getVisible()) +		// Differs from childrenHandleMouseEvent() in that we want to offer +		// tooltips even for disabled widgets. +		if(!viewp->visibleAndContains(local_x, local_y))  		{  			continue;  		} -		if (viewp->handleToolTip(local_x, local_y, mask) ) +		if (viewp->handleToolTip(local_x, local_y, mask)  +			|| viewp->blockMouseEvent(local_x, local_y))  		{ -			if (sDebugMouseHandling) -			{ -				sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -			} +			viewp->logMouseEvent(); +			return viewp; +		} +	} +	return NULL; +} -			handled_view = viewp; -			break; +LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, +									   BOOL drop, +									   EDragAndDropType cargo_type, +									   void* cargo_data, +									   EAcceptance* accept, +									   std::string& tooltip_msg) +{ +	// default to not accepting drag and drop, will be overridden by handler +	*accept = ACCEPT_NO; + +	BOOST_FOREACH(LLView* viewp, mChildList) +	{ +		S32 local_x = x - viewp->getRect().mLeft; +		S32 local_y = y - viewp->getRect().mBottom; +		if( !viewp->visibleEnabledAndContains(local_x, local_y)) +		{ +			continue;  		} -		if (viewp->blockMouseEvent(local_x, local_y)) +		// Differs from childrenHandleMouseEvent() simply in that this virtual +		// method call diverges pretty radically from the usual (x, y, int). +		if (viewp->handleDragAndDrop(local_x, local_y, mask, drop, +									 cargo_type, +									 cargo_data, +									 accept, +									 tooltip_msg) +			|| viewp->blockMouseEvent(local_x, local_y))  		{ -			handled_view = viewp; -			break; +			return viewp;  		}  	} -	return handled_view; +	return NULL;  } +LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) +{ +	BOOST_FOREACH(LLView* viewp, mChildList) +	{ +		S32 local_x = x - viewp->getRect().mLeft; +		S32 local_y = y - viewp->getRect().mBottom; +		if(!viewp->visibleEnabledAndContains(local_x, local_y)) +		{ +			continue; +		} + +		// This call differentiates this method from childrenHandleMouseEvent(). +		LLUI::sWindow->setCursor(viewp->getHoverCursor()); + +		if (viewp->handleHover(local_x, local_y, mask) +			|| viewp->blockMouseEvent(local_x, local_y)) +		{ +			viewp->logMouseEvent(); +			return viewp; +		} +	} +	return NULL; +} -LLView*	LLView::childFromPoint(S32 x, S32 y) +LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)  { -	if (!getVisible()  ) +	if (!getVisible())  		return false; -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) + +	BOOST_FOREACH(LLView* viewp, mChildList)  	{ -		LLView* viewp = *child_it;  		S32 local_x = x - viewp->getRect().mLeft;  		S32 local_y = y - viewp->getRect().mBottom; -		if (!viewp->pointInView(local_x, local_y)  -			|| !viewp->getVisible() ) +		if (!viewp->visibleAndContains(local_x, local_y))  		{  			continue;  		} +		// Here we've found the first (frontmost) visible child at this level +		// containing the specified point. Is the caller asking us to drill +		// down and return the innermost leaf child at this point, or just the +		// top-level child? +		if (recur) +		{ +			LLView* leaf(viewp->childFromPoint(local_x, local_y, recur)); +			// Maybe viewp is already a leaf LLView, or maybe it has children +			// but this particular (x, y) point falls between them. If the +			// recursive call returns non-NULL, great, use that; else just use +			// viewp. +			return leaf? leaf : viewp; +		}  		return viewp;  	} @@ -708,15 +862,16 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)  	// parents provide tooltips first, which are optionally  	// overridden by children, in case child is mouse_opaque -	if (!mToolTipMsg.empty()) +	std::string tooltip = getToolTip(); +	if (!tooltip.empty())  	{  		// allow "scrubbing" over ui by showing next tooltip immediately  		// if previous one was still visible  		F32 timeout = LLToolTipMgr::instance().toolTipVisible()  -			? 0.f +			? LLUI::sSettingGroups["config"]->getF32( "ToolTipFastDelay" )  			: LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );  		LLToolTipMgr::instance().show(LLToolTip::Params() -			.message(mToolTipMsg) +			.message(tooltip)  			.sticky_rect(calcScreenRect())  			.delay_time(timeout)); @@ -815,45 +970,6 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  	return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;  } -LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, -									   BOOL drop, -									   EDragAndDropType cargo_type, -									   void* cargo_data, -									   EAcceptance* accept, -									   std::string& tooltip_msg) -{ -	LLView* handled_view = NULL; -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -	{ -		LLView* viewp = *child_it; -		S32 local_x = x - viewp->getRect().mLeft; -		S32 local_y = y - viewp->getRect().mBottom; -		if( !viewp->pointInView(local_x, local_y) || -			!viewp->getVisible() || -			!viewp->getEnabled()) -		{ -			continue; -		} -		if (viewp->handleDragAndDrop(local_x, local_y, mask, drop, -									 cargo_type, -									 cargo_data, -									 accept, -									 tooltip_msg)) -		{ -			handled_view = viewp; -			break; -		} - -		if (viewp->blockMouseEvent(x, y)) -		{ -			*accept = ACCEPT_NO; -			handled_view = viewp; -			break; -		} -	} -	return handled_view; -} -  void LLView::onMouseCaptureLost()  {  } @@ -903,391 +1019,57 @@ BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)  	return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;  } -  LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)  { -	LLView* handled_view = NULL; -	if (getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if (!viewp->pointInView(local_x, local_y)  -				|| !viewp->getVisible() -				|| !viewp->getEnabled()) -			{ -				continue; -			} - -			if (viewp->handleScrollWheel( local_x, local_y, clicks )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} - -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; -} - -LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) -{ -	LLView* handled_view = NULL; -	if (getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if(!viewp->pointInView(local_x, local_y)  -				|| !viewp->getVisible()  -				|| !viewp->getEnabled()) -			{ -				continue; -			} - -			if (viewp->handleHover(local_x, local_y, mask) ) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} - -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				LLUI::sWindow->setCursor(viewp->getHoverCursor()); - -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false);  }  // Called during downward traversal  LLView* LLView::childrenHandleKey(KEY key, MASK mask)  { -	LLView* handled_view = NULL; - -	if ( getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			if (viewp->handleKey(key, mask, TRUE)) -			{ -				if (LLView::sDebugKeys) -				{ -					llinfos << "Key handled by " << viewp->getName() << llendl; -				} -				handled_view = viewp; -				break; -			} -		} -	} - -	return handled_view; +	return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask);  }  // Called during downward traversal  LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)  { -	LLView* handled_view = NULL; - -	if ( getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			if (viewp->handleUnicodeChar(uni_char, TRUE)) -			{ -				if (LLView::sDebugKeys) -				{ -					llinfos << "Unicode character handled by " << viewp->getName() << llendl; -				} -				handled_view = viewp; -				break; -			} -		} -	} - -	return handled_view; +	return childrenHandleCharEvent("Unicode character", &LLView::handleUnicodeCharWithDummyMask, +								   uni_char, MASK_NONE);  }  LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; - -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -	{ -		LLView* viewp = *child_it; -		S32 local_x = x - viewp->getRect().mLeft; -		S32 local_y = y - viewp->getRect().mBottom; - -		if (!viewp->pointInView(local_x, local_y)  -			|| !viewp->getVisible()  -			|| !viewp->getEnabled()) -		{ -			continue; -		} - -		if(viewp->handleMouseDown( local_x, local_y, mask )) -		{ -			if (sDebugMouseHandling) -			{ -				sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -			} -			handled_view = viewp; -			break; -		} - -		if(viewp->blockMouseEvent(local_x, local_y)) -		{ -			handled_view = viewp; -			break; -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleMouseDown, x, y, mask);  }  LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; - -	if (getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; - -			if (!viewp->pointInView(local_x, local_y) -				|| !viewp->getVisible()  -				|| !viewp->getEnabled()) -			{ -				continue; -			} - -			if (viewp->handleRightMouseDown( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} - -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleRightMouseDown, x, y, mask);  }  LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; - -	if (getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if (!viewp->pointInView(local_x, local_y) -				|| !viewp->getVisible()  -				|| !viewp->getEnabled()) -			{ -				continue; -			} - -			if(viewp->handleMiddleMouseDown( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleMiddleMouseDown, x, y, mask);  }  LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; - -	if (getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; - -			if (!viewp->pointInView(local_x, local_y)  -				|| !viewp->getVisible()  -				|| !viewp->getEnabled()) -			{ -				continue; -			} - -			if (viewp->handleDoubleClick( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleDoubleClick, x, y, mask);  }  LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; -	if( getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if (!viewp->pointInView(local_x, local_y) -				|| !viewp->getVisible() -				|| !viewp->getEnabled()) -			{ -				continue; -			} -			 -			if (viewp->handleMouseUp( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);  }  LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; -	if( getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if (!viewp->pointInView(local_x, local_y)  -				|| !viewp->getVisible()  -				|| !viewp->getEnabled() ) -			{ -				continue; -			} - -			if(viewp->handleRightMouseUp( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} -				handled_view = viewp; -				break; -			} - -			if(viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleRightMouseUp, x, y, mask);  }  LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)  { -	LLView* handled_view = NULL; -	if( getVisible() && getEnabled() ) -	{ -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) -		{ -			LLView* viewp = *child_it; -			S32 local_x = x - viewp->getRect().mLeft; -			S32 local_y = y - viewp->getRect().mBottom; -			if (!viewp->pointInView(local_x, local_y)  -				|| !viewp->getVisible()  -				|| !viewp->getEnabled()) -			{ -				continue; -			} -				 -			if(viewp->handleMiddleMouseUp( local_x, local_y, mask )) -			{ -				if (sDebugMouseHandling) -				{ -					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage; -				} -				handled_view = viewp; -				break; -			} - -			if (viewp->blockMouseEvent(local_x, local_y)) -			{ -				handled_view = viewp; -				break; -			} -		} -	} -	return handled_view; +	return childrenHandleMouseEvent(&LLView::handleMiddleMouseUp, x, y, mask);  }  void LLView::draw() @@ -1460,9 +1242,8 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)  		mRect.mTop = getRect().mBottom + height;  		// move child views according to reshape flags -		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +		BOOST_FOREACH(LLView* viewp, mChildList)  		{ -			LLView* viewp = *child_it;  			LLRect child_rect( viewp->mRect );  			if (viewp->followsRight() && viewp->followsLeft()) @@ -1525,10 +1306,8 @@ LLRect LLView::calcBoundingRect()  {  	LLRect local_bounding_rect = LLRect::null; -	child_list_const_iter_t child_it; -	for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* childp, mChildList)  	{ -		LLView* childp = *child_it;  		// ignore invisible and "top" children when calculating bounding rect  		// such as combobox popups  		if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl())  @@ -1693,11 +1472,9 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const  	//richard: should we allow empty names?  	//if(name.empty())  	//	return NULL; -	child_list_const_iter_t child_it;  	// Look for direct children *first* -	for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* childp, mChildList)  	{ -		LLView* childp = *child_it;  		llassert(childp);  		if (childp->getName() == name)  		{ @@ -1707,9 +1484,8 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const  	if (recurse)  	{  		// Look inside each child as well. -		for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +		BOOST_FOREACH(LLView* childp, mChildList)  		{ -			LLView* childp = *child_it;  			llassert(childp);  			LLView* viewp = childp->findChildView(name, recurse);  			if ( viewp ) @@ -1826,13 +1602,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)  { @@ -2850,9 +2619,9 @@ S32	LLView::notifyParent(const LLSD& info)  bool	LLView::notifyChildren(const LLSD& info)  {  	bool ret = false; -	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) +	BOOST_FOREACH(LLView* childp, mChildList)  	{ -		ret |= (*child_it)->notifyChildren(info); +		ret = ret || childp->notifyChildren(info);  	}  	return ret;  } @@ -2872,3 +2641,24 @@ const LLViewDrawContext& LLViewDrawContext::getCurrentContext()  	return *sDrawContextStack.back();  } + +LLSD LLView::getInfo(void) +{ +	LLSD info; +	addInfo(info); +	return info; +} + +void LLView::addInfo(LLSD & info) +{ +	info["path"] = getPathname(); +	info["class"] = typeid(*this).name(); +	info["visible"] = getVisible(); +	info["visible_chain"] = isInVisibleChain(); +	info["enabled"] = getEnabled(); +	info["enabled_chain"] = isInEnabledChain(); +	info["available"] = isAvailable(); +	LLRect rect(calcScreenRect()); +	info["rect"] = LLSDMap("left", rect.mLeft)("top", rect.mTop) +				("right", rect.mRight)("bottom", rect.mBottom); +} diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 594a5eec6b..08828e55e6 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -50,6 +50,8 @@  #include "llfocusmgr.h"  #include <list> +#include <boost/function.hpp> +#include <boost/noncopyable.hpp>  class LLSD; @@ -95,13 +97,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 +149,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&); @@ -240,7 +240,7 @@ public:  	ECursorType	getHoverCursor() { return mHoverCursor; } -	const std::string& getToolTip() const			{ return mToolTipMsg.getString(); } +	virtual const std::string getToolTip() const			{ return mToolTipMsg.getString(); }  	void		sendChildToFront(LLView* child);  	void		sendChildToBack(LLView* child); @@ -437,12 +437,15 @@ public:  	/*virtual*/ void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;  	/*virtual*/ void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; -	virtual		LLView*	childFromPoint(S32 x, S32 y); +	virtual		LLView*	childFromPoint(S32 x, S32 y, bool recur=false);  	// view-specific handlers   	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);  	virtual void	onMouseLeave(S32 x, S32 y, MASK mask); +	std::string getPathname() const; +	// static method handles NULL pointer too +	static std::string getPathname(const LLView*);  	template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const  	{ @@ -467,6 +470,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 +499,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(), @@ -511,11 +527,17 @@ public:  	virtual S32	notify(const LLSD& info) { return 0;};  	static const LLViewDrawContext& getDrawContext(); +	 +	// Returns useful information about this ui widget. +	LLSD getInfo(void);  protected:  	void			drawDebugRect();  	void			drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);  	void			drawChildren(); +	bool			visibleAndContains(S32 local_x, S32 local_Y); +	bool			visibleEnabledAndContains(S32 local_x, S32 local_y); +	void			logMouseEvent();  	LLView*	childrenHandleKey(KEY key, MASK mask);  	LLView* childrenHandleUnicodeChar(llwchar uni_char); @@ -538,9 +560,24 @@ protected:  	LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask);  	ECursorType mHoverCursor; -	 + +	virtual void addInfo(LLSD & info);  private: +	template <typename METHOD, typename XDATA> +	LLView* childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block = true); + +	template <typename METHOD, typename CHARTYPE> +	LLView* childrenHandleCharEvent(const std::string& desc, const METHOD& method, +									CHARTYPE c, MASK mask); + +	// adapter to blur distinction between handleKey() and handleUnicodeChar() +	// for childrenHandleCharEvent() +	BOOL	handleUnicodeCharWithDummyMask(llwchar uni_char, MASK /* dummy */, BOOL from_parent) +	{ +		return handleUnicodeChar(uni_char, from_parent); +	} +  	LLView*		mParentView;  	child_list_t mChildList; @@ -582,7 +619,35 @@ private:  	LLView& getDefaultWidgetContainer() const; +	// This allows special mouse-event targeting logic for testing. +	typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc; +	static DrilldownFunc sDrilldown; +  public: +	// This is the only public accessor to alter sDrilldown. This is not +	// an accident. The intended usage pattern is like: +	// { +	//     LLView::TemporaryDrilldownFunc scoped_func(myfunctor); +	//     // ... test with myfunctor ... +	// } // exiting block restores original LLView::sDrilldown +	class TemporaryDrilldownFunc: public boost::noncopyable +	{ +	public: +		TemporaryDrilldownFunc(const DrilldownFunc& func): +			mOldDrilldown(sDrilldown) +		{ +			sDrilldown = func; +		} + +		~TemporaryDrilldownFunc() +		{ +			sDrilldown = mOldDrilldown; +		} + +	private: +		DrilldownFunc mOldDrilldown; +	}; +  	// Depth in view hierarchy during rendering  	static S32	sDepth; diff --git a/indra/llui/llviewinject.cpp b/indra/llui/llviewinject.cpp new file mode 100644 index 0000000000..46c5839f8e --- /dev/null +++ b/indra/llui/llviewinject.cpp @@ -0,0 +1,49 @@ +/** + * @file   llviewinject.cpp + * @author Nat Goodspeed + * @date   2011-08-16 + * @brief  Implementation for llviewinject. + *  + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Copyright (c) 2011, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llviewinject.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +llview::TargetEvent::TargetEvent(LLView* view) +{ +    // Walk up the view tree from target LLView to the root (NULL). If +    // passed NULL, iterate 0 times. +    for (; view; view = view->getParent()) +    { +        // At each level, operator() is going to ask: for a particular parent +        // LLView*, which of its children should I select? So for this view's +        // parent, select this view. +        mChildMap[view->getParent()] = view; +    } +} + +bool llview::TargetEvent::operator()(const LLView* view, S32 /*x*/, S32 /*y*/) const +{ +    // We are being called to decide whether to direct an incoming mouse event +    // to this child view. (Normal LLView processing is to check whether the +    // incoming (x, y) is within the view.) Look up the parent to decide +    // whether, for that parent, this is the previously-selected child. +    ChildMap::const_iterator found(mChildMap.find(view->getParent())); +    // If we're looking at a child whose parent isn't even in the map, never +    // mind. +    if (found == mChildMap.end()) +    { +        return false; +    } +    // So, is this the predestined child for this parent? +    return (view == found->second); +} diff --git a/indra/llui/llviewinject.h b/indra/llui/llviewinject.h new file mode 100644 index 0000000000..0de3d155c4 --- /dev/null +++ b/indra/llui/llviewinject.h @@ -0,0 +1,56 @@ +/** + * @file   llviewinject.h + * @author Nat Goodspeed + * @date   2011-08-16 + * @brief  Supplemental LLView functionality used for simulating UI events. + *  + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Copyright (c) 2011, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLVIEWINJECT_H) +#define LL_LLVIEWINJECT_H + +#include "llview.h" +#include <map> + +namespace llview +{ + +    /** +     * TargetEvent is a callable with state, specifically intended for use as +     * an LLView::TemporaryDrilldownFunc. Instantiate it with the desired +     * target LLView*; pass it to a TemporaryDrilldownFunc instance; +     * TargetEvent::operator() will then attempt to direct subsequent mouse +     * events to the desired target LLView*. (This is an "attempt" because +     * LLView will still balk unless the target LLView and every parent are +     * visible and enabled.) +     */ +    class TargetEvent +    { +    public: +        /** +         * Construct TargetEvent with the desired target LLView*. (See +         * LLUI::resolvePath() to obtain an LLView* given a string pathname.) +         * This sets up for operator(). +         */ +        TargetEvent(LLView* view); + +        /** +         * This signature must match LLView::DrilldownFunc. When you install +         * this TargetEvent instance using LLView::TemporaryDrilldownFunc, +         * LLView will call this method to decide whether to propagate an +         * incoming mouse event to the passed child LLView*. +         */ +        bool operator()(const LLView*, S32 x, S32 y) const; + +    private: +        // For a given parent LLView, identify which child to select. +        typedef std::map<LLView*, LLView*> ChildMap; +        ChildMap mChildMap; +    }; + +} // llview namespace + +#endif /* ! defined(LL_LLVIEWINJECT_H) */ diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index d522123260..4f251db93b 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -124,8 +124,8 @@ namespace LLInitParam  	{  		descriptor.mCurrentBlockPtr = this;  	} -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {} +	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } +	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {}  	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; }  	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }  	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 2f814f4200..c1fb050206 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -72,7 +72,6 @@ S32 LLUIImage::getHeight() const  namespace LLInitParam  { -	S32 Parser::sNextParseGeneration = 0;  	BlockDescriptor::BlockDescriptor() {}  	ParamDescriptor::ParamDescriptor(param_handle_t p,   						merge_func_t merge_func,  diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index fb6a2eabf1..627f3129e9 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -66,8 +66,6 @@ namespace LLInitParam  	BaseBlock::BaseBlock() {}  	BaseBlock::~BaseBlock() {} -	S32 Parser::sNextParseGeneration = 0; -  	BlockDescriptor::BlockDescriptor() {}  	ParamDescriptor::ParamDescriptor(param_handle_t p,   						merge_func_t merge_func,  @@ -98,8 +96,8 @@ namespace LLInitParam  		mEnclosingBlockOffset = 0x7FFFffff & ((U32)(my_addr - block_addr));  	} -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, S32 generation){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const {} +	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } +	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {}  	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; }  	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }  	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } | 
