diff options
Diffstat (limited to 'indra/llui')
108 files changed, 5916 insertions, 2502 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 0bbdcfd6ff..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} @@ -29,11 +31,13 @@ set(llui_SOURCE_FILES      llaccordionctrl.cpp      llaccordionctrltab.cpp      llbadge.cpp +    llbadgeholder.cpp      llbadgeowner.cpp      llbutton.cpp      llcheckboxctrl.cpp      llclipboard.cpp      llcombobox.cpp +    llcommandmanager.cpp      llconsole.cpp      llcontainerview.cpp      llctrlselectioninterface.cpp @@ -98,6 +102,7 @@ set(llui_SOURCE_FILES      lltimectrl.cpp      lltransutil.cpp      lltoggleablemenu.cpp +    lltoolbar.cpp      lltooltip.cpp      llui.cpp      lluicolortable.cpp @@ -111,6 +116,7 @@ set(llui_SOURCE_FILES      llurlmatch.cpp      llurlregistry.cpp      llviewborder.cpp +    llviewinject.cpp      llviewmodel.cpp      llview.cpp      llviewquery.cpp @@ -123,12 +129,14 @@ set(llui_HEADER_FILES      llaccordionctrl.h      llaccordionctrltab.h      llbadge.h +    llbadgeholder.h      llbadgeowner.h      llbutton.h      llcallbackmap.h      llcheckboxctrl.h      llclipboard.h      llcombobox.h +    llcommandmanager.h      llconsole.h      llcontainerview.h      llctrlselectioninterface.h @@ -165,7 +173,7 @@ set(llui_HEADER_FILES      llnotificationslistener.h      llnotificationsutil.h      llnotificationtemplate.h -	llnotificationvisibilityrule.h +    llnotificationvisibilityrule.h      llpanel.h      llprogressbar.h      llradiogroup.h @@ -198,6 +206,7 @@ set(llui_HEADER_FILES      lltextvalidate.h      lltimectrl.h      lltoggleablemenu.h +    lltoolbar.h      lltooltip.h      lltransutil.h      lluicolortable.h @@ -214,6 +223,7 @@ set(llui_HEADER_FILES      llurlmatch.h      llurlregistry.h      llviewborder.h +    llviewinject.h      llviewmodel.h      llview.h      llviewquery.h @@ -243,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/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 6afe276379..c025cd7939 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -339,7 +339,7 @@ LLAccordionCtrlTab::Params::Params()  	,fit_panel("fit_panel",true)  	,selection_enabled("selection_enabled", false)  { -	mouse_opaque(false); +	changeDefault(mouse_opaque, false);  }  LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) @@ -973,10 +973,10 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)  		if ( root_rect.overlaps(screen_rect)  && LLUI::sDirtyRect.overlaps(screen_rect))  		{ -			glMatrixMode(GL_MODELVIEW); +			gGL.matrixMode(LLRender::MM_MODELVIEW);  			LLUI::pushMatrix();  			{ -				LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom, 0.f); +				LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom);  				child->draw();  			} diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index c28a947a7f..8ede4e3468 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -27,11 +27,14 @@  #define LLBADGE_CPP  #include "llbadge.h" +#include "llscrollcontainer.h"  #include "lluictrlfactory.h"  static LLDefaultChildRegistry::Register<LLBadge> r("badge"); +static const S32 BADGE_OFFSET_NOT_SPECIFIED = 0x7FFFFFFF; +  // Compiler optimization, generate extern template  template class LLBadge* LLView::getChild<class LLBadge>(const std::string& name, BOOL recurse) const; @@ -43,15 +46,16 @@ LLBadge::Params::Params()  	, image_color("image_color")  	, label("label")  	, label_color("label_color") +	, label_offset_horiz("label_offset_horiz") +	, label_offset_vert("label_offset_vert")  	, location("location", LLRelPos::TOP_LEFT) +	, location_offset_hcenter("location_offset_hcenter") +	, location_offset_vcenter("location_offset_vcenter")  	, location_percent_hcenter("location_percent_hcenter")  	, location_percent_vcenter("location_percent_vcenter")  	, padding_horiz("padding_horiz")  	, padding_vert("padding_vert") -{ -	// We set a name here so the name isn't necessary in any xml files that use badges -	name = "badge"; -} +{}  bool LLBadge::Params::equals(const Params& a) const  { @@ -65,7 +69,11 @@ bool LLBadge::Params::equals(const Params& a) const  	comp &= (image_color() == a.image_color());  	comp &= (label() == a.label());  	comp &= (label_color() == a.label_color()); +	comp &= (label_offset_horiz() == a.label_offset_horiz()); +	comp &= (label_offset_vert() == a.label_offset_vert());  	comp &= (location() == a.location()); +	comp &= (location_offset_hcenter() == a.location_offset_hcenter()); +	comp &= (location_offset_vcenter() == a.location_offset_vcenter());  	comp &= (location_percent_hcenter() == a.location_percent_hcenter());  	comp &= (location_percent_vcenter() == a.location_percent_vcenter());  	comp &= (padding_horiz() == a.padding_horiz()); @@ -84,17 +92,32 @@ LLBadge::LLBadge(const LLBadge::Params& p)  	, mImageColor(p.image_color)  	, mLabel(p.label)  	, mLabelColor(p.label_color) +	, mLabelOffsetHoriz(p.label_offset_horiz) +	, mLabelOffsetVert(p.label_offset_vert)  	, mLocation(p.location) +	, mLocationOffsetHCenter(BADGE_OFFSET_NOT_SPECIFIED) +	, mLocationOffsetVCenter(BADGE_OFFSET_NOT_SPECIFIED)  	, mLocationPercentHCenter(0.5f)  	, mLocationPercentVCenter(0.5f)  	, mPaddingHoriz(p.padding_horiz)  	, mPaddingVert(p.padding_vert) +	, mParentScroller(NULL)  {  	if (mImage.isNull())  	{  		llwarns << "Badge: " << getName() << " with no image!" << llendl;  	} +	if (p.location_offset_hcenter.isProvided()) +	{ +		mLocationOffsetHCenter = p.location_offset_hcenter(); +	} + +	if (p.location_offset_vcenter.isProvided()) +	{ +		mLocationOffsetVCenter = p.location_offset_vcenter(); +	} +  	//  	// The following logic is to set the mLocationPercentHCenter and mLocationPercentVCenter  	// based on the Location enum and our horizontal and vertical location percentages.  The @@ -131,6 +154,27 @@ LLBadge::~LLBadge()  {  } +bool LLBadge::addToView(LLView * view) +{ +	bool child_added = view->addChild(this); + +	if (child_added) +	{ +		setShape(view->getLocalRect()); + +		// Find a parent scroll container, if there is one in case we need it for positioning + +		LLView * parent = mOwner.get(); + +		while ((parent != NULL) && ((mParentScroller = dynamic_cast<LLScrollContainer *>(parent)) == NULL)) +		{ +			parent = parent->getParent(); +		} +	} + +	return child_added; +} +  void LLBadge::setLabel(const LLStringExplicit& label)  {  	mLabel = label; @@ -183,21 +227,11 @@ void LLBadge::draw()  		if (owner_view)  		{  			// -			// Calculate badge position based on owner -			// -			 -			LLRect owner_rect; -			owner_view->localRectToOtherView(owner_view->getLocalRect(), & owner_rect, this); -			 -			F32 badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter; -			F32 badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter; - -			//  			// Calculate badge size based on label text  			//  			LLWString badge_label_wstring = mLabel; -			 +  			S32 badge_label_begin_offset = 0;  			S32 badge_char_length = S32_MAX;  			S32 badge_pixel_length = S32_MAX; @@ -210,6 +244,77 @@ void LLBadge::draw()  			F32 badge_height = (2.0f * mPaddingVert) + mGLFont->getLineHeight();  			// +			// Calculate badge position based on owner +			// +			 +			LLRect owner_rect; +			owner_view->localRectToOtherView(owner_view->getLocalRect(), & owner_rect, this); + +			S32 location_offset_horiz = mLocationOffsetHCenter; +			S32 location_offset_vert = mLocationOffsetVCenter; + +			// If we're in a scroll container, do some math to keep us in the same place on screen if applicable +			if (mParentScroller != NULL) +			{ +				LLRect visibleRect = mParentScroller->getVisibleContentRect(); + +				if (mLocationOffsetHCenter != BADGE_OFFSET_NOT_SPECIFIED) +				{ +					if (LLRelPos::IsRight(mLocation)) +					{ +						location_offset_horiz += visibleRect.mRight; +					} +					else if (LLRelPos::IsLeft(mLocation)) +					{ +						location_offset_horiz += visibleRect.mLeft; +					} +					else // center +					{ +						location_offset_horiz += (visibleRect.mLeft + visibleRect.mRight) / 2; +					} +				} + +				if (mLocationOffsetVCenter != BADGE_OFFSET_NOT_SPECIFIED) +				{ +					if (LLRelPos::IsTop(mLocation)) +					{ +						location_offset_vert += visibleRect.mTop; +					} +					else if (LLRelPos::IsBottom(mLocation)) +					{ +						location_offset_vert += visibleRect.mBottom; +					} +					else // center +					{ +						location_offset_vert += (visibleRect.mBottom + visibleRect.mTop) / 2; +					} +				} +			} +			 +			F32 badge_center_x; +			F32 badge_center_y; + +			// Compute x position +			if (mLocationOffsetHCenter == BADGE_OFFSET_NOT_SPECIFIED) +			{ +				badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter; +			} +			else +			{ +				badge_center_x = location_offset_horiz; +			} + +			// Compute y position +			if (mLocationOffsetVCenter == BADGE_OFFSET_NOT_SPECIFIED) +			{ +				badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter; +			} +			else +			{ +				badge_center_y = location_offset_vert; +			} + +			//  			// Draw button image, if available.  			// Otherwise draw basic rectangular button.  			// @@ -241,8 +346,10 @@ void LLBadge::draw()  			// Draw the label  			// -			mGLFont->render(badge_label_wstring, badge_label_begin_offset, -							badge_center_x, badge_center_y, +			mGLFont->render(badge_label_wstring, +							badge_label_begin_offset, +							badge_center_x + mLabelOffsetHoriz, +							badge_center_y + mLabelOffsetVert,  							mLabelColor % alpha,  							LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position  							LLFontGL::NORMAL, // normal text (not bold, italics, etc.) diff --git a/indra/llui/llbadge.h b/indra/llui/llbadge.h index 0f923ef01b..4b21a71aaa 100644 --- a/indra/llui/llbadge.h +++ b/indra/llui/llbadge.h @@ -39,8 +39,9 @@  // Declarations  // -class LLUICtrlFactory;  class LLFontGL; +class LLScrollContainer; +class LLUICtrlFactory;  //  // Relative Position Alignment @@ -104,7 +105,12 @@ public:  		Optional< std::string >			label;  		Optional< LLUIColor >			label_color; +		Optional< S32 >					label_offset_horiz; +		Optional< S32 >					label_offset_vert; +  		Optional< LLRelPos::Location >	location; +		Optional< S32 >					location_offset_hcenter; +		Optional< S32 >					location_offset_vcenter;  		Optional< U32 >					location_percent_hcenter;  		Optional< U32 >					location_percent_vcenter; @@ -123,7 +129,9 @@ protected:  public:  	~LLBadge(); -	 + +	bool				addToView(LLView * view); +  	virtual void		draw();  	const std::string	getLabel() const { return wstring_to_utf8str(mLabel); } @@ -141,7 +149,12 @@ private:  	LLUIString				mLabel;  	LLUIColor				mLabelColor; +	S32						mLabelOffsetHoriz; +	S32						mLabelOffsetVert; +  	LLRelPos::Location		mLocation; +	S32						mLocationOffsetHCenter; +	S32						mLocationOffsetVCenter;  	F32						mLocationPercentHCenter;  	F32						mLocationPercentVCenter; @@ -149,6 +162,8 @@ private:  	F32						mPaddingHoriz;  	F32						mPaddingVert; + +	LLScrollContainer*		mParentScroller;  };  // Build time optimization, generate once in .cpp file diff --git a/indra/llui/llbadgeholder.cpp b/indra/llui/llbadgeholder.cpp new file mode 100644 index 0000000000..1f786f36ae --- /dev/null +++ b/indra/llui/llbadgeholder.cpp @@ -0,0 +1,45 @@ +/**  + * @file llbadgeholder.cpp + * @brief Source for badge holders + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * 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 "llbadgeholder.h" + +#include "llbadge.h" +#include "llview.h" + + +bool LLBadgeHolder::addBadge(LLBadge * badge) +{ +	bool badge_added = false; + +	LLView * this_view = dynamic_cast<LLView *>(this); + +	if (this_view && mAcceptsBadge) +	{ +		badge_added = badge->addToView(this_view); +	} + +	return badge_added; +} diff --git a/indra/llui/llbadgeholder.h b/indra/llui/llbadgeholder.h new file mode 100644 index 0000000000..2538eaae91 --- /dev/null +++ b/indra/llui/llbadgeholder.h @@ -0,0 +1,56 @@ +/**  + * @file llbadgeholder.h + * @brief Header for badge holders + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * 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_LLBADGEHOLDER_H +#define LL_LLBADGEHOLDER_H + +// +// Classes +// + +class LLBadge; + +class LLBadgeHolder +{ +public: + +	LLBadgeHolder(bool acceptsBadge) +		: mAcceptsBadge(acceptsBadge) +	{ +	} + +	void setAcceptsBadge(bool acceptsBadge) { mAcceptsBadge = acceptsBadge; } +	bool acceptsBadge() const { return mAcceptsBadge; } + +	virtual bool addBadge(LLBadge * badge); + +private: + +	bool		mAcceptsBadge; + +}; + +#endif  // LL_LLBADGEHOLDER_H diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp index 77f15567bf..1860a05edd 100644 --- a/indra/llui/llbadgeowner.cpp +++ b/indra/llui/llbadgeowner.cpp @@ -26,6 +26,7 @@  #include "linden_common.h" +#include "llbadgeholder.h"  #include "llbadgeowner.h"  #include "llpanel.h" @@ -81,40 +82,44 @@ void LLBadgeOwner::setBadgeVisibility(bool visible)  	}  } -void LLBadgeOwner::addBadgeToParentPanel() +bool LLBadgeOwner::addBadgeToParentPanel()  { +	bool badge_added = false; +  	LLView * owner_view = mBadgeOwnerView.get();  	if (mBadge && owner_view)  	{ -		// Badge parent is badge owner by default -		LLView * badge_parent = owner_view; +		LLBadgeHolder * badge_holder = NULL; -		// Find the appropriate parent for the badge +		// Find the appropriate holder for the badge  		LLView * parent = owner_view->getParent();  		while (parent)  		{ -			LLPanel * parent_panel = dynamic_cast<LLPanel *>(parent); +			LLBadgeHolder * badge_holder_panel = dynamic_cast<LLBadgeHolder *>(parent); -			if (parent_panel && parent_panel->acceptsBadge()) +			if (badge_holder_panel && badge_holder_panel->acceptsBadge())  			{ -				badge_parent = parent; +				badge_holder = badge_holder_panel;  				break;  			}  			parent = parent->getParent();  		} -		if (badge_parent) +		if (badge_holder)  		{ -			badge_parent->addChild(mBadge); +			badge_added = badge_holder->addBadge(mBadge);  		}  		else  		{ -			llwarns << "Unable to find parent panel for badge " << mBadge->getName() << " on " << owner_view->getName() << llendl; +			// Badge parent is fallback badge owner if no valid holder exists in the hierarchy +			badge_added = mBadge->addToView(owner_view);  		}  	} + +	return badge_added;  }  LLBadge* LLBadgeOwner::createBadge(const LLBadge::Params& p) diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h index a2399189a5..8d03e30645 100644 --- a/indra/llui/llbadgeowner.h +++ b/indra/llui/llbadgeowner.h @@ -41,7 +41,7 @@ public:  	LLBadgeOwner(LLHandle< LLView > viewHandle);  	void initBadgeParams(const LLBadge::Params& p); -	void addBadgeToParentPanel(); +	bool addBadgeToParentPanel();  	bool badgeHasParent() const { return (mBadge && mBadge->getParent()); } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 7b015bd576..705fe16559 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,19 +100,22 @@ 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") +	handle_right_mouse("handle_right_mouse"), +	held_down_delay("held_down_delay"), +	button_flash_count("button_flash_count"), +	button_flash_rate("button_flash_rate")  {  	addSynonym(is_toggle, "toggle"); -	held_down_delay.seconds = 0.5f; -	initial_value.set(LLSD(false), false); +	changeDefault(initial_value, LLSD(false));  }  LLButton::LLButton(const LLButton::Params& p)  :	LLUICtrl(p), -	LLBadgeOwner(LLView::getHandle()), +	LLBadgeOwner(getHandle()),  	mMouseDownFrame(0),  	mMouseHeldDownCount(0),  	mBorderEnabled( 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,37 @@ 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()  { +	static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);  	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 ) +	if( mFlashing)  	{ -		F32 elapsed = mFlashingTimer.getElapsedTimeF32(); -		S32 flash_count = S32(elapsed * button_flash_rate * 2.f); -		// flash on or off? -		flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f); +		if ( sEnableButtonFlashing) +		{ +			F32 elapsed = mFlashingTimer.getElapsedTimeF32(); +			S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f); +			// flash on or off? +			flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f); +		} +		else +		{ // otherwise just highlight button in flash color +			flash = true; +		}  	}  	bool pressed_by_keyboard = FALSE; @@ -597,7 +634,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 +744,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 +809,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 +829,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 +841,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 +859,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 +895,7 @@ void LLButton::draw()  		S32 y_offset = 2 + (getRect().getHeight() - 20)/2; -		if (pressed) +		if (pressed && mDisplayPressedState)  		{  			y_offset--;  			x++; @@ -876,9 +908,9 @@ void LLButton::draw()  		// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.  		mLastDrawCharsCount = mGLFont->render(label, 0,  			(F32)x, -			(F32)(mBottomVPad + y_offset), +			(F32)(getRect().getHeight() / 2 + mBottomVPad),  			label_color % alpha, -			mHAlign, LLFontGL::BOTTOM, +			mHAlign, LLFontGL::VCENTER,  			LLFontGL::NORMAL,  			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,  			S32_MAX, text_width, @@ -919,7 +951,7 @@ void LLButton::setToggleState(BOOL b)  void LLButton::setFlashing( BOOL b )	  {  -	if (b != mFlashing) +	if ((bool)b != mFlashing)  	{  		mFlashing = b;   		mFlashingTimer.reset(); @@ -959,6 +991,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 +1019,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 +1029,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)  		{ -			setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom)); +			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) +		{ +			reshape(min_width, getRect().getHeight());  		}  	}   } @@ -1140,7 +1201,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 @@ -1181,7 +1242,6 @@ void LLButton::resetMouseDownTimer()  	mMouseDownTimer.reset();  } -  BOOL LLButton::handleDoubleClick(S32 x, S32 y, MASK mask)  {  	// just treat a double click as a second click 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..14173fdbb0 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -34,103 +34,113 @@  #include "llview.h"  #include "llwindow.h" -// Global singleton -LLClipboard gClipboard; - - -LLClipboard::LLClipboard() +LLClipboard::LLClipboard() : +	mGeneration(0)  { +	reset();  } -  LLClipboard::~LLClipboard()  { +	reset();  } - -void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +void LLClipboard::reset()  { -	mSourceID = source_id; -	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToClipboard( mString ); +	// Increment the clipboard count +	mGeneration++; +	// Clear the clipboard +	mObjects.clear(); +	mCutMode = false; +	mString = LLWString();  } -void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) +// Copy the input uuid to the LL clipboard +bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	mSourceID = source_id; -	mString = src; -	LLView::getWindow()->copyTextToClipboard( mString ); +	reset(); +	return addToClipboard(src, type);  } -const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) +// Add the input uuid to the LL clipboard +// Convert the uuid to string and concatenate that string to the system clipboard if legit +bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type)  { -	if( mSourceID.notNull() ) +	bool res = false; +	if (src.notNull())  	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromClipboard(temp_string); - -		if( temp_string != mString ) +		res = true; +		if (LLAssetType::lookupIsAssetIDKnowable(type))  		{ -			mSourceID.setNull(); -			mString = temp_string; +			LLWString source = utf8str_to_wstring(src.asString()); +			res = addToClipboard(source, 0, source.size()); +		} +		if (res) +		{ +			mObjects.push_back(src); +			mGeneration++;  		}  	} -	else -	{ -		LLView::getWindow()->pasteTextFromClipboard(mString); -	} +	return res; +} -	if( source_id ) +bool LLClipboard::pasteFromClipboard(std::vector<LLUUID>& inv_objects) const +{ +	bool res = false; +	S32 count = mObjects.size(); +	if (count > 0)  	{ -		*source_id = mSourceID; +		res = true; +		inv_objects.clear(); +		for (S32 i = 0; i < count; i++) +		{ +			inv_objects.push_back(mObjects[i]); +		}  	} - -	return mString; +	return res;  } +// Returns true if the LL Clipboard has pasteable items in it +bool LLClipboard::hasContents() const +{ +	return (mObjects.size() > 0); +} -BOOL LLClipboard::canPasteString() const +// Returns true if the input uuid is in the list of clipboard objects +bool LLClipboard::isOnClipboard(const LLUUID& object) const  { -	return LLView::getWindow()->isClipboardTextAvailable(); +	std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); +	return (iter != mObjects.end());  } +// Copy the input string to the LL and the system clipboard +bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) +{ +	return addToClipboard(src, pos, len, use_primary); +} -void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +// Concatenate the input string to the LL and the system clipboard +bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)  { -	mSourceID = source_id;  	mString = src.substr(pos, len); -	LLView::getWindow()->copyTextToPrimary( mString ); +	return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString));  } - -const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) +// Copy the System clipboard to the output string. +// Manage the LL Clipboard / System clipboard consistency +bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary)  { -	if( mSourceID.notNull() ) +	bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); +	if (res)  	{ -		LLWString temp_string; -		LLView::getWindow()->pasteTextFromPrimary(temp_string); - -		if( temp_string != mString ) -		{ -			mSourceID.setNull(); -			mString = temp_string; -		} +		mString = dst;  	} -	else -	{ -		LLView::getWindow()->pasteTextFromPrimary(mString); -	} - -	if( source_id ) -	{ -		*source_id = mSourceID; -	} - -	return mString; +	return res;  } - -BOOL LLClipboard::canPastePrimaryString() const +// Return true if there's something on the System clipboard +bool LLClipboard::isTextAvailable(bool use_primary) const  { -	return LLView::getWindow()->isPrimaryTextAvailable(); +	return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable());  } + diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 24cb46c3f4..fd2e7610df 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -27,39 +27,68 @@  #ifndef LL_LLCLIPBOARD_H  #define LL_LLCLIPBOARD_H +#include <boost/function.hpp>  #include "llstring.h"  #include "lluuid.h" +#include "stdenums.h" +#include "llsingleton.h" +#include "llassettype.h" +#include "llinventory.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLClipboard +// +// This class is used to cut/copy/paste text strings and inventory items around  +// the world. Use LLClipboard::instance().method() to use its methods. +// Note that the text and UUIDs are loosely coupled only. There are few cases +// where the viewer does offer a serialized version of the UUID on the clipboard. +// In those case, the text is overridden when copying/cutting the item.  +// In all other cases, the text and the UUIDs are very much independent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLClipboard +class LLClipboard : public LLSingleton<LLClipboard>  {  public:  	LLClipboard();  	~LLClipboard(); +	 +	// Clears the clipboard +	void reset(); +	// Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) +	int	getGeneration() const { return mGeneration; } -	/* We support two flavors of clipboard.  The default is the explicitly -	   copy-and-pasted clipboard.  The second is the so-called 'primary' clipboard -	   which is implicitly copied upon selection on platforms which expect this -	   (i.e. X11/Linux). */ +	// Text strings management: +	// ------------------------ +	// We support two flavors of text clipboards. The default is the explicitly +	// copy-and-pasted clipboard. The second is the so-called 'primary' clipboard +	// which is implicitly copied upon selection on platforms which expect this +	// (i.e. X11/Linux, Mac). +	bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); +	bool pasteFromClipboard(LLWString& dst, bool use_primary = false); +	bool isTextAvailable(bool use_primary = false) const; +	 +	// Object list management: +	// ----------------------- +	// Clears and adds one single object to the clipboard +	bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Adds one object to the current list of objects on the clipboard +	bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); +	// Gets a copy of the objects on the clipboard +	bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const; +	 +	bool hasContents() const;										// True if the clipboard has pasteable objects +	bool isOnClipboard(const LLUUID& object) const;					// True if the input object uuid is on the clipboard -	void		copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	void		copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPasteString() const; -	const LLWString&	getPasteWString(LLUUID* source_id = NULL); - -	void		copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); -	BOOL		canPastePrimaryString() const; -	const LLWString&	getPastePrimaryWString(LLUUID* source_id = NULL);	 +	bool isCutMode() const { return mCutMode; } +	void setCutMode(bool mode) { mCutMode = mode; mGeneration++; }  private: -	LLUUID		mSourceID; -	LLWString	mString; +	std::vector<LLUUID> mObjects;		// Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) +	LLWString mString;					// The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable. +	bool mCutMode;						// This is a convenience flag for the viewer. +	int mGeneration;					// Incremented when the clipboard changes so that interested parties can check for changes on the clipboard.	  }; - -// Global singleton -extern LLClipboard gClipboard; - -  #endif  // LL_LLCLIPBOARD_H diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index a4d1854bc8..806d2ef3f6 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -525,15 +525,12 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)  	else  	{  		mButton->setRect(rect); -		mButton->setTabStop(TRUE); -		mButton->setHAlign(LLFontGL::LEFT);  		mButton->setLabel(mLabel.getString());  		if (mTextEntry)  		{  			mTextEntry->setVisible(FALSE);  		} -		mButton->setFollowsAll();  	}  } @@ -616,7 +613,7 @@ void LLComboBox::showList()  	}  	mList->setOrigin(rect.mLeft, rect.mBottom);  	mList->reshape(rect.getWidth(), rect.getHeight()); -	mList->translateIntoRect(root_view_local, FALSE); +	mList->translateIntoRect(root_view_local);  	// Make sure we didn't go off bottom of screen  	S32 x, y; @@ -791,8 +788,10 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)  			return FALSE;  		}  		// if selection has changed, pop open list -		else if (mList->getLastSelectedItem() != last_selected_item || -				(key == KEY_DOWN || key == KEY_UP) && !mList->isEmpty()) +		else if (mList->getLastSelectedItem() != last_selected_item  +					|| ((key == KEY_DOWN || key == KEY_UP) +						&& mList->getCanSelect() +						&& !mList->isEmpty()))  		{  			showList();  		} 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/llconsole.cpp b/indra/llui/llconsole.cpp index 04040200d0..161496b1f5 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -372,9 +372,7 @@ LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_t  // static  void LLConsole::updateClass()  {	 -	LLInstanceTrackerScopedGuard guard; - -	for (instance_iter it = guard.beginInstances(); it != guard.endInstances(); ++it) +	for (instance_iter it = beginInstances(); it != endInstances(); ++it)  	{  		it->update();  	}  diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h index bb8ea50bed..f32f1dd74c 100644 --- a/indra/llui/llconsole.h +++ b/indra/llui/llconsole.h @@ -54,7 +54,7 @@ public:  			persist_time("persist_time", 0.f), // forever  			font_size_index("font_size_index")  		{ -			mouse_opaque(false); +			changeDefault(mouse_opaque, false);  		}  	};  protected: diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h index 7d3d5cf787..e81600fd6c 100644 --- a/indra/llui/llcontainerview.h +++ b/indra/llui/llcontainerview.h @@ -50,7 +50,7 @@ public:  			  show_label("show_label", FALSE),  			  display_children("display_children", TRUE)  		{ -			mouse_opaque(false); +			changeDefault(mouse_opaque, false);  		}  	}; diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index ca2dc644a4..3396213f1c 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -82,7 +82,7 @@ BOOL LLDockableFloater::postBuild()  		mForceDocking = true;  	} -	mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); +	mDockTongue = LLUI::getUIImage("Flyout_Pointer");  	LLFloater::setDocked(true);  	return LLView::postBuild();  } @@ -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("Flyout_Left"); +		break; +	case LLDockControl::RIGHT: +		mDockTongue = LLUI::getUIImage("Flyout_Right"); +		break; +	default: +		mDockTongue = LLUI::getUIImage("Flyout_Pointer"); +		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/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 42e6c3c786..5f69c6af31 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -244,7 +244,7 @@ void LLDragHandleTop::reshapeTitleBox()  	const LLFontGL* font = LLFontGL::getFontSansSerif();  	S32 title_width = getRect().getWidth();  	title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); -	S32 title_height = llround(font->getLineHeight()); +	S32 title_height = font->getLineHeight();  	LLRect title_rect;  	title_rect.setLeftTopAndSize(   		LEFT_PAD,  diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h index 7c56475e75..e095e577b1 100644 --- a/indra/llui/lldraghandle.h +++ b/indra/llui/lldraghandle.h @@ -51,8 +51,8 @@ public:  			drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")),  			drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark"))  		{ -			mouse_opaque(true); -			follows.flags(FOLLOWS_ALL); +			changeDefault(mouse_opaque, true); +			changeDefault(follows.flags, FOLLOWS_ALL);  		}  	};  	void initFromParams(const Params&); diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index 710699fdc1..3a05bc05a1 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -42,12 +42,7 @@ class LLFilterEditor : public LLSearchEditor  {  public:  	struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params> -	{ -		Params() -		{ -			name = "filter_editor"; -		} -	}; +	{};  protected:  	LLFilterEditor(const Params&); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index d19e33ea55..a8a3a1f906 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -58,10 +58,23 @@  #include "llhelp.h"  #include "llmultifloater.h"  #include "llsdutil.h" +#include <boost/foreach.hpp> +  // use this to control "jumping" behavior when Ctrl-Tabbing  const S32 TABBED_FLOATER_OFFSET = 0; +namespace LLInitParam +{ +	void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() +	{ +		declare("relative",   LLFloaterEnums::POSITIONING_RELATIVE); +		declare("cascading",  LLFloaterEnums::POSITIONING_CASCADING); +		declare("centered",   LLFloaterEnums::POSITIONING_CENTERED); +		declare("specified",  LLFloaterEnums::POSITIONING_SPECIFIED); +	} +} +  std::string	LLFloater::sButtonNames[BUTTON_COUNT] =   {  	"llfloater_close_btn",		//BUTTON_CLOSE @@ -100,7 +113,6 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =  LLMultiFloater* LLFloater::sHostp = NULL;  BOOL			LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting -LLFloater::handle_map_t	LLFloater::sFloaterMap;  LLFloaterView* gFloaterView = NULL; @@ -154,7 +166,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 +176,8 @@ 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), +	positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),  	header_height("header_height", 0),  	legacy_header_height("legacy_header_height", 0),  	close_image("close_image"), @@ -180,9 +193,10 @@ LLFloater::Params::Params()  	dock_pressed_image("dock_pressed_image"),  	help_pressed_image("help_pressed_image"),  	open_callback("open_callback"), -	close_callback("close_callback") +	close_callback("close_callback"), +	follows("follows")  { -	visible = false; +	changeDefault(visible, false);  } @@ -226,13 +240,14 @@ 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), +	mPositioning(p.positioning),  	mMinWidth(p.min_width),  	mMinHeight(p.min_height),  	mHeaderHeight(p.header_height), @@ -251,7 +266,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)  	mMinimizeSignal(NULL)  //	mNotificationContext(NULL)  { -	mHandle.bind(this); +	mPosition.setFloater(*this);  //	mNotificationContext = new LLFloaterNotificationContext(getHandle());  	// Clicks stop here. @@ -306,9 +321,6 @@ void LLFloater::initFloater(const Params& p)  	// Floaters are created in the invisible state	  	setVisible(FALSE); -	// add self to handle->floater map -	sFloaterMap[mHandle] = this; -  	if (!getParent())  	{  		gFloaterView->addChild(this); @@ -459,15 +471,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);  	}  } @@ -506,8 +527,6 @@ LLFloater::~LLFloater()  	// correct, non-minimized positions.  	setMinimized( FALSE ); -	sFloaterMap.erase(mHandle); -  	delete mDragHandle;  	for (S32 i = 0; i < 4; i++)   	{ @@ -515,7 +534,6 @@ LLFloater::~LLFloater()  		delete mResizeHandle[i];  	} -	storeRectControl();  	setVisible(false); // We're not visible if we're destroyed  	storeVisibilityControl();  	storeDockStateControl(); @@ -525,10 +543,18 @@ LLFloater::~LLFloater()  void LLFloater::storeRectControl()  { -	if( mRectControl.size() > 1 ) +	if (!mRectControl.empty())  	{  		getControlGroup()->setRect( mRectControl, getRect() );  	} +	if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) +	{ +		getControlGroup()->setF32( mPosXControl, mPosition.mX ); +	} +	if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) +	{ +		getControlGroup()->setF32( mPosYControl, mPosition.mY ); +	}  }  void LLFloater::storeVisibilityControl() @@ -547,23 +573,6 @@ void LLFloater::storeDockStateControl()  	}  } -LLRect LLFloater::getSavedRect() const -{ -	LLRect rect; - -	if (mRectControl.size() > 1) -	{ -		rect = getControlGroup()->getRect(mRectControl); -	} - -	return rect; -} - -bool LLFloater::hasSavedRect() const -{ -	return !getSavedRect().isEmpty(); -} -  // static  std::string LLFloater::getControlName(const std::string& name, const LLSD& key)  { @@ -660,6 +669,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 +767,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(); +			}  		}  	}  } @@ -766,7 +788,6 @@ void LLFloater::closeFloater(bool app_quitting)  void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)  {  	LLPanel::reshape(width, height, called_from_parent); -	storeRectControl();  }  void LLFloater::releaseFocus() @@ -823,43 +844,153 @@ LLMultiFloater* LLFloater::getHost()  	return (LLMultiFloater*)mHostHandle.get();   } -void    LLFloater::applySavedVariables() +void LLFloater::applyControlsAndPosition(LLFloater* other)  { -	applyRectControl(); -	applyDockState(); +	if (!applyDockState()) +	{ +		if (!applyRectControl()) +		{ +			applyPositioning(other, true); +		} +	}  } -void LLFloater::applyRectControl() +bool LLFloater::applyRectControl()  { -	// first, center on screen if requested	 -	if (mOpenCentered) +	bool saved_rect = false; + +	LLRect screen_rect = calcScreenRect(); +	mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); +	 +	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(); +		mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;  	} - -	// override center if we have saved rect control -	if (mRectControl.size() > 1) +	else  	{ -		const LLRect& rect = getControlGroup()->getRect(mRectControl); -		if (rect.getWidth() > 0 && rect.getHeight() > 0) +		bool rect_specified = false; +		if (!mRectControl.empty())  		{ -			translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); -			if (mResizable) +			// If we have a saved rect, use it +			const LLRect& rect = getControlGroup()->getRect(mRectControl); +			if (rect.notEmpty()) saved_rect = true; +			if (saved_rect)  			{ -				reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); +				setOrigin(rect.mLeft, rect.mBottom); + +				if (mResizable) +				{ +					reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); +				} +				mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +				LLRect screen_rect = calcScreenRect(); +				mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); +				rect_specified = true;  			}  		} + +		LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl); +		LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl); +		if (x_control.notNull()  +			&& y_control.notNull() +			&& !x_control->isDefault() +			&& !y_control->isDefault()) +		{ +			mPosition.mX = x_control->getValue().asReal(); +			mPosition.mY = y_control->getValue().asReal(); +			mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +			applyRelativePosition(); + +			saved_rect = true; +		} + +		// remember updated position +		if (rect_specified) +		{ +			storeRectControl(); +		} +	} + +	if (saved_rect) +	{ +		// propagate any derived positioning data back to settings file +		storeRectControl();  	} + + +	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, bool on_open) +{ +	// Otherwise position according to the positioning code +	switch (mPositioning) +	{ +	case LLFloaterEnums::POSITIONING_CENTERED: +		center(); +		break; + +	case LLFloaterEnums::POSITIONING_SPECIFIED: +		break; + +	case LLFloaterEnums::POSITIONING_CASCADING: +		if (!on_open) +		{ +			applyRelativePosition(); +		} +		// fall through +	case LLFloaterEnums::POSITIONING_CASCADE_GROUP: +		if (on_open) +		{ +			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); +			} +			setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); +		} +		break; + +	case LLFloaterEnums::POSITIONING_RELATIVE: +		{ +			applyRelativePosition(); + +			break; +		} +	default: +		// Do nothing +		break; +	}  }  void LLFloater::applyTitle() @@ -936,7 +1067,9 @@ BOOL LLFloater::canSnapTo(const LLView* other_view)  	if (other_view != getParent())  	{  		const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);		 -		if (other_floaterp && other_floaterp->getSnapTarget() == getHandle() && mDependents.find(other_floaterp->getHandle()) != mDependents.end()) +		if (other_floaterp  +			&& other_floaterp->getSnapTarget() == getHandle()  +			&& mDependents.find(other_floaterp->getHandle()) != mDependents.end())  		{  			// this is a dependent that is already snapped to us, so don't snap back to it  			return FALSE; @@ -968,6 +1101,14 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)  	const LLRect old_rect = getRect();  	LLView::handleReshape(new_rect, by_user); +	if (by_user && !isMinimized()) +	{ +		storeRectControl(); +		mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +		LLRect screen_rect = calcScreenRect(); +		mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); +	} +  	// if not minimized, adjust all snapped dependents to new shape  	if (!isMinimized())  	{ @@ -1025,7 +1166,7 @@ void LLFloater::setMinimized(BOOL minimize)  	if (minimize == mMinimized) return; -	if(mMinimizeSignal) +	if (mMinimizeSignal)  	{  		(*mMinimizeSignal)(this, LLSD(minimize));  	} @@ -1057,10 +1198,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(); @@ -1147,6 +1284,7 @@ void LLFloater::setMinimized(BOOL minimize)  		// Reshape *after* setting mMinimized  		reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); +		applyPositioning(NULL, false);  	}  	make_ui_sound("UISndWindowClose"); @@ -1211,19 +1349,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)  { @@ -1311,7 +1439,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) @@ -1384,6 +1515,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); @@ -1489,6 +1621,13 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)  	{  		mDocked = docked;  		mButtonsEnabled[BUTTON_DOCK] = !mDocked; + +		if (mDocked) +		{ +			setMinimized(FALSE); +			mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; +		} +  		updateTitleButtons();  		storeDockStateControl(); @@ -1520,7 +1659,7 @@ void LLFloater::onClickTearOff(LLFloater* self)  		self->openFloater(self->getKey());  		// only force position for floaters that don't have that data saved -		if (self->mRectControl.size() <= 1) +		if (self->mRectControl.empty())  		{  			new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight());  			self->setRect(new_rect); @@ -1572,18 +1711,19 @@ void LLFloater::onClickHelp( LLFloater* self )  LLFloater* LLFloater::getClosableFloaterFromFocus()  {  	LLFloater* focused_floater = NULL; - -	handle_map_iter_t iter; -	for(iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter) +	LLInstanceTracker<LLFloater>::instance_iter it = beginInstances(); +	LLInstanceTracker<LLFloater>::instance_iter end_it = endInstances(); +	for (; it != end_it; ++it)  	{ -		focused_floater = iter->second; -		if (focused_floater->hasFocus()) +		if (it->hasFocus())  		{ +			LLFloater& floater = *it; +			focused_floater = &floater;  			break;  		}  	} -	if (iter == sFloaterMap.end()) +	if (it == endInstances())  	{  		// nothing found, return  		return NULL; @@ -1698,7 +1838,7 @@ void LLFloater::draw()  				const LLFontGL* font = LLFontGL::getFontSansSerif();  				LLRect r = getRect(); -				gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,  +				gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1,   					titlebar_focus_color % alpha, 0, TRUE);  			}  		} @@ -1727,7 +1867,7 @@ void LLFloater::draw()  		{  			drawChild(mButtons[i]);  		} -		drawChild(mDragHandle); +		drawChild(mDragHandle, 0, 0, TRUE);  	}  	else  	{ @@ -1844,6 +1984,12 @@ void LLFloater::setCanDrag(BOOL can_drag)  	}  } +bool LLFloater::getCanDrag() +{ +	return mDragHandle->getEnabled(); +} + +  void LLFloater::updateTitleButtons()  {  	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); @@ -2048,25 +2194,20 @@ static LLDefaultChildRegistry::Register<LLFloaterView> r("floater_view");  LLFloaterView::LLFloaterView (const Params& p)  :	LLUICtrl (p), -  	mFocusCycleMode(FALSE),  	mMinimizePositionVOffset(0),  	mSnapOffsetBottom(0),  	mSnapOffsetRight(0)  { +	mSnapView = getHandle();  }  // By default, adjust vertical.  void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)  { -	reshapeFloater(width, height, called_from_parent, ADJUST_VERTICAL_YES); -} +	LLView::reshape(width, height, called_from_parent); -// When reshaping this view, make the floaters follow their closest edge. -void LLFloaterView::reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical) -{ -	S32 old_width = getRect().getWidth(); -	S32 old_height = getRect().getHeight(); +	mLastSnapRect = getSnapRect();  	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)  	{ @@ -2074,70 +2215,52 @@ void LLFloaterView::reshapeFloater(S32 width, S32 height, BOOL called_from_paren  		LLFloater* floaterp = (LLFloater*)viewp;  		if (floaterp->isDependent())  		{ -			// dependents use same follow flags as their "dependee" +			// dependents are moved with their "dependee"  			continue;  		} -		// Make if follow the edge it is closest to -		U32 follow_flags = 0x0; - -		if (floaterp->isMinimized()) +		if (!floaterp->isMinimized() && floaterp->getCanDrag())  		{ -			follow_flags |= (FOLLOWS_LEFT | FOLLOWS_TOP); -		} -		else -		{ -			LLRect r = floaterp->getRect(); +			LLRect old_rect = floaterp->getRect(); +			floaterp->applyPositioning(NULL, false); +			LLRect new_rect = floaterp->getRect(); -			// Compute absolute distance from each edge of screen -			S32 left_offset = llabs(r.mLeft - 0); -			S32 right_offset = llabs(old_width - r.mRight); +			//LLRect r = floaterp->getRect(); -			S32 top_offset = llabs(old_height - r.mTop); -			S32 bottom_offset = llabs(r.mBottom - 0); +			//// Compute absolute distance from each edge of screen +			//S32 left_offset = llabs(r.mLeft - 0); +			//S32 right_offset = llabs(old_right - r.mRight); +			//S32 top_offset = llabs(old_top - r.mTop); +			//S32 bottom_offset = llabs(r.mBottom - 0); -			if (left_offset < right_offset) -			{ -				follow_flags |= FOLLOWS_LEFT; -			} -			else -			{ -				follow_flags |= FOLLOWS_RIGHT; -			} +			S32 translate_x = new_rect.mLeft - old_rect.mLeft; +			S32 translate_y = new_rect.mBottom - old_rect.mBottom; -			// "No vertical adjustment" usually means that the bottom of the view -			// has been pushed up or down.  Hence we want the floaters to follow -			// the top. -			if (!adjust_vertical) -			{ -				follow_flags |= FOLLOWS_TOP; -			} -			else if (top_offset < bottom_offset) -			{ -				follow_flags |= FOLLOWS_TOP; -			} -			else -			{ -				follow_flags |= FOLLOWS_BOTTOM; -			} -		} +			//if (left_offset > right_offset) +			//{ +			//	translate_x = new_right - old_right; +			//} -		floaterp->setFollows(follow_flags); +			//if (top_offset < bottom_offset) +			//{ +			//	translate_y = new_top - old_top; +			//} -		//RN: all dependent floaters copy follow behavior of "parent" -		for(LLFloater::handle_set_iter_t dependent_it = floaterp->mDependents.begin(); -			dependent_it != floaterp->mDependents.end(); ++dependent_it) -		{ -			LLFloater* dependent_floaterp = dependent_it->get(); -			if (dependent_floaterp) +			// don't reposition immovable floaters +			//if (floaterp->getCanDrag()) +			//{ +			//	floaterp->translate(translate_x, translate_y); +			//} +			BOOST_FOREACH(LLHandle<LLFloater> dependent_floater, floaterp->mDependents)  			{ -				dependent_floaterp->setFollows(follow_flags); +				if (dependent_floater.get()) +				{ +					dependent_floater.get()->translate(translate_x, translate_y); +				}  			}  		}  	} - -	LLView::reshape(width, height, called_from_parent);  } @@ -2458,6 +2581,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()  { @@ -2491,6 +2660,12 @@ void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset)  void LLFloaterView::refresh()  { +	LLRect snap_rect = getSnapRect(); +	if (snap_rect != mLastSnapRect) +	{ +		reshape(getRect().getWidth(), getRect().getHeight(), TRUE); +	} +  	// Constrain children to be entirely on the screen  	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)  	{ @@ -2503,6 +2678,8 @@ void LLFloaterView::refresh()  	}  } +const S32 FLOATER_MIN_VISIBLE_PIXELS = 16; +  void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside)  {  	if (floater->getParent() != this) @@ -2556,7 +2733,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_MIN_VISIBLE_PIXELS : S32_MAX ))  	{  		floater->clearSnapTarget();  	} @@ -2770,9 +2947,11 @@ void LLFloater::setInstanceName(const std::string& name)  		std::string ctrl_name = getControlName(mInstanceName, mKey);  		// save_rect and save_visibility only apply to registered floaters -		if (!mRectControl.empty()) +		if (mSaveRect)  		{  			mRectControl = LLFloaterReg::declareRectControl(ctrl_name); +			mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name); +			mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);  		}  		if (!mVisibilityControl.empty())  		{ @@ -2782,7 +2961,6 @@ void LLFloater::setInstanceName(const std::string& name)  		{  			mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);  		} -  	}  } @@ -2829,6 +3007,12 @@ void LLFloater::initFromParams(const LLFloater::Params& p)  	 // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible  	LLPanel::initFromParams(p); +	// override any follows flags +	if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED) +	{ +		setFollows(FOLLOWS_NONE); +	} +  	mTitle = p.title;  	mShortTitle = p.short_title;  	applyTitle(); @@ -2844,18 +3028,15 @@ 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; -	if (p.save_rect) -	{ -		mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set -	} +	mPositioning = p.positioning; + +	mSaveRect = p.save_rect;  	if (p.save_visibility)  	{  		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 @@ -2864,13 +3045,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 )  @@ -2879,19 +3065,67 @@ 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);  }  LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); +static LLFastTimer::DeclareTimer FTM_EXTERNAL_FLOATER_LOAD("Load Extern Floater Reference");  bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)  { -	Params params(LLUICtrlFactory::getDefaultParams<LLFloater>()); +	Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>()); +	Params params(default_params); +  	LLXUIParser parser;  	parser.readXUI(node, params, filename); // *TODO: Error checking +	std::string xml_filename = params.filename; + +	if (!xml_filename.empty()) +	{ +		LLXMLNodePtr referenced_xml; + +		if (output_node) +		{ +			//if we are exporting, we want to export the current xml +			//not the referenced xml +			Params output_params; +			parser.readXUI(node, output_params, LLUICtrlFactory::getInstance()->getCurFileName()); +			setupParamsForExport(output_params, parent); +			output_node->setName(node->getName()->mString); +			parser.writeXUI(output_node, output_params, &default_params); +			return TRUE; +		} + +		LLUICtrlFactory::instance().pushFileName(xml_filename); + +		LLFastTimer _(FTM_EXTERNAL_FLOATER_LOAD); +		if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) +		{ +			llwarns << "Couldn't parse panel from: " << xml_filename << llendl; + +			return FALSE; +		} + +		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); +		LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); + +		LLUICtrlFactory::instance().popFileName(); +	} + +  	if (output_node)  	{  		Params output_params(params); @@ -2912,9 +3146,8 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str  	{  		params.rect.left.set(0);  	} -  	params.from_xui = true; -	applyXUILayout(params, parent); +	applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect());   	initFromParams(params);  	initFloater(params); @@ -3054,3 +3287,156 @@ bool LLFloater::buildFromFile(const std::string& filename, LLXMLNodePtr output_n  	return res;  } + +void LLFloater::stackWith(LLFloater& other) +{ +	static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16); + +	LLRect next_rect; +	if (other.getHost()) +	{ +		next_rect = other.getHost()->getRect(); +	} +	else +	{ +		next_rect = other.getRect(); +	} +	next_rect.translate(floater_offset, -floater_offset); + +	next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); +	 +	setShape(next_rect); + +	other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; +	other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); +} + +void LLFloater::applyRelativePosition() +{ +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); +	LLRect floater_screen_rect = calcScreenRect(); + +	LLCoordGL new_center = mPosition.convert(); +	LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY()); +	translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); +} + + +LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) +:	coord_t((S32)x, (S32)y) +{ +	mFloater = floater.getHandle(); +} + + +LLCoordFloater::LLCoordFloater(const LLCoordCommon& other, LLFloater& floater) +{ +	mFloater = floater.getHandle(); +	convertFromCommon(other); +} + +LLCoordFloater& LLCoordFloater::operator=(const LLCoordFloater& other) +{ +	mFloater = other.mFloater; +	coord_t::operator =(other); +	return *this; +} + +void LLCoordFloater::setFloater(LLFloater& floater) +{ +	mFloater = floater.getHandle(); +} + +bool LLCoordFloater::operator==(const LLCoordFloater& other) const  +{  +	return mX == other.mX && mY == other.mY && mFloater == other.mFloater;  +} + +LLCoordCommon LL_COORD_FLOATER::convertToCommon() const +{ +	const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); + +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + +	LLFloater* floaterp = mFloater.get(); +	S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; +	S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; +	LLCoordCommon out; +	if (self.mX < -0.5f) +	{ +		out.mX = llround(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft)); +	} +	else if (self.mX > 0.5f) +	{ +		out.mX = llround(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS)); +	} +	else +	{ +		out.mX = llround(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width)); +	} + +	if (self.mY < -0.5f) +	{ +		out.mY = llround(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom)); +	} +	else if (self.mY > 0.5f) +	{ +		out.mY = llround(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS)); +	} +	else +	{ +		out.mY = llround(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height)); +	} + +	// return center point instead of lower left +	out.mX += floater_width / 2; +	out.mY += floater_height / 2; + +	return out; +} + +void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from) +{ +	LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); +	LLRect snap_rect = gFloaterView->getSnapRect(); +	LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); +	snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + + +	LLFloater* floaterp = mFloater.get(); +	S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; +	S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; + +	S32 from_x = from.mX - floater_width / 2; +	S32 from_y = from.mY - floater_height / 2; + +	if (from_x < snap_rect.mLeft) +	{ +		self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f); +	} +	else if (from_x + floater_width > snap_rect.mRight) +	{ +		self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); +	} +	else +	{ +		self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f); +	} + +	if (from_y < snap_rect.mBottom) +	{ +		self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f); +	} +	else if (from_y + floater_height > snap_rect.mTop) +	{ +		self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); +	} +	else +	{ +		self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f); +	} +} diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 5b7b020881..64d6dcea04 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,66 @@ const BOOL CLOSE_NO = FALSE;  const BOOL ADJUST_VERTICAL_YES = TRUE;  const BOOL ADJUST_VERTICAL_NO = FALSE; -class LLFloater : public LLPanel +namespace LLFloaterEnums  { -friend class LLFloaterView; -friend class LLFloaterReg; -friend class LLMultiFloater; +	enum EOpenPositioning +	{ +		POSITIONING_RELATIVE, +		POSITIONING_CASCADING, +		POSITIONING_CASCADE_GROUP, +		POSITIONING_CENTERED, +		POSITIONING_SPECIFIED, +		POSITIONING_COUNT +	}; +} + +namespace LLInitParam +{ +	template<> +	struct TypeValues<LLFloaterEnums::EOpenPositioning> : public TypeValuesHelper<LLFloaterEnums::EOpenPositioning> +	{ +		static void declareValues(); +	}; +} + +struct LL_COORD_FLOATER +{ +	typedef F32 value_t; + +	LLCoordCommon convertToCommon() const; +	void convertFromCommon(const LLCoordCommon& from); +protected: +	LLHandle<LLFloater> mFloater; +}; + +struct LLCoordFloater : LLCoord<LL_COORD_FLOATER> +{ +	typedef LLCoord<LL_COORD_FLOATER> coord_t; + +	LLCoordFloater() {} +	LLCoordFloater(F32 x, F32 y, LLFloater& floater); +	LLCoordFloater(const LLCoordCommon& other, LLFloater& floater); + +	LLCoordFloater& operator=(const LLCoordCommon& other) +	{ +		convertFromCommon(other); +		return *this; +	} + +	LLCoordFloater& operator=(const LLCoordFloater& other); + +	bool operator==(const LLCoordFloater& other) const; +	bool operator!=(const LLCoordFloater& other) const { return !(*this == other); } + +	void setFloater(LLFloater& floater); +}; + +class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater> +{ +	friend class LLFloaterView; +	friend class LLFloaterReg; +	friend class LLMultiFloater; +  public:  	struct KeyCompare  	{ @@ -95,7 +151,7 @@ public:  								short_title;  		Optional<bool>			single_instance, -								auto_tile, +								reuse_instance,  								can_resize,  								can_minimize,  								can_close, @@ -105,7 +161,10 @@ public:  								save_visibility,  								save_dock_state,  								can_dock, -								open_centered; +								show_title; +		 +		Optional<LLFloaterEnums::EOpenPositioning>	positioning; +		  		Optional<S32>			header_height,  								legacy_header_height; // HACK see initFromXML() @@ -125,6 +184,8 @@ public:  		Optional<CommitCallbackParam> open_callback,  									  close_callback; + +		Ignored					follows;  		Params();  	}; @@ -144,13 +205,14 @@ 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);  	bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);  	/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); -	/*virtual*/ BOOL canSnapTo(const LLView* other_view); +	/*virtual*/ BOOL canSnapTo(const LLView* other_view);   	/*virtual*/ void setSnappedTo(const LLView* snap_view);  	/*virtual*/ void setFocus( BOOL b );  	/*virtual*/ void setIsChrome(BOOL is_chrome); @@ -179,7 +241,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); @@ -203,12 +264,11 @@ public:  	void			setCanTearOff(BOOL can_tear_off);  	virtual void	setCanResize(BOOL can_resize);  	void			setCanDrag(BOOL can_drag); +	bool			getCanDrag();  	void			setHost(LLMultiFloater* host);  	BOOL			isResizable() const				{ return mResizable; }  	void			setResizeLimits( S32 min_width, S32 min_height );  	void			getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } -	LLRect			getSavedRect() const; -	bool			hasSavedRect() const;  	static std::string		getControlName(const std::string& name, const LLSD& key);  	static LLControlGroup*	getControlGroup(); @@ -251,9 +311,9 @@ public:  	void			clearSnapTarget() { mSnappedTo.markDead(); }  	LLHandle<LLFloater>	getSnapTarget() const { return mSnappedTo; } -	LLHandle<LLFloater> getHandle() const { return mHandle; } +	LLHandle<LLFloater> getHandle() const { return getDerivedHandle<LLFloater>(); }  	const LLSD& 	getKey() { return mKey; } -	BOOL		 	matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); } +	virtual bool	matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); }  	const std::string& getInstanceName() { return mInstanceName; } @@ -288,14 +348,19 @@ public:  	void			updateTransparency(ETypeTransparency transparency_type); +	void			enableResizeCtrls(bool enable, bool width = true, bool height = true); + +	bool			isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); }  protected: +	void			applyControlsAndPosition(LLFloater* other); -	void			setRectControl(const std::string& rectname) { mRectControl = rectname; }; +	void			stackWith(LLFloater& other); -	virtual void    applySavedVariables(); +	virtual bool	applyRectControl(); +	bool			applyDockState(); +	void			applyPositioning(LLFloater* other, bool on_open); +	void			applyRelativePosition(); -	void			applyRectControl(); -	void			applyDockState();  	void			storeRectControl();  	void			storeVisibilityControl();  	void			storeDockStateControl(); @@ -340,7 +405,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 @@ -360,7 +424,10 @@ public:  	commit_signal_t* mMinimizeSignal;  protected: +	bool			mSaveRect;  	std::string		mRectControl; +	std::string		mPosXControl; +	std::string		mPosYControl;  	std::string		mVisibilityControl;  	std::string		mDocStateControl;  	LLSD			mKey;				// Key used for retrieving instances; set (for now) by LLFLoaterReg @@ -377,15 +444,17 @@ 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	mPositioning; +	LLCoordFloater	mPosition;  	S32				mMinWidth;  	S32				mMinHeight; @@ -424,18 +493,9 @@ private:  	typedef void(*click_callback)(LLFloater*);  	static click_callback sButtonCallbacks[BUTTON_COUNT]; -	typedef std::map<LLHandle<LLFloater>, LLFloater*> handle_map_t; -	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; - -//	LLFloaterNotificationContext* mNotificationContext; -	LLRootHandle<LLFloater>		mHandle;	  }; @@ -455,8 +515,6 @@ protected:  public:  	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); -	void reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical); -  	/*virtual*/ void draw();  	/*virtual*/ LLRect getSnapRect() const;  	/*virtual*/ void refresh(); @@ -485,6 +543,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; @@ -499,11 +561,16 @@ public:  	void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; }  private: +	void hiddenFloaterClosed(LLFloater* floater); + +	LLRect				mLastSnapRect;  	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 4677d535db..9115eb7174 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -57,29 +57,59 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con  }  //static -LLRect LLFloaterReg::getFloaterRect(const std::string& name) +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())  		{ -			static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16); -			LLFloater* last_floater = list.back(); -			if (last_floater->getHost()) +			for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter)  			{ -				rect = last_floater->getHost()->getRect(); +				LLFloater* inst = *iter; + +				if (inst->getVisible() && !inst->isMinimized()) +				{ +					return inst; +				}  			} -			else +		} +	} +	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::POSITIONING_CASCADING) +					|| inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADE_GROUP)))  			{ -				rect = last_floater->getRect(); +				if (candidate_rect.mTop > inst->getRect().mTop) +				{ +					candidate_floater = inst; +					candidate_rect = inst->getRect(); +				}  			} -			rect.translate(floater_offset, -floater_offset);  		}  	} -	return rect; + +	return candidate_floater;  }  //static @@ -117,34 +147,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 -				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) +				if (res->mKey.isUndefined())   				{ -					const LLRect& cur_rect = res->getRect(); -					LLRect next_rect = getFloaterRect(groupname); -					next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, cur_rect.getWidth(), cur_rect.getHeight()); -					res->setRect(next_rect); -					res->setRectControl(LLStringUtil::null); // don't save rect of tiled floaters -					gFloaterView->adjustToFitScreen(res, true); -				} -				else -				{ -					gFloaterView->adjustToFitScreen(res, false); +					res->mKey = key;  				} +				res->setInstanceName(name); + +				LLFloater *last_floater = (list.empty() ? NULL : list.back()); + +				res->applyControlsAndPosition(last_floater); + +				gFloaterView->adjustToFitScreen(res, false); +  				list.push_back(res);  			}  		} @@ -331,9 +360,7 @@ void LLFloaterReg::restoreVisibleInstances()  //static  std::string LLFloaterReg::getRectControlName(const std::string& name)  { -	std::string res = std::string("floater_rect_") + name; -	LLStringUtil::replaceChar( res, ' ', '_' ); -	return res; +	return std::string("floater_rect_") + getBaseControlName(name);  }  //static @@ -341,19 +368,48 @@ std::string LLFloaterReg::declareRectControl(const std::string& name)  {  	std::string controlname = getRectControlName(name);  	LLFloater::getControlGroup()->declareRect(controlname, LLRect(), -												 llformat("Window Position and Size for %s", name.c_str()), +												 llformat("Window Size for %s", name.c_str()),  												 TRUE);  	return controlname;  } +std::string LLFloaterReg::declarePosXControl(const std::string& name) +{ +	std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_x"; +	LLFloater::getControlGroup()->declareF32(controlname,  +											10.f, +											llformat("Window X Position for %s", name.c_str()), +											TRUE); +	return controlname; +} + +std::string LLFloaterReg::declarePosYControl(const std::string& name) +{ +	std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_y"; +	LLFloater::getControlGroup()->declareF32(controlname, +											10.f, +											llformat("Window Y Position for %s", name.c_str()), +											TRUE); + +	return controlname; +} + +  //static  std::string LLFloaterReg::getVisibilityControlName(const std::string& name)  { -	std::string res = std::string("floater_vis_") + name; +	return std::string("floater_vis_") + getBaseControlName(name); +} + +//static  +std::string LLFloaterReg::getBaseControlName(const std::string& name) +{ +	std::string res(name);  	LLStringUtil::replaceChar( res, ' ', '_' );  	return res;  } +  //static  std::string LLFloaterReg::declareVisibilityControl(const std::string& name)  { @@ -410,70 +466,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 8414b92113..a1e1f8a988 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -86,7 +86,8 @@ public:  					const std::string& groupname = LLStringUtil::null);  	// Helpers -	static LLRect getFloaterRect(const std::string& name); +	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()); @@ -114,21 +115,18 @@ public:  	// Control Variables  	static std::string getRectControlName(const std::string& name);  	static std::string declareRectControl(const std::string& name); +	static std::string declarePosXControl(const std::string& name); +	static std::string declarePosYControl(const std::string& name);  	static std::string getVisibilityControlName(const std::string& name);  	static std::string declareVisibilityControl(const std::string& name); - +	static std::string getBaseControlName(const std::string& name);  	static std::string declareDockStateControl(const std::string& name);  	static std::string getDockStateControlName(const std::string& name);  	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 +149,7 @@ public:  	static void blockShowFloaters(bool value) { sBlockShowFloaters = value;} +	static U32 getVisibleFloaterInstanceCount();  };  #endif diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h index 8d59380a00..36998eba2e 100644 --- a/indra/llui/llflyoutbutton.h +++ b/indra/llui/llflyoutbutton.h @@ -46,7 +46,7 @@ public:  		:	action_button("action_button"),  		    allow_text_entry("allow_text_entry")  		{ -			LLComboBox::Params::allow_text_entry = false; +			changeDefault(LLComboBox::Params::allow_text_entry, false);  		}  	}; diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 752c7df7ee..899cc3a326 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -103,7 +103,7 @@ public:  		}  		else  		{ -			llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl; +			lldebugs << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl;  			return mMap[LOGFUNCTOR];  		}  	} @@ -115,7 +115,7 @@ private:  	static void log_functor(const LLSD& notification, const LLSD& payload)  	{ -		llwarns << "log_functor called with payload: " << payload << llendl; +		lldebugs << "log_functor called with payload: " << payload << llendl;  	}  	static void do_nothing(const LLSD& notification, const LLSD& payload) diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h index 8c000eee48..37c657dd92 100644 --- a/indra/llui/llhandle.h +++ b/indra/llui/llhandle.h @@ -28,17 +28,18 @@  #define LLHANDLE_H  #include "llpointer.h" +#include <boost/type_traits/is_convertible.hpp> +#include <boost/utility/enable_if.hpp> -template <typename T>  class LLTombStone : public LLRefCount  {  public: -	LLTombStone(T* target = NULL) : mTarget(target) {} +	LLTombStone(void* target = NULL) : mTarget(target) {} -	void setTarget(T* target) { mTarget = target; } -	T* getTarget() const { return mTarget; } +	void setTarget(void* target) { mTarget = target; } +	void* getTarget() const { return mTarget; }  private: -	T* mTarget; +	mutable void* mTarget;  };  //	LLHandles are used to refer to objects whose lifetime you do not control or influence.   @@ -53,13 +54,15 @@ private:  template <typename T>  class LLHandle  { +	template <typename U> friend class LLHandle; +	template <typename U> friend class LLHandleProvider;  public:  	LLHandle() : mTombStone(getDefaultTombStone()) {} -	const LLHandle<T>& operator =(const LLHandle<T>& other)   -	{  -		mTombStone = other.mTombStone; -		return *this;  -	} + +	template<typename U> +	LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) +	: mTombStone(other.mTombStone) +	{}  	bool isDead() const   	{  @@ -73,7 +76,7 @@ public:  	T* get() const  	{ -		return mTombStone->getTarget(); +		return reinterpret_cast<T*>(mTombStone->getTarget());  	}  	friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs) @@ -94,12 +97,13 @@ public:  	}  protected: -	LLPointer<LLTombStone<T> > mTombStone; +	LLPointer<LLTombStone> mTombStone;  private: -	static LLPointer<LLTombStone<T> >& getDefaultTombStone() +	typedef T* pointer_t; +	static LLPointer<LLTombStone>& getDefaultTombStone()  	{ -		static LLPointer<LLTombStone<T> > sDefaultTombStone = new LLTombStone<T>; +		static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone;  		return sDefaultTombStone;  	}  }; @@ -108,23 +112,26 @@ template <typename T>  class LLRootHandle : public LLHandle<T>  {  public: +	typedef LLRootHandle<T> self_t; +	typedef LLHandle<T> base_t; +  	LLRootHandle(T* object) { bind(object); }  	LLRootHandle() {};  	~LLRootHandle() { unbind(); } -	// this is redundant, since a LLRootHandle *is* an LLHandle -	LLHandle<T> getHandle() { return LLHandle<T>(*this); } +	// this is redundant, since an LLRootHandle *is* an LLHandle +	//LLHandle<T> getHandle() { return LLHandle<T>(*this); }  	void bind(T* object)   	{   		// unbind existing tombstone  		if (LLHandle<T>::mTombStone.notNull())  		{ -			if (LLHandle<T>::mTombStone->getTarget() == object) return; +			if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return;  			LLHandle<T>::mTombStone->setTarget(NULL);  		}  		// tombstone reference counted, so no paired delete -		LLHandle<T>::mTombStone = new LLTombStone<T>(object); +		LLHandle<T>::mTombStone = new LLTombStone((void*)object);  	}  	void unbind()  @@ -142,6 +149,15 @@ private:  template <typename T>  class LLHandleProvider  { +public: +	LLHandle<T> getHandle() const +	{  +		// perform lazy binding to avoid small tombstone allocations for handle +		// providers whose handles are never referenced +		mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this)));  +		return mHandle;  +	} +  protected:  	typedef LLHandle<T> handle_type_t;  	LLHandleProvider()  @@ -149,16 +165,17 @@ protected:  		// provided here to enforce T deriving from LLHandleProvider<T>  	}  -	LLHandle<T> getHandle()  -	{  -		// perform lazy binding to avoid small tombstone allocations for handle -		// providers whose handles are never referenced -		mHandle.bind(static_cast<T*>(this));  -		return mHandle;  +	template <typename U> +	LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const +	{ +		LLHandle<U> downcast_handle; +		downcast_handle.mTombStone = getHandle().mTombStone; +		return downcast_handle;  	} +  private: -	LLRootHandle<T> mHandle; +	mutable LLRootHandle<T> mHandle;  };  #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/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 47f2cfaf89..30b79b4d20 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -43,10 +43,7 @@ LLIconCtrl::Params::Params()  	color("color"),  	use_draw_context_alpha("use_draw_context_alpha", true),  	scale_image("scale_image") -{ -	tab_stop = false; -	mouse_opaque = false; -} +{}  LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)  :	LLUICtrl(p), diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index ceec9c7eb1..c1cd04186b 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -57,6 +57,22 @@ LLKeywords::LLKeywords() : mLoaded(FALSE)  {  } +inline BOOL LLKeywordToken::isTail(const llwchar* s) const +{ +	BOOL res = TRUE; +	const llwchar* t = mDelimiter.c_str(); +	S32 len = mDelimiter.size(); +	for (S32 i=0; i<len; i++) +	{ +		if (s[i] != t[i]) +		{ +			res = FALSE; +			break; +		} +	} +	return res; +} +  LLKeywords::~LLKeywords()  {  	std::for_each(mWordTokenMap.begin(), mWordTokenMap.end(), DeletePairedPointer()); @@ -106,6 +122,7 @@ BOOL LLKeywords::loadFromFile( const std::string& filename )  	std::string SOL_LINE("[line ");  	std::string SOL_ONE_SIDED_DELIMITER("[one_sided_delimiter ");  	std::string SOL_TWO_SIDED_DELIMITER("[two_sided_delimiter "); +	std::string SOL_DOUBLE_QUOTATION_MARKS("[double_quotation_marks ");  	LLColor3 cur_color( 1, 0, 0 );  	LLKeywordToken::TOKEN_TYPE cur_type = LLKeywordToken::WORD; @@ -137,6 +154,12 @@ BOOL LLKeywords::loadFromFile( const std::string& filename )  			cur_type = LLKeywordToken::TWO_SIDED_DELIMITER;  			continue;  		} +		else if( line.find(SOL_DOUBLE_QUOTATION_MARKS) == 0 ) +		{ +			cur_color = readColor( line.substr(SOL_DOUBLE_QUOTATION_MARKS.size()) ); +			cur_type = LLKeywordToken::DOUBLE_QUOTATION_MARKS; +			continue; +		}  		else if( line.find(SOL_ONE_SIDED_DELIMITER) == 0 )	  		{  			cur_color = readColor( line.substr(SOL_ONE_SIDED_DELIMITER.size()) ); @@ -154,10 +177,26 @@ BOOL LLKeywords::loadFromFile( const std::string& filename )  		if( !token_buffer.empty() && token_word_iter != word_tokens.end() )  		{ -			// first word is keyword +			// first word is the keyword or a left delimiter  			std::string keyword = (*token_word_iter);  			LLStringUtil::trim(keyword); +			// second word may be a right delimiter +			std::string delimiter; +			if (cur_type == LLKeywordToken::TWO_SIDED_DELIMITER) +			{ +				while (delimiter.length() == 0 && ++token_word_iter != word_tokens.end()) +				{ +					delimiter = *token_word_iter; +					LLStringUtil::trim(delimiter); +				} +			} +			else if (cur_type == LLKeywordToken::DOUBLE_QUOTATION_MARKS) +			{ +				// Closing delimiter is identical to the opening one. +				delimiter = keyword; +			} +  			// following words are tooltip  			std::string tool_tip;  			while (++token_word_iter != word_tokens.end()) @@ -170,11 +209,11 @@ BOOL LLKeywords::loadFromFile( const std::string& filename )  			{  				// Replace : with \n for multi-line tool tips.  				LLStringUtil::replaceChar( tool_tip, ':', '\n' ); -				addToken(cur_type, keyword, cur_color, tool_tip ); +				addToken(cur_type, keyword, cur_color, tool_tip, delimiter );  			}  			else  			{ -				addToken(cur_type, keyword, cur_color, LLStringUtil::null ); +				addToken(cur_type, keyword, cur_color, LLStringUtil::null, delimiter );  			}  		}  	} @@ -189,23 +228,26 @@ BOOL LLKeywords::loadFromFile( const std::string& filename )  void LLKeywords::addToken(LLKeywordToken::TOKEN_TYPE type,  						  const std::string& key_in,  						  const LLColor3& color, -						  const std::string& tool_tip_in ) +						  const std::string& tool_tip_in, +						  const std::string& delimiter_in)  {  	LLWString key = utf8str_to_wstring(key_in);  	LLWString tool_tip = utf8str_to_wstring(tool_tip_in); +	LLWString delimiter = utf8str_to_wstring(delimiter_in);  	switch(type)  	{  	case LLKeywordToken::WORD: -		mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip); +		mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null);  		break;  	case LLKeywordToken::LINE: -		mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip)); +		mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null));  		break;  	case LLKeywordToken::TWO_SIDED_DELIMITER: +	case LLKeywordToken::DOUBLE_QUOTATION_MARKS:  	case LLKeywordToken::ONE_SIDED_DELIMITER: -		mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip)); +		mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, delimiter));  		break;  	default: @@ -357,7 +399,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW  			}  			// cur is now at the first non-whitespace character of a new line	 -		 +  			// Line start tokens  			{  				BOOL line_done = FALSE; @@ -418,14 +460,15 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW  					S32 seg_end = 0;  					seg_start = cur - base; -					cur += cur_delimiter->getLength(); +					cur += cur_delimiter->getLengthHead(); -					if( cur_delimiter->getType() == LLKeywordToken::TWO_SIDED_DELIMITER ) +					LLKeywordToken::TOKEN_TYPE type = cur_delimiter->getType(); +					if( type == LLKeywordToken::TWO_SIDED_DELIMITER || type == LLKeywordToken::DOUBLE_QUOTATION_MARKS )  					{ -						while( *cur && !cur_delimiter->isHead(cur)) +						while( *cur && !cur_delimiter->isTail(cur))  						{  							// Check for an escape sequence. -							if (*cur == '\\') +							if (type == LLKeywordToken::DOUBLE_QUOTATION_MARKS && *cur == '\\')  							{  								// Count the number of backslashes.  								S32 num_backslashes = 0; @@ -435,10 +478,10 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW  									between_delimiters++;  									cur++;  								} -								// Is the next character the end delimiter? -								if (cur_delimiter->isHead(cur)) +								// If the next character is the end delimiter? +								if (cur_delimiter->isTail(cur))  								{ -									// Is there was an odd number of backslashes, then this delimiter +									// If there was an odd number of backslashes, then this delimiter  									// does not end the sequence.  									if (num_backslashes % 2 == 1)  									{ @@ -461,13 +504,13 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW  						if( *cur )  						{ -							cur += cur_delimiter->getLength(); -							seg_end = seg_start + between_delimiters + 2 * cur_delimiter->getLength(); +							cur += cur_delimiter->getLengthHead(); +							seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead() + cur_delimiter->getLengthTail();  						}  						else  						{  							// eof -							seg_end = seg_start + between_delimiters + cur_delimiter->getLength(); +							seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();  						}  					}  					else @@ -479,7 +522,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW  							between_delimiters++;  							cur++;  						} -						seg_end = seg_start + between_delimiters + cur_delimiter->getLength(); +						seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();  					}  					insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, defaultColor, editor); diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index f6d75b7e75..ac34015393 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -41,23 +41,44 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr;  class LLKeywordToken  {  public: -	enum TOKEN_TYPE { WORD, LINE, TWO_SIDED_DELIMITER, ONE_SIDED_DELIMITER }; +	/**  +	 * @brief Types of tokens/delimters being parsed. +	 * +	 * @desc Tokens/delimiters that need to be identified/highlighted. All are terminated if an EOF is encountered. +	 * - WORD are keywords in the normal sense, i.e. constants, events, etc. +	 * - LINE are for entire lines (currently only flow control labels use this). +	 * - ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL. +	 * - TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with. +	 * - DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close. +	 */ +	enum TOKEN_TYPE +	{ +		WORD, +		LINE, +		TWO_SIDED_DELIMITER, +		ONE_SIDED_DELIMITER, +		DOUBLE_QUOTATION_MARKS +	}; -	LLKeywordToken( TOKEN_TYPE type, const LLColor3& color, const LLWString& token, const LLWString& tool_tip )  +	LLKeywordToken( TOKEN_TYPE type, const LLColor3& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter  )   		:  		mType( type ),  		mToken( token ),  		mColor( color ), -		mToolTip( tool_tip ) +		mToolTip( tool_tip ), +		mDelimiter( delimiter )		// right delimiter  	{  	} -	S32					getLength() const		{ return mToken.size(); } +	S32					getLengthHead() const	{ return mToken.size(); } +	S32					getLengthTail() const	{ return mDelimiter.size(); }  	BOOL				isHead(const llwchar* s) const; +	BOOL				isTail(const llwchar* s) const;  	const LLWString&	getToken() const		{ return mToken; }  	const LLColor3&		getColor() const		{ return mColor; }  	TOKEN_TYPE			getType()  const		{ return mType; }  	const LLWString&	getToolTip() const		{ return mToolTip; } +	const LLWString&	getDelimiter() const	{ return mDelimiter; }  #ifdef _DEBUG  	void		dump(); @@ -68,6 +89,7 @@ private:  	LLWString	mToken;  	LLColor3	mColor;  	LLWString	mToolTip; +	LLWString	mDelimiter;  };  class LLKeywords @@ -85,7 +107,8 @@ public:  	void addToken(LLKeywordToken::TOKEN_TYPE type,  					const std::string& key,  					const LLColor3& color, -					const std::string& tool_tip = LLStringUtil::null); +					const std::string& tool_tip = LLStringUtil::null, +					const std::string& delimiter = LLStringUtil::null);  	// This class is here as a performance optimization.  	// The word token map used to be defined as std::map<LLWString, LLKeywordToken*>. diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 6a91ec56e4..4c730286da 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -34,6 +34,10 @@  #include "llpanel.h"  #include "llresizebar.h"  #include "llcriticaldamp.h" +#include "boost/foreach.hpp" + +static const F32 MIN_FRACTIONAL_SIZE = 0.0f; +static const F32 MAX_FRACTIONAL_SIZE = 1.f;  static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");  static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel"); @@ -47,26 +51,31 @@ void LLLayoutStack::OrientationNames::declareValues()  //  // LLLayoutPanel  // +LLLayoutPanel::Params::Params()	 +:	expanded_min_dim("expanded_min_dim", 0), +	min_dim("min_dim", -1), +	user_resize("user_resize", false), +	auto_resize("auto_resize", true) +{ +	addSynonym(min_dim, "min_width"); +	addSynonym(min_dim, "min_height"); +} +  LLLayoutPanel::LLLayoutPanel(const Params& p)	  :	LLPanel(p), -	mExpandedMinDimSpecified(false), -	mExpandedMinDim(p.min_dim), +	mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim),   	mMinDim(p.min_dim),  - 	mMaxDim(p.max_dim),    	mAutoResize(p.auto_resize),   	mUserResize(p.user_resize),  	mCollapsed(FALSE),  	mCollapseAmt(0.f),  	mVisibleAmt(1.f), // default to fully visible -	mResizeBar(NULL)  +	mResizeBar(NULL), +	mFractionalSize(MIN_FRACTIONAL_SIZE), +	mTargetDim(0), +	mIgnoreReshape(false), +	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()) -	{ -		mExpandedMinDimSpecified = true; -		mExpandedMinDim = p.expanded_min_dim(); -	} -	  	// panels initialized as hidden should not start out partially visible  	if (!getVisible())  	{ @@ -88,20 +97,111 @@ LLLayoutPanel::~LLLayoutPanel()  	mResizeBar = NULL;  } -F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation) +F32 LLLayoutPanel::getAutoResizeFactor() const +{ +	return mVisibleAmt * (1.f - mCollapseAmt); +} +  +F32 LLLayoutPanel::getVisibleAmount() const +{ +	return mVisibleAmt; +} + +S32 LLLayoutPanel::getLayoutDim() const  { -	if (orientation == LLLayoutStack::HORIZONTAL) +	return llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) +					? getRect().getWidth() +					: getRect().getHeight())); +} + +S32 LLLayoutPanel::getTargetDim() const +{ +	return mTargetDim; +} + +void LLLayoutPanel::setTargetDim(S32 value) +{ +	LLRect new_rect(getRect()); +	if (mOrientation == LLLayoutStack::HORIZONTAL)  	{ -		F32 collapse_amt =  -			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth())); -		return mVisibleAmt * collapse_amt; +		new_rect.mRight = new_rect.mLeft + value;  	}  	else  	{ -		F32 collapse_amt =  -			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getHeight()))); -		return mVisibleAmt * collapse_amt; +		new_rect.mTop = new_rect.mBottom + value; +	} +	setShape(new_rect, true); +} + +S32 LLLayoutPanel::getVisibleDim() const +{ +	F32 min_dim = getRelevantMinDim(); +	return llround(mVisibleAmt +					* (min_dim +						+ (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt)))); +} +  +void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientation ) +{ +	mOrientation = orientation; +	S32 layout_dim = llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) +		? getRect().getWidth() +		: getRect().getHeight())); + +	if (mAutoResize == FALSE  +		&& mUserResize == TRUE  +		&& mMinDim == -1 ) +	{ +		setMinDim(layout_dim); +	} +	mTargetDim = llmax(layout_dim, getMinDim()); +} +  +void LLLayoutPanel::setVisible( BOOL visible ) +{ +	if (visible != getVisible()) +	{ +		LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); +		if (stackp) +		{ +			stackp->mNeedsLayout = true; +		} +	} +	LLPanel::setVisible(visible); +} + +void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ ) +{ +	if (width == getRect().getWidth() && height == getRect().getHeight()) return; + +	if (!mIgnoreReshape && mAutoResize == false) +	{ +		mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height; +		LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); +		if (stackp) +		{ +			stackp->mNeedsLayout = true; +		} +	} +	LLPanel::reshape(width, height, called_from_parent); +} + +void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user) +{ +	LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); +	if (stackp) +	{ +		if (by_user) +		{	// tell layout stack to account for new shape +			 +			// make sure that panels have already been auto resized +			stackp->updateLayout(); +			// now apply requested size to panel +			stackp->updatePanelRect(this, new_rect); +		} +		stackp->mNeedsLayout = true;  	} +	LLPanel::handleReshape(new_rect, by_user);  }  // @@ -114,22 +214,21 @@ LLLayoutStack::Params::Params()  	clip("clip", true),  	open_time_constant("open_time_constant", 0.02f),  	close_time_constant("close_time_constant", 0.03f), +	resize_bar_overlap("resize_bar_overlap", 1),  	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) -{ -	name="stack"; -} +{}  LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)   :	LLView(p), -	mMinWidth(0), -	mMinHeight(0),  	mPanelSpacing(p.border_size),  	mOrientation(p.orientation),  	mAnimate(p.animate),  	mAnimatedThisFrame(false), +	mNeedsLayout(true),  	mClip(p.clip),  	mOpenTimeConstant(p.open_time_constant), -	mCloseTimeConstant(p.close_time_constant) +	mCloseTimeConstant(p.close_time_constant), +	mResizeBarOverlap(p.resize_bar_overlap)  {}  LLLayoutStack::~LLLayoutStack() @@ -143,28 +242,27 @@ void LLLayoutStack::draw()  {  	updateLayout(); -	e_panel_list_t::iterator panel_it; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) +	// always clip to stack itself +	LLLocalClipRect clip(getLocalRect()); +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{  		// clip to layout rectangle, not bounding rectangle -		LLRect clip_rect = (*panel_it)->getRect(); +		LLRect clip_rect = panelp->getRect();  		// 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 + panelp->getVisibleDim();  		}  		else  		{ -			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation)); +			clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim();  		} -		LLPanel* panelp = (*panel_it); - -		LLLocalClipRect clip(clip_rect, mClip); -		// only force drawing invisible children if visible amount is non-zero -		drawChild(panelp, 0, 0, !clip_rect.isEmpty()); +		{LLLocalClipRect clip(clip_rect, mClip); +			// only force drawing invisible children if visible amount is non-zero +			drawChild(panelp, 0, 0, !clip_rect.isEmpty()); +		}  	} -	mAnimatedThisFrame = false;  }  void LLLayoutStack::removeChild(LLView* view) @@ -175,12 +273,10 @@ void LLLayoutStack::removeChild(LLView* view)  	{  		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));  		delete embedded_panelp; +		updateFractionalSizes(); +		mNeedsLayout = true;  	} -	// need to update resizebars - -	calcMinExtents(); -  	LLView::removeChild(view);  } @@ -195,50 +291,15 @@ bool LLLayoutStack::addChild(LLView* child, S32 tab_group)  	LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);  	if (panelp)  	{ +		panelp->setOrientation(mOrientation);  		mPanels.push_back(panelp); +		createResizeBar(panelp); +		mNeedsLayout = true;  	} -	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); -	LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel); +	BOOL result = LLView::addChild(child, tab_group); -	if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel) -	{ -		llwarns << "One of the panels was not found in stack or NULL was passed instead of valid panel" << llendl; -		return; -	} -	e_panel_list_t::iterator it = std::find(mPanels.begin(), mPanels.end(), embedded_panel_to_move); -	mPanels.erase(it); -	it = move_to_front ? mPanels.begin() : std::find(mPanels.begin(), mPanels.end(), embedded_target_panel); -	mPanels.insert(it, embedded_panel_to_move); +	updateFractionalSizes(); +	return result;  }  void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate) @@ -253,82 +314,281 @@ void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate)  	}  } -void LLLayoutStack::removePanel(LLPanel* panel) -{ -	removeChild(panel); -} -  void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)  {  	LLLayoutPanel* panel_container = findEmbeddedPanel(panel);  	if (!panel_container) return;  	panel_container->mCollapsed = collapsed; +	mNeedsLayout = true;  } -void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize) +static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks"); + +void LLLayoutStack::updateLayout() +{	 +	LLFastTimer ft(FTM_UPDATE_LAYOUT); + +	if (!mNeedsLayout) return; + +	bool continue_animating = animatePanels(); +	F32 total_visible_fraction = 0.f; +	S32 space_to_distribute = (mOrientation == HORIZONTAL) +							? getRect().getWidth() +							: getRect().getHeight(); + +	// first, assign minimum dimensions +	LLLayoutPanel* panelp = NULL; +	BOOST_FOREACH(panelp, mPanels) +	{ +		if (panelp->mAutoResize) +		{ +			panelp->mTargetDim = panelp->getRelevantMinDim(); +		} +		space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount()); +		total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); +	} + +	llassert(total_visible_fraction < 1.05f); + +	// don't need spacing after last panel +	space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; + +	S32 remaining_space = space_to_distribute; +	F32 fraction_distributed = 0.f; +	if (space_to_distribute > 0 && total_visible_fraction > 0.f) +	{	// give space proportionally to visible auto resize panels +		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +		{ +			if (panelp->mAutoResize) +			{ +				F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction); +				S32 delta = llround((F32)space_to_distribute * fraction_to_distribute); +				fraction_distributed += fraction_to_distribute; +				panelp->mTargetDim += delta; +				remaining_space -= delta; +			} +		} +	} + +	// distribute any left over pixels to non-collapsed, visible panels +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (remaining_space == 0) break; + +		if (panelp->mAutoResize  +			&& !panelp->mCollapsed  +			&& panelp->getVisible()) +		{ +			S32 space_for_panel = remaining_space > 0 ? 1 : -1; +			panelp->mTargetDim += space_for_panel; +			remaining_space -= space_for_panel; +		} +	} + +	F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight(); + +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); +		F32 panel_visible_dim = panelp->getVisibleDim(); + +		LLRect panel_rect; +		if (mOrientation == HORIZONTAL) +		{ +			panel_rect.setLeftTopAndSize(llround(cur_pos), +										getRect().getHeight(), +										llround(panel_dim), +										getRect().getHeight()); +		} +		else +		{ +			panel_rect.setLeftTopAndSize(0, +										llround(cur_pos), +										getRect().getWidth(), +										llround(panel_dim)); +		} +		panelp->setIgnoreReshape(true); +		panelp->setShape(panel_rect); +		panelp->setIgnoreReshape(false); + +		LLRect resize_bar_rect(panel_rect); + +		F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount(); +		if (mOrientation == HORIZONTAL) +		{ +			resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; +			resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap; + +			cur_pos += panel_visible_dim + panel_spacing; +		} +		else //VERTICAL +		{ +			resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; +			resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap; + +			cur_pos -= panel_visible_dim + panel_spacing; +		} +		panelp->mResizeBar->setShape(resize_bar_rect); +	} + +	updateResizeBarLimits(); + +	// clear animation flag at end, since panel resizes will set it +	// and leave it set if there is any animation in progress +	mNeedsLayout = continue_animating; +} // end LLLayoutStack::updateLayout + +LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const  { -	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	if (!panelp) return NULL; -	if (panel) +	e_panel_list_t::const_iterator panel_it; +	BOOST_FOREACH(LLLayoutPanel* p, mPanels)  	{ -		panel->mAutoResize = auto_resize; +		if (p == panelp) +		{ +			return p; +		}  	} +	return NULL;  } -void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize) +LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const  { -	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	LLLayoutPanel* result = NULL; -	if (panel) +	BOOST_FOREACH(LLLayoutPanel* p, mPanels)  	{ -		panel->mUserResize = user_resize; +		if (p->getName() == name) +		{ +			result = p; +			break; +		}  	} + +	return result;  } -bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp) +void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)  { -	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	BOOST_FOREACH(LLLayoutPanel* lp, mPanels) +	{ +		if (lp->mResizeBar == NULL) +		{ +			LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; +			LLRect resize_bar_rect = getRect(); -	if (panel && min_dimp) +			LLResizeBar::Params resize_params; +			resize_params.name("resize"); +			resize_params.resizing_view(lp); +			resize_params.min_size(lp->getRelevantMinDim()); +			resize_params.side(side); +			resize_params.snapping_enabled(false); +			LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); +			lp->mResizeBar = resize_bar; +			LLView::addChild(resize_bar, 0); +		} +	} +	// bring all resize bars to the front so that they are clickable even over the panels +	// with a bit of overlap +	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{ -		*min_dimp = panel->getRelevantMinDim(); +		LLResizeBar* resize_barp = (*panel_it)->mResizeBar; +		sendChildToFront(resize_barp);  	} +} -	return NULL != panel; +// update layout stack animations, etc. once per frame +// NOTE: we use this to size world view based on animating UI, *before* we draw the UI +// we might still need to call updateLayout during UI draw phase, in case UI elements +// are resizing themselves dynamically +//static  +void LLLayoutStack::updateClass() +{ +	for (instance_iter it = beginInstances(); it != endInstances(); ++it) +	{ +		it->updateLayout(); +		it->mAnimatedThisFrame = false; +	}  } -bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp) +void LLLayoutStack::updateFractionalSizes()  { -	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	F32 total_resizable_dim = 0.f; + +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (panelp->mAutoResize) +		{ +			total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim()); +		} +	} -	if (panel) +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{ -		if (max_dimp) *max_dimp = panel->mMaxDim; +		if (panelp->mAutoResize) +		{ +			F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); +			panelp->mFractionalSize = panel_resizable_dim > 0.f  +				? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) +				: MIN_FRACTIONAL_SIZE; +			llassert(!llisnan(panelp->mFractionalSize)); +		}  	} -	return NULL != panel; +	normalizeFractionalSizes();  } -static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks"); -void LLLayoutStack::updateLayout(BOOL force_resize) + +void LLLayoutStack::normalizeFractionalSizes()  { -	LLFastTimer ft(FTM_UPDATE_LAYOUT); -	static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0); -	calcMinExtents(); -	createResizeBars(); +	S32 num_auto_resize_panels = 0; +	F32 total_fractional_size = 0.f; +	 +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (panelp->mAutoResize) +		{ +			total_fractional_size += panelp->mFractionalSize; +			num_auto_resize_panels++; +		} +	} -	// calculate current extents -	S32 total_width = 0; -	S32 total_height = 0; +	if (total_fractional_size == 0.f) +	{ // equal distribution +		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +		{ +			if (panelp->mAutoResize) +			{ +				panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels; +			} +		} +	} +	else +	{ // renormalize +		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +		{ +			if (panelp->mAutoResize) +			{ +				panelp->mFractionalSize /= total_fractional_size; +			} +		} +	} +} -	e_panel_list_t::iterator panel_it; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it) +bool LLLayoutStack::animatePanels() +{ +	bool continue_animating = false; +	 +	// +	// animate visibility +	// +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)  	{ -		LLLayoutPanel* panelp = (*panel_it); -		if (panelp->getVisible())  +		if (panelp->getVisible())  		{ -			if (mAnimate) +			if (mAnimate && panelp->mVisibleAmt < 1.f)  			{  				if (!mAnimatedThisFrame)  				{ @@ -338,15 +598,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  						panelp->mVisibleAmt = 1.f;  					}  				} +				 +				mAnimatedThisFrame = true; +				continue_animating = true;  			}  			else  			{ -				panelp->mVisibleAmt = 1.f; +				if (panelp->mVisibleAmt != 1.f) +				{ +					panelp->mVisibleAmt = 1.f; +					mAnimatedThisFrame = true; +				}  			}  		}  		else // not visible  		{ -			if (mAnimate) +			if (mAnimate && panelp->mVisibleAmt > 0.f)  			{  				if (!mAnimatedThisFrame)  				{ @@ -356,368 +623,235 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  						panelp->mVisibleAmt = 0.f;  					}  				} + +				continue_animating = true; +				mAnimatedThisFrame = true;  			}  			else  			{ -				panelp->mVisibleAmt = 0.f; +				if (panelp->mVisibleAmt != 0.f) +				{ +					panelp->mVisibleAmt = 0.f; +					mAnimatedThisFrame = true; +				}  			}  		} -		if (panelp->mCollapsed) -		{ -			panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); -		} -		else -		{ -			panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); -		} - -		if (mOrientation == HORIZONTAL) -		{ -			// enforce minimize size constraint by default -			if (panelp->getRect().getWidth() < panelp->getRelevantMinDim()) -			{ -				panelp->reshape(panelp->getRelevantMinDim(), panelp->getRect().getHeight()); -			} -        	total_width += llround(panelp->getRect().getWidth() * panelp->getCollapseFactor(mOrientation)); -        	// want n-1 panel gaps for n panels -			if (panel_it != mPanels.begin()) -			{ -				total_width += mPanelSpacing; -			} -		} -		else //VERTICAL +		F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f; +		if (panelp->mCollapseAmt != collapse_state)  		{ -			// enforce minimize size constraint by default -			if (panelp->getRect().getHeight() < panelp->getRelevantMinDim()) +			if (mAnimate)  			{ -				panelp->reshape(panelp->getRect().getWidth(), panelp->getRelevantMinDim()); +				if (!mAnimatedThisFrame) +				{ +					panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); +				} +			 +				if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) +				{ +					panelp->mCollapseAmt = collapse_state; +				} + +				mAnimatedThisFrame = true; +				continue_animating = true;  			} -			total_height += llround(panelp->getRect().getHeight() * panelp->getCollapseFactor(mOrientation)); -			if (panel_it != mPanels.begin()) +			else  			{ -				total_height += mPanelSpacing; +				panelp->mCollapseAmt = collapse_state; +				mAnimatedThisFrame = true;  			}  		}  	} -	S32 num_resizable_panels = 0; -	S32 shrink_headroom_available = 0; -	S32 shrink_headroom_total = 0; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) +	if (mAnimatedThisFrame) mNeedsLayout = true; +	return continue_animating; +} + +void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect ) +{ +	S32 new_dim = (mOrientation == HORIZONTAL) +					? new_rect.getWidth() +					: new_rect.getHeight(); +	S32 delta_dim = new_dim - resized_panel->getVisibleDim(); +	if (delta_dim == 0) return; + +	F32 total_visible_fraction = 0.f; +	F32 delta_auto_resize_headroom = 0.f; +	F32 original_auto_resize_headroom = 0.f; + +	LLLayoutPanel* other_resize_panel = NULL; +	LLLayoutPanel* following_panel = NULL; + +	BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels)  	{ -		// panels that are not fully visible do not count towards shrink headroom -		if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f)  +		if (panelp->mAutoResize)  		{ -			continue; +			original_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); +			if (panelp->getVisible() && !panelp->mCollapsed) +			{ +				total_visible_fraction += panelp->mFractionalSize; +			}  		} -		S32 relevant_dimension = (mOrientation == HORIZONTAL) ? (*panel_it)->getRect().getWidth() : (*panel_it)->getRect().getHeight(); -		S32 relevant_min = (*panel_it)->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  -				&& !force_resize)) +		if (panelp == resized_panel)  		{ -			shrink_headroom_total += relevant_dimension - relevant_min; +			other_resize_panel = following_panel;  		} -		else + +		if (panelp->getVisible() && !panelp->mCollapsed)  		{ -			num_resizable_panels++; -			 -			shrink_headroom_available += relevant_dimension - relevant_min; -			shrink_headroom_total += relevant_dimension - relevant_min; +			following_panel = panelp;  		}  	} -	// 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) + +	if (resized_panel->mAutoResize)  	{ -		pixels_to_distribute = getRect().getWidth() - total_width; +		if (!other_resize_panel || !other_resize_panel->mAutoResize) +		{ +			delta_auto_resize_headroom += delta_dim;	 +		}  	} -	else //VERTICAL +	else   	{ -		pixels_to_distribute = getRect().getHeight() - total_height; +		if (!other_resize_panel || other_resize_panel->mAutoResize) +		{ +			delta_auto_resize_headroom -= delta_dim; +		}  	} -	// now we distribute the pixels... -	S32 cur_x = 0; -	S32 cur_y = getRect().getHeight(); +	F32 fraction_given_up = 0.f; +	F32 fraction_remaining = 1.f; +	F32 updated_auto_resize_headroom = original_auto_resize_headroom + delta_auto_resize_headroom; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) +	enum  	{ -		LLLayoutPanel* panelp = (*panel_it); +		BEFORE_RESIZED_PANEL, +		RESIZED_PANEL, +		NEXT_PANEL, +		AFTER_RESIZED_PANEL +	} which_panel = BEFORE_RESIZED_PANEL; -		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(); +	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) +	{ +		if (!panelp->getVisible() || panelp->mCollapsed) continue; -		if (mOrientation == HORIZONTAL) -		{ -			new_width = llmax(relevant_min, new_width); -		} -		else +		if (panelp == resized_panel)  		{ -			new_height = llmax(relevant_min, new_height); +			which_panel = RESIZED_PANEL;  		} -		S32 delta_size = 0; -		// if panel can automatically resize (not animating, and resize flag set)... -		if (panelp->getCollapseFactor(mOrientation) == 1.f  -			&& (force_resize || panelp->mAutoResize)  -			&& !panelp->mResizeBar->hasMouseCapture())  +		switch(which_panel)  		{ -			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); +		case BEFORE_RESIZED_PANEL: +			if (panelp->mAutoResize) +			{	// freeze current size as fraction of overall auto_resize space +				F32 fractional_adjustment_factor = updated_auto_resize_headroom == 0.f +													? 1.f +													: original_auto_resize_headroom / updated_auto_resize_headroom; +				F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor, +													MIN_FRACTIONAL_SIZE, +													MAX_FRACTIONAL_SIZE); +				fraction_given_up -= new_fractional_size - panelp->mFractionalSize; +				fraction_remaining -= panelp->mFractionalSize; +				panelp->mFractionalSize = new_fractional_size; +				llassert(!llisnan(panelp->mFractionalSize));  			}  			else  			{ -				new_width = getDefaultWidth(new_width); +				// leave non auto-resize panels alone  			} - -			if (mOrientation == VERTICAL) +			break; +		case RESIZED_PANEL: +			if (panelp->mAutoResize) +			{	// freeze new size as fraction +				F32 new_fractional_size = (updated_auto_resize_headroom == 0.f) +					? MAX_FRACTIONAL_SIZE +					: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); +				fraction_given_up -= new_fractional_size - panelp->mFractionalSize; +				fraction_remaining -= panelp->mFractionalSize; +				panelp->mFractionalSize = new_fractional_size; +				llassert(!llisnan(panelp->mFractionalSize)); +			} +			else +			{	// freeze new size as original size +				panelp->mTargetDim = new_dim; +			} +			which_panel = NEXT_PANEL; +			break; +		case NEXT_PANEL: +			if (panelp->mAutoResize)  			{ -				if (pixels_to_distribute < 0) +				fraction_remaining -= panelp->mFractionalSize; +				if (resized_panel->mAutoResize)  				{ -					// 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); +					panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); +					fraction_given_up = 0.f;  				}  				else  				{ -					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels); -					num_resizable_panels--; +					F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)  +														/ updated_auto_resize_headroom, +													MIN_FRACTIONAL_SIZE, +													MAX_FRACTIONAL_SIZE); +					fraction_given_up -= new_fractional_size - panelp->mFractionalSize; +					panelp->mFractionalSize = new_fractional_size;  				} -				pixels_to_distribute -= delta_size; -				new_height = llmax(relevant_min, cur_height + delta_size);  			}  			else  			{ -				new_height = getDefaultHeight(new_height); +				panelp->mTargetDim -= delta_dim;  			} -		} -		else -		{ -			if (mOrientation == HORIZONTAL) -			{ -				new_height = getDefaultHeight(new_height); -			} -			else // VERTICAL +			which_panel = AFTER_RESIZED_PANEL; +			break; +		case AFTER_RESIZED_PANEL: +			if (panelp->mAutoResize && fraction_given_up != 0.f)  			{ -				new_width = getDefaultWidth(new_width); +				panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up, +												MIN_FRACTIONAL_SIZE, +												MAX_FRACTIONAL_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); -		panelp->setShape(panel_rect); - -		LLRect resize_bar_rect = panel_rect; -		if (mOrientation == HORIZONTAL) -		{ -			resize_bar_rect.mLeft = panel_rect.mRight - resize_bar_overlap; -			resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + resize_bar_overlap; -		} -		else -		{ -			resize_bar_rect.mTop = panel_rect.mBottom + resize_bar_overlap; -			resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - resize_bar_overlap; -		} -		(*panel_it)->mResizeBar->setRect(resize_bar_rect); - -		if (mOrientation == HORIZONTAL) -		{ -			cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing; -		} -		else //VERTICAL -		{ -			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing; -		} -	} - -	// update resize bars with new limits -	LLLayoutPanel* last_resizeable_panel = NULL; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) -	{ -		LLLayoutPanel* panelp = (*panel_it); -		S32 relevant_min = panelp->getRelevantMinDim(); - -		if (mOrientation == HORIZONTAL) -		{ -			(*panel_it)->mResizeBar->setResizeLimits( -				relevant_min,  -				relevant_min + shrink_headroom_total); -		} -		else //VERTICAL -		{ -			(*panel_it)->mResizeBar->setResizeLimits( -				relevant_min,  -				relevant_min + shrink_headroom_total); -		} - -		// toggle resize bars based on panel visibility, resizability, etc -		BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize; -		(*panel_it)->mResizeBar->setVisible(resize_bar_enabled); - -		if ((*panel_it)->mUserResize || (*panel_it)->mAutoResize) -		{ -			last_resizeable_panel = (*panel_it); -		} -	} - -	// hide last resize bar as there is nothing past it -	// resize bars need to be in between two resizable panels -	if (last_resizeable_panel) -	{ -		last_resizeable_panel->mResizeBar->setVisible(FALSE); -	} - -	// 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))) -	{ -		// do another layout pass with all stacked elements contributing -		// even those that don't usually resize -		llassert_always(force_resize == FALSE); -		updateLayout(TRUE); -	} - -	 mAnimatedThisFrame = true; -} // end LLLayoutStack::updateLayout - - -LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const -{ -	if (!panelp) return NULL; - -	e_panel_list_t::const_iterator panel_it; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) -	{ -		if ((*panel_it) == panelp) -		{ -			return *panel_it; +		default: +			break;  		}  	} -	return NULL; +	updateLayout(); +	normalizeFractionalSizes();  } -LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const +void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)  { -	LLLayoutPanel* result = NULL; - -	for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) -	{ -		LLLayoutPanel* p = *panel_it; - -		if (p->getName() == name) -		{ -			result = p; -			break; -		} -	} - -	return result; +	mNeedsLayout = true; +	LLView::reshape(width, height, called_from_parent);  } -// Compute sum of min_width or min_height of children -void LLLayoutStack::calcMinExtents() +void LLLayoutStack::updateResizeBarLimits()  { -	mMinWidth = 0; -	mMinHeight = 0; - -	e_panel_list_t::iterator panel_it; -	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) +	LLLayoutPanel* previous_visible_panelp = NULL; +	BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels)  	{ -		if (mOrientation == HORIZONTAL) +		if (!visible_panelp->getVisible() || visible_panelp->mCollapsed)  		{ -            mMinWidth += (*panel_it)->getRelevantMinDim(); -			if (panel_it != mPanels.begin()) -			{ -				mMinWidth += mPanelSpacing; -			} +			visible_panelp->mResizeBar->setVisible(FALSE); +			continue;  		} -		else //VERTICAL + +		// toggle resize bars based on panel visibility, resizability, etc +		if (previous_visible_panelp +			&& (visible_panelp->mUserResize || previous_visible_panelp->mUserResize)				// one of the pair is user resizable +			&& (visible_panelp->mAutoResize || visible_panelp->mUserResize)							// current panel is resizable +			&& (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize))		// previous panel is resizable  		{ -			mMinHeight += (*panel_it)->getRelevantMinDim(); -			if (panel_it != mPanels.begin()) -			{ -				mMinHeight += mPanelSpacing; -			} +			visible_panelp->mResizeBar->setVisible(TRUE); +			S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim(); +			visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(),  +														visible_panelp->getVisibleDim() + previous_panel_headroom);  		} -	} -} - -void LLLayoutStack::createResizeBars() -{ -	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) -	{ -		LLLayoutPanel* lp = (*panel_it); -		if (lp->mResizeBar == NULL) +		else  		{ -			LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; -			LLRect resize_bar_rect = getRect(); - -			LLResizeBar::Params resize_params; -			resize_params.name("resize"); -			resize_params.resizing_view(lp); -			resize_params.min_size(lp->getRelevantMinDim()); -			resize_params.side(side); -			resize_params.snapping_enabled(false); -			LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); -			lp->mResizeBar = resize_bar; -			LLView::addChild(resize_bar, 0); - -			// bring all resize bars to the front so that they are clickable even over the panels -			// with a bit of overlap -			for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) -			{ -				LLResizeBar* resize_barp = (*panel_it)->mResizeBar; -				sendChildToFront(resize_barp); -			} +			visible_panelp->mResizeBar->setVisible(FALSE);  		} -	} -} -// update layout stack animations, etc. once per frame -// NOTE: we use this to size world view based on animating UI, *before* we draw the UI -// we might still need to call updateLayout during UI draw phase, in case UI elements -// are resizing themselves dynamically -//static  -void LLLayoutStack::updateClass() -{ -	LLInstanceTrackerScopedGuard guard; -	for (LLLayoutStack::instance_iter it = guard.beginInstances(); -	     it != guard.endInstances(); -	     ++it) -	{ -		it->updateLayout(); +		previous_visible_panelp = visible_panelp;  	}  } diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index d8ef0aeaca..648cd5fdce 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -5,7 +5,7 @@   *   * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2010, Linden Reshasearch, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -60,6 +60,7 @@ public:  								clip;  		Optional<F32>			open_time_constant,  								close_time_constant; +		Optional<S32>			resize_bar_overlap;  		Params();  	}; @@ -71,13 +72,12 @@ public:  	/*virtual*/ void draw();  	/*virtual*/ void removeChild(LLView*);  	/*virtual*/ BOOL postBuild(); -	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); +	/*virtual*/ bool addChild(LLView* child, S32 tab_groupdatefractuiona = 0); +	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); +  	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); -	S32 getMinWidth() const { return mMinWidth; } -	S32 getMinHeight() const { return mMinHeight; } -	  	typedef enum e_animate  	{  		NO_ANIMATE, @@ -85,49 +85,24 @@ public:  	} EAnimate;  	void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE); -	void removePanel(LLPanel* panel);  	void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);  	S32 getNumPanels() { return mPanels.size(); } -	/** -	 * Moves panel_to_move before target_panel inside layout stack (both panels should already be there). -	 * If move_to_front is true target_panel is ignored and panel_to_move is moved to the beginning of mPanels -	 */ -	void movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front = false); - -	void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize); -	void setPanelUserResize(const std::string& panel_name, BOOL user_resize); -	 -	/** -	 * Gets minimal dimension along layout_stack axis of the specified by name panel. -	 * -	 * @returns true if specified by panel_name internal panel exists, false otherwise. -	 */ -	bool getPanelMinSize(const std::string& panel_name, S32* min_dimp); - -	/** -	 * Gets maximal dimension along layout_stack axis of the specified by name panel. -	 * -	 * @returns true if specified by panel_name internal panel exists, false otherwise. -	 */ -	bool getPanelMaxSize(const std::string& panel_name, S32* max_dim); -	 -	void updateLayout(BOOL force_resize = FALSE); -	 + +	void updateLayout(); +  	S32 getPanelSpacing() const { return mPanelSpacing; } -	BOOL getAnimate () const { return mAnimate; } -	void setAnimate (BOOL animate) { mAnimate = animate; }  	static void updateClass();  protected:  	LLLayoutStack(const Params&);  	friend class LLUICtrlFactory; +	friend class LLLayoutPanel;  private: -	void createResizeBars(); -	void calcMinExtents(); -	S32 getDefaultHeight(S32 cur_height); -	S32 getDefaultWidth(S32 cur_width); +	void updateResizeBarLimits(); +	bool animatePanels(); +	void createResizeBar(LLLayoutPanel* panel);  	const ELayoutOrientation mOrientation; @@ -136,17 +111,20 @@ private:  	LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;  	LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const; +	void updateFractionalSizes(); +	void normalizeFractionalSizes(); +	void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect ); -	S32 mMinWidth;  // calculated by calcMinExtents -	S32 mMinHeight;  // calculated by calcMinExtents  	S32 mPanelSpacing;  	// true if we already applied animation this frame  	bool mAnimatedThisFrame;  	bool mAnimate;  	bool mClip; -	F32 mOpenTimeConstant; -	F32 mCloseTimeConstant; +	F32  mOpenTimeConstant; +	F32  mCloseTimeConstant; +	bool mNeedsLayout; +	S32  mResizeBarOverlap;  }; // end class LLLayoutStack @@ -158,37 +136,32 @@ public:  	struct Params : public LLInitParam::Block<Params, LLPanel::Params>  	{  		Optional<S32>			expanded_min_dim, -								min_dim, -								max_dim; +								min_dim;  		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); -	S32 getMinDim() const { return mMinDim; } -	void setMinDim(S32 value) { mMinDim = value; if (!mExpandedMinDimSpecified) mExpandedMinDim = value; } +	void handleReshape(const LLRect& new_rect, bool by_user); + +	void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); +	 -	S32 getMaxDim() const { return mMaxDim; } -	void setMaxDim(S32 value) { mMaxDim = value; } +	void setVisible(BOOL visible); -	S32 getExpandedMinDim() const { return mExpandedMinDim; } -	void setExpandedMinDim(S32 value) { mExpandedMinDim = value; mExpandedMinDimSpecified = true; } +	S32 getLayoutDim() const; +	S32 getTargetDim() const; +	void setTargetDim(S32 value); +	S32 getMinDim() const { return llmax(0, mMinDim); } +	void setMinDim(S32 value) { mMinDim = value; } + +	S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); } +	void setExpandedMinDim(S32 value) { mExpandedMinDim = value; }  	S32 getRelevantMinDim() const  	{ @@ -196,28 +169,37 @@ public:  		if (!mCollapsed)  		{ -			min_dim = mExpandedMinDim; +			min_dim = getExpandedMinDim();  		}  		return min_dim;  	} +	F32 getAutoResizeFactor() const; +	F32 getVisibleAmount() const; +	S32 getVisibleDim() const; + +	void setOrientation(LLLayoutStack::ELayoutOrientation orientation); +	void storeOriginalDim(); + +	void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; } +  protected:  	LLLayoutPanel(const Params& p); -	F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation); - -	bool mExpandedMinDimSpecified; -	S32 mExpandedMinDim; -	 -	S32 mMinDim; -	S32 mMaxDim; -	BOOL mAutoResize; -	BOOL mUserResize; -	BOOL mCollapsed; +	const bool	mAutoResize; +	const bool	mUserResize; + +	S32		mExpandedMinDim; +	S32		mMinDim; +	bool	mCollapsed; +	F32		mVisibleAmt; +	F32		mCollapseAmt; +	F32		mFractionalSize; +	S32		mTargetDim; +	bool	mIgnoreReshape; +	LLLayoutStack::ELayoutOrientation mOrientation;  	class LLResizeBar* mResizeBar; -	F32 mVisibleAmt; -	F32 mCollapseAmt;  }; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 06fbc0f234..d0fbf4b913 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -103,10 +103,11 @@ LLLineEditor::Params::Params()  	text_pad_right("text_pad_right"),  	default_text("default_text")  { -	mouse_opaque = true; +	changeDefault(mouse_opaque, true);  	addSynonym(select_on_focus, "select_all_on_focus_received");  	addSynonym(border, "border");  	addSynonym(label, "watermark_text"); +	addSynonym(max_length.chars, "max_length");  }  LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) @@ -197,6 +198,7 @@ LLLineEditor::~LLLineEditor()  void LLLineEditor::onFocusReceived()  { +	gEditMenuHandler = this;  	LLUICtrl::onFocusReceived();  	updateAllowingLanguageInput();  } @@ -1045,7 +1047,7 @@ void LLLineEditor::cut()  		// Prepare for possible rollback  		LLLineEditorRollback rollback( this ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  		deleteSelection();  		// Validate new string and rollback the if needed. @@ -1076,13 +1078,13 @@ void LLLineEditor::copy()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length );  	}  }  BOOL LLLineEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable();   }  void LLLineEditor::paste() @@ -1113,14 +1115,7 @@ void LLLineEditor::pasteHelper(bool is_primary)  	if (can_paste_it)  	{  		LLWString paste; -		if (is_primary) -		{ -			paste = gClipboard.getPastePrimaryWString(); -		} -		else  -		{ -			paste = gClipboard.getPasteWString(); -		} +		LLClipboard::instance().pasteFromClipboard(paste, is_primary);  		if (!paste.empty())  		{ @@ -1207,13 +1202,13 @@ void LLLineEditor::copyPrimary()  	{  		S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  		S32 length = llabs( mSelectionStart - mSelectionEnd ); -		gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); +		LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length, true);  	}  }  BOOL LLLineEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString();  +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);   }  void LLLineEditor::updatePrimary() @@ -1628,7 +1623,7 @@ void LLLineEditor::draw()  	LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 );  	background.stretch( -mBorderThickness ); -	S32 lineeditor_v_pad = llround((background.getHeight() - mGLFont->getLineHeight())/2); +	S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2;  	drawBackground(); 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/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index eed0085273..50d59f79f4 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -35,9 +35,16 @@  static LLDefaultChildRegistry::Register<LLMenuButton> r("menu_button"); +void LLMenuButton::MenuPositions::declareValues() +{ +	declare("topleft", MP_TOP_LEFT); +	declare("topright", MP_TOP_RIGHT); +	declare("bottomleft", MP_BOTTOM_LEFT); +}  LLMenuButton::Params::Params() -:	menu_filename("menu_filename") +:	menu_filename("menu_filename"), +	position("position", MP_BOTTOM_LEFT)  {  } @@ -45,7 +52,7 @@ LLMenuButton::Params::Params()  LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)  :	LLButton(p),  	mIsMenuShown(false), -	mMenuPosition(MP_BOTTOM_LEFT) +	mMenuPosition(p.position)  {  	std::string menu_filename = p.menu_filename; diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 7b657595da..e2396e7fb2 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -35,21 +35,30 @@ class LLMenuButton  : public LLButton  {  public: +	typedef enum e_menu_position +	{ +		MP_TOP_LEFT, +		MP_TOP_RIGHT, +		MP_BOTTOM_LEFT +	} EMenuPosition; + +	struct MenuPositions +		:	public LLInitParam::TypeValuesHelper<EMenuPosition, MenuPositions> +	{ +		static void declareValues(); +	}; +  	struct Params   	:	public LLInitParam::Block<Params, LLButton::Params>  	{  		// filename for it's toggleable menu  		Optional<std::string>	menu_filename; +		Optional<EMenuPosition>	position;  		Params();  	}; -	typedef enum e_menu_position -	{ -		MP_TOP_LEFT, -		MP_TOP_RIGHT, -		MP_BOTTOM_LEFT -	} EMenuPosition; +  	boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 8de9c769e2..ff6928ffda 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -90,7 +90,6 @@ const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;  const S32 MENU_ITEM_PADDING = 4;  const std::string SEPARATOR_NAME("separator"); -const std::string SEPARATOR_LABEL( "-----------" );  const std::string VERTICAL_SEPARATOR_LABEL( "|" );  const std::string LLMenuGL::BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK @@ -149,7 +148,7 @@ LLMenuItemGL::Params::Params()  	highlight_bg_color("highlight_bg_color"),  	highlight_fg_color("highlight_fg_color")  {	 -	mouse_opaque = true; +	changeDefault(mouse_opaque, true);  }  // Default constructor @@ -318,7 +317,7 @@ void LLMenuItemGL::setJumpKey(KEY key)  // virtual   U32 LLMenuItemGL::getNominalHeight( void ) const   {  -	return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING;  +	return mFont->getLineHeight() + MENU_ITEM_PADDING;  }  //virtual @@ -509,19 +508,19 @@ void LLMenuItemGL::draw( void )  	{  		if( !mDrawBoolLabel.empty() )  		{ -			mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		} -		mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +		mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  					   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		if( !mDrawAccelLabel.empty() )  		{ -			mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		}  		if( !mDrawBranchLabel.empty() )  		{ -			mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color, +			mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,  						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );  		}  	} @@ -566,8 +565,6 @@ void LLMenuItemGL::handleVisibilityChange(BOOL new_visibility)  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  LLMenuItemSeparatorGL::Params::Params()  { -	name = "separator"; -	label = SEPARATOR_LABEL;  }  LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) : @@ -755,30 +752,6 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const  	return TEAROFF_SEPARATOR_HEIGHT_PIXELS;   } - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLMenuItemBlankGL -// -// This class represents a blank, non-functioning item. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLMenuItemBlankGL : public LLMenuItemGL -{ -public: -	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> -	{ -		Params() -		{ -			name=""; -			enabled = false; -		} -	}; -	LLMenuItemBlankGL( const Params& p ) :	LLMenuItemGL( p ) -	{} -	virtual void draw( void ) {} -}; - -  ///============================================================================  /// Class LLMenuItemCallGL  ///============================================================================ @@ -974,9 +947,14 @@ LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p)  LLMenuItemBranchGL::~LLMenuItemBranchGL()  { -	LLView::deleteViewByHandle(mBranchHandle); +	if (mBranchHandle.get()) +	{ +		mBranchHandle.get()->die(); +	}  } + +  // virtual  LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse) const  { @@ -1713,7 +1691,8 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)  	mSpilloverMenu(NULL),  	mJumpKey(p.jump_key),  	mCreateJumpKeys(p.create_jump_keys), -	mNeedsArrange(FALSE),  +	mNeedsArrange(FALSE), +	mResetScrollPositionOnShow(true),  	mShortcutPad(p.shortcut_pad)  {  	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; @@ -1758,7 +1737,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)  	{ @@ -1987,7 +1966,7 @@ void LLMenuGL::arrange( void )  		// *FIX: create the item first and then ask for its dimensions?  		S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate -		S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING; +		S32 spillover_item_height = LLFontGL::getFontSansSerif()->getLineHeight() + MENU_ITEM_PADDING;  		// Scrolling support  		item_list_t::iterator first_visible_item_iter; @@ -3070,7 +3049,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  	S32 mouse_x, mouse_y;  	// Resetting scrolling position -	if (menu->isScrollable()) +	if (menu->isScrollable() && menu->isScrollPositionOnShowReset())  	{  		menu->mFirstVisibleItem = NULL;  	} @@ -3103,7 +3082,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  		mouse_y + MOUSE_CURSOR_PADDING,   		CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2,   		CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); -	menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE ); +	menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect );  	menu->getParent()->sendChildToFront(menu);  } @@ -3446,7 +3425,7 @@ void LLMenuHolderGL::draw()  		LLUI::pushMatrix();  		{ -			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f); +			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom);  			selecteditem->getMenu()->drawBackground(selecteditem, interpolant);  			selecteditem->draw();  		} diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 7bde8e83ec..36f3ba34b9 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -372,17 +372,16 @@ public:  			drop_shadow("drop_shadow", true),  			bg_visible("bg_visible", true),  			create_jump_keys("create_jump_keys", false), +			keep_fixed_size("keep_fixed_size", false),  			bg_color("bg_color",  LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )),  			scrollable("scrollable", false),   			max_scrollable_items("max_scrollable_items", U32_MAX),  			preferred_width("preferred_width", U32_MAX),  			shortcut_pad("shortcut_pad") -			  		{  			addSynonym(bg_visible, "opaque");  			addSynonym(bg_color, "color"); - -			name = "menu"; +			addSynonym(can_tear_off, "can_tear_off");  		}  	}; @@ -517,6 +516,9 @@ public:  	static class LLMenuHolderGL* sMenuContainer; +	void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } +	bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } +  protected:  	void createSpilloverBranch();  	void cleanupSpilloverBranch(); @@ -566,6 +568,7 @@ private:  	KEY				mJumpKey;  	BOOL			mCreateJumpKeys;  	S32				mShortcutPad; +	bool			mResetScrollPositionOnShow;  }; // end class LLMenuGL @@ -650,7 +653,7 @@ public:  	{  		Params()  		{ -			visible = false; +			changeDefault(visible, false);  		}  	}; @@ -678,7 +681,7 @@ public:  			BOOL	appendContextSubMenu(LLContextMenu *menu); -			LLHandle<LLContextMenu> getHandle() { mHandle.bind(this); return mHandle; } +			LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }  protected:  	BOOL						mHoveredAnyItem; @@ -698,16 +701,7 @@ class LLMenuBarGL : public LLMenuGL  {  public:  	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> -	{ -		Params() -		{ -			can_tear_off = false; -			keep_fixed_size = true; -			horizontal_layout = true; -			visible = true; -			drop_shadow = false; -		} -	}; +	{};  	LLMenuBarGL( const Params& p );  	virtual ~LLMenuBarGL(); @@ -825,13 +819,7 @@ class LLMenuItemTearOffGL : public LLMenuItemGL  {  public:  	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> -	{ -		Params() -		{ -			name = "tear off"; -			label = "~~~~~~~~~~~"; -		} -	}; +	{};  	LLMenuItemTearOffGL( const Params& ); diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 9052bc7d1d..70bcfb5b4f 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -66,11 +66,7 @@ LLMultiSlider::Params::Params()  	mouse_up_callback("mouse_up_callback"),  	thumb_width("thumb_width"),  	sliders("slider") -{ -	name = "multi_slider_bar"; -	mouse_opaque(true); -	follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); -} +{}  LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  :	LLF32UICtrl(p), diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 6085c61f9a..8aa548b974 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"; @@ -245,7 +246,6 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica  	LLParamSDParser parser;  	parser.writeSD(mFormData, p.form_elements); -	mFormData = mFormData[""];  	if (!mFormData.isArray())  	{  		// change existing contents to a one element array @@ -417,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)); @@ -1398,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;  		}  	}  } @@ -1420,6 +1412,7 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path  bool LLNotifications::loadTemplates()  { +	llinfos << "Reading notifications template" << llendl;  	std::vector<std::string> search_paths;  	std::string skin_relative_path = gDirUtilp->getDirDelimiter() + LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + "notifications.xml"; @@ -1454,50 +1447,46 @@ 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));  	} +	llinfos << "...done" << llendl; +  	return true;  } @@ -1518,12 +1507,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; @@ -1641,7 +1627,7 @@ LLNotificationPtr LLNotifications::find(LLUUID uuid)  	LLNotificationSet::iterator it=mItems.find(target);  	if (it == mItems.end())  	{ -		llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl; +		LL_DEBUGS("Notifications") << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl;  		return LLNotificationPtr((LLNotification*)NULL);  	}  	else 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 eff572b553..fb50c9c123 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -88,10 +88,10 @@ struct LLNotificationTemplate  	{  	private:  		// this idiom allows  -		// <notification unique="true"> +		// <notification> <unique/> </notification>  		// as well as  		// <notification> <unique> <context></context> </unique>... -		Optional<bool>			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.cpp b/indra/llui/llpanel.cpp index 1dcdd79efa..00318cec6b 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -90,7 +90,6 @@ LLPanel::Params::Params()  	visible_callback("visible_callback"),  	accepts_badge("accepts_badge")  { -	name = "panel";  	addSynonym(background_visible, "bg_visible");  	addSynonym(has_border, "border_visible");  	addSynonym(label, "title"); @@ -99,6 +98,7 @@ LLPanel::Params::Params()  LLPanel::LLPanel(const LLPanel::Params& p)  :	LLUICtrl(p), +	LLBadgeHolder(p.accepts_badge),  	mBgVisible(p.background_visible),  	mBgOpaque(p.background_opaque),  	mBgOpaqueColor(p.bg_opaque_color()), @@ -114,8 +114,7 @@ LLPanel::LLPanel(const LLPanel::Params& p)  	mCommitCallbackRegistrar(false),  	mEnableCallbackRegistrar(false),  	mXMLFilename(p.filename), -	mVisibleSignal(NULL), -	mAcceptsBadge(p.accepts_badge) +	mVisibleSignal(NULL)  	// *NOTE: Be sure to also change LLPanel::initFromParams().  We have too  	// many classes derived from LLPanel to retrofit them all to pass in params.  { @@ -123,8 +122,6 @@ LLPanel::LLPanel(const LLPanel::Params& p)  	{  		addBorder(p.border);  	} -	 -	mPanelHandle.bind(this);  }  LLPanel::~LLPanel() @@ -488,7 +485,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p)  	mBgOpaqueImageOverlay = p.bg_opaque_image_overlay;  	mBgAlphaImageOverlay = p.bg_alpha_image_overlay; -	mAcceptsBadge = p.accepts_badge; +	setAcceptsBadge(p.accepts_badge);  }  static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup"); @@ -515,9 +512,6 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  		if (!xml_filename.empty())  		{ -			LLUICtrlFactory::instance().pushFileName(xml_filename); - -			LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD);  			if (output_node)  			{  				//if we are exporting, we want to export the current xml @@ -530,6 +524,9 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  				return TRUE;  			} +			LLUICtrlFactory::instance().pushFileName(xml_filename); + +			LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD);  			if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))  			{  				llwarns << "Couldn't parse panel from: " << xml_filename << llendl; diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 67674fab7e..f620201020 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -35,6 +35,7 @@  #include "lluiimage.h"  #include "lluistring.h"  #include "v4color.h" +#include "llbadgeholder.h"  #include <list>  #include <queue> @@ -51,7 +52,7 @@ class LLUIImage;   * With or without border,   * Can contain LLUICtrls.   */ -class LLPanel : public LLUICtrl +class LLPanel : public LLUICtrl, public LLBadgeHolder  {  public:  	struct LocalizedString : public LLInitParam::Block<LocalizedString> @@ -95,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 @@ -137,6 +135,8 @@ public:  	const LLColor4&	getBackgroundColor() const { return mBgOpaqueColor; }  	void			setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; }  	const LLColor4& getTransparentColor() const { return mBgAlphaColor; } +	void			setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; } +	void			setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; }  	LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; }  	LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; }  	LLColor4		getBackgroundImageOverlay() { return mBgOpaqueImageOverlay; } @@ -155,7 +155,7 @@ public:  	void			setCtrlsEnabled(BOOL b); -	LLHandle<LLPanel>	getHandle() const { return mPanelHandle; } +	LLHandle<LLPanel>	getHandle() const { return getDerivedHandle<LLPanel>(); }  	const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } @@ -252,8 +252,6 @@ public:  	boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb ); -	bool acceptsBadge() const { return mAcceptsBadge; } -  protected:  	// Override to set not found list  	LLButton*		getDefaultButton() { return mDefaultBtn; } @@ -266,9 +264,11 @@ protected:  	std::string		mHelpTopic;         // the name of this panel's help topic to display in the Help Viewer  	typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;  	static factory_stack_t	sFactoryStack; + +	// for setting the xml filename when building panel in context dependent cases +	std::string		mXMLFilename;  private: -	bool			mAcceptsBadge;  	BOOL			mBgVisible;				// any background at all?  	BOOL			mBgOpaque;				// use opaque color or image  	LLUIColor		mBgOpaqueColor; @@ -280,13 +280,10 @@ private:  	LLViewBorder*	mBorder;  	LLButton*		mDefaultBtn;  	LLUIString		mLabel; -	LLRootHandle<LLPanel> mPanelHandle;  	typedef std::map<std::string, std::string> ui_string_map_t;  	ui_string_map_t	mUIStrings; -	// for setting the xml filename when building panel in context dependent cases -	std::string		mXMLFilename;  }; // end class LLPanel diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index 3a12debf7e..95a7d09382 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -74,9 +74,6 @@ LLRadioGroup::Params::Params()  {  	addSynonym(items, "radio_item"); -	name = "radio_group"; -	mouse_opaque = true; -	follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;  	// radio items are not tabbable until they are selected  	tab_stop = false;  } @@ -96,7 +93,10 @@ void LLRadioGroup::initFromParams(const Params& p)  	{  		LLRadioGroup::ItemParams item_params(*it); -		item_params.font.setIfNotProvided(mFont); // apply radio group font by default +		if (!item_params.font.isProvided()) +		{ +			item_params.font = mFont; // apply radio group font by default +		}  		item_params.commit_callback.function = boost::bind(&LLRadioGroup::onClickButton, this, _1);  		item_params.from_xui = p.from_xui;  		if (p.from_xui) diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index 02f60c76fa..87aeb4d7a7 100644 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -79,6 +79,8 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)  BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)  { +	if (!canResize()) return FALSE; +  	// Route future Mouse messages here preemptively.  (Release on mouse up.)  	// No handler needed for focus lost since this clas has no state that depends on it.  	gFocusMgr.setMouseCapture( this ); @@ -243,7 +245,7 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)  		handled = TRUE;  	} -	if( handled ) +	if( handled && canResize() )  	{  		switch( mSide )  		{ diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 0725fbd846..6daf191918 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -70,6 +70,7 @@ public:  	void			setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; }  	void			setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; }  	void			setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; } +	bool			canResize() { return getEnabled() && mMaxSize > mMinSize; }  private:  	S32				mDragLastScreenX; 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/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index 3a867a10a7..5d3bf7a670 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -63,9 +63,7 @@ LLScrollbar::Params::Params()  	right_button("right_button"),  	bg_visible("bg_visible", false),  	bg_color("bg_color", LLColor4::black) -{ -	tab_stop = false; -} +{}  LLScrollbar::LLScrollbar(const Params & p)  :		LLUICtrl(p), diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 380c477eb2..9b7e30bb04 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -74,11 +74,7 @@ LLScrollContainer::Params::Params()  	min_auto_scroll_rate("min_auto_scroll_rate", 100),  	max_auto_scroll_rate("max_auto_scroll_rate", 1000),  	reserve_scroll_corner("reserve_scroll_corner", false) -{ -	name = "scroll_container"; -	mouse_opaque(true); -	tab_stop(false); -} +{}  // Default constructor @@ -227,6 +223,15 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)  	return FALSE;  } +BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char) +{ +	if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) +	{ +		return TRUE; +	} +	return FALSE; +} +  BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )  {  	// Give event to my child views - they may have scroll bars @@ -373,19 +378,24 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height  	if (!mHideScrollbar)  	{ -		if( *visible_height < doc_height ) +		// Note: 1 pixel change can happen on final animation and should not trigger  +		// the display of sliders. +		if ((doc_height - *visible_height) > 1)  		{  			*show_v_scrollbar = TRUE;  			*visible_width -= scrollbar_size;  		} - -		if( *visible_width < doc_width ) +		if ((doc_width - *visible_width) > 1)  		{  			*show_h_scrollbar = TRUE;  			*visible_height -= scrollbar_size; +			// The view inside the scroll container should not be extended +			// to container's full height to ensure the correct computation +			// of *show_v_scrollbar after subtracting horizontal scrollbar_size. +  			// Must retest now that visible_height has changed -			if( !*show_v_scrollbar && (*visible_height < doc_height) ) +			if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) )  			{  				*show_v_scrollbar = TRUE;  				*visible_width -= scrollbar_size; @@ -419,63 +429,66 @@ void LLScrollContainer::draw()  		focusFirstItem();  	} -	// Draw background -	if( mIsOpaque ) +	if (getRect().isValid())   	{ -		F32 alpha = getCurrentTransparency(); +		// Draw background +		if( mIsOpaque ) +		{ +			F32 alpha = getCurrentTransparency(); -		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -		gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); -	} +			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +			gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); +		} -	// Draw mScrolledViews and update scroll bars. -	// get a scissor region ready, and draw the scrolling view. The -	// scissor region ensures that we don't draw outside of the bounds -	// of the rectangle. -	if( mScrolledView ) -	{ -		updateScroll(); - -		// Draw the scrolled area. +		// Draw mScrolledViews and update scroll bars. +		// get a scissor region ready, and draw the scrolling view. The +		// scissor region ensures that we don't draw outside of the bounds +		// of the rectangle. +		if( mScrolledView )  		{ -			S32 visible_width = 0; -			S32 visible_height = 0; -			BOOL show_v_scrollbar = FALSE; -			BOOL show_h_scrollbar = FALSE; -			calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - -			LLLocalClipRect clip(LLRect(mInnerRect.mLeft,  -					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, -					mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), -					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) -					)); -			drawChild(mScrolledView); -		} -	} - -	// Highlight border if a child of this container has keyboard focus -	if( mBorder->getVisible() ) -	{ -		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); -	} +			updateScroll(); -	// Draw all children except mScrolledView -	// Note: scrollbars have been adjusted by above drawing code -	for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); -		 child_iter != getChildList()->rend(); ++child_iter) -	{ -		LLView *viewp = *child_iter; -		if( sDebugRects ) -		{ -			sDepth++; +			// Draw the scrolled area. +			{ +				S32 visible_width = 0; +				S32 visible_height = 0; +				BOOL show_v_scrollbar = FALSE; +				BOOL show_h_scrollbar = FALSE; +				calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + +				LLLocalClipRect clip(LLRect(mInnerRect.mLeft,  +						mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, +						mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), +						mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) +						)); +				drawChild(mScrolledView); +			}  		} -		if( (viewp != mScrolledView) && viewp->getVisible() ) + +		// Highlight border if a child of this container has keyboard focus +		if( mBorder->getVisible() )  		{ -			drawChild(viewp); +			mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) );  		} -		if( sDebugRects ) + +		// Draw all children except mScrolledView +		// Note: scrollbars have been adjusted by above drawing code +		for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); +			 child_iter != getChildList()->rend(); ++child_iter)  		{ -			sDepth--; +			LLView *viewp = *child_iter; +			if( sDebugRects ) +			{ +				sDepth++; +			} +			if( (viewp != mScrolledView) && viewp->getVisible() ) +			{ +				drawChild(viewp); +			} +			if( sDebugRects ) +			{ +				sDepth--; +			}  		}  	}  } // end draw diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 46a71a7e30..d87c95b3d7 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -91,7 +91,7 @@ public:  	void			setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; }  	LLRect			getVisibleContentRect();  	LLRect			getContentWindowRect(); -	const LLRect&	getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } +	virtual const LLRect	getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; }  	void			pageUp(S32 overlap = 0);  	void			pageDown(S32 overlap = 0);  	void			goToTop(); @@ -103,6 +103,7 @@ public:  	// LLView functionality  	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  	virtual BOOL	handleKeyHere(KEY key, MASK mask); +	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);  	virtual BOOL	handleScrollWheel( S32 x, S32 y, S32 clicks );  	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  								   EDragAndDropType cargo_type, @@ -115,6 +116,9 @@ public:  	bool autoScroll(S32 x, S32 y); +protected: +	LLView*		mScrolledView; +  private:  	// internal scrollbar handlers  	virtual void scrollHorizontal( S32 new_pos ); @@ -123,7 +127,6 @@ private:  	void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const;  	LLScrollbar* mScrollbar[SCROLLBAR_COUNT]; -	LLView*		mScrolledView;  	S32			mSize;  	BOOL		mIsOpaque;  	LLUIColor	mBackgroundColor; diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 8f569c2a58..e8df176ec3 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -51,12 +51,7 @@ class LLScrollingPanelList : public LLUICtrl  {  public:  	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> -	{ -		Params() -		{ -			name = "scrolling_panel_list"; -		} -	}; +	{};  	LLScrollingPanelList(const Params& p)  	:	LLUICtrl(p)   	{} diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 9d25c7180d..8000efad0e 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -232,7 +232,7 @@ BOOL LLScrollListText::getVisible() const  //virtual   S32 LLScrollListText::getHeight() const  { -	return llround(mFont->getLineHeight()); +	return mFont->getLineHeight();  } @@ -306,7 +306,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col  			break;  		}  		LLRect highlight_rect(left - 2,  -				llround(mFont->getLineHeight()) + 1,  +				mFont->getLineHeight() + 1,   				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,   				1);  		mRoundedRectImage->draw(highlight_rect, highlight_color); @@ -329,7 +329,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col  		break;  	}  	mFont->render(mText.getWString(), 0,  -					start_x, 2.f, +					start_x, 0.f,  					display_color,  					mFontAlignment,  					LLFontGL::BOTTOM,  diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index 696e4a2bb1..07a6dfaa10 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -46,10 +46,7 @@ static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid  //---------------------------------------------------------------------------  LLScrollColumnHeader::Params::Params()  :	column("column") -{ -	name  = "column_header"; -	tab_stop(false); -} +{}  LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p)  diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h index e2711ac75a..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; @@ -135,7 +135,7 @@ public:  			halign("halign", LLFontGL::LEFT)  		{  			// default choice to "dynamic_width" -			width.dynamic_width = true; +			changeDefault(width.dynamic_width, true);  			addSynonym(sort_column, "sort");  		} diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index b7848ec37c..b3e1b63db5 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -147,12 +147,9 @@ LLScrollListCtrl::Params::Params()  	highlighted_color("highlighted_color"),  	contents(""),  	scroll_bar_bg_visible("scroll_bar_bg_visible"), -	scroll_bar_bg_color("scroll_bar_bg_color") -	, border("border") -{ -	name = "scroll_list"; -	mouse_opaque = true; -} +	scroll_bar_bg_color("scroll_bar_bg_color"),  +	border("border") +{}  LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)  :	LLUICtrl(p), @@ -178,6 +175,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)  	mBorder(NULL),  	mSortCallback(NULL),  	mPopupMenu(NULL), +	mCommentTextView(NULL),  	mNumDynamicWidthColumns(0),  	mTotalStaticColumnWidth(0),  	mTotalColumnPadding(0), @@ -479,7 +477,12 @@ void LLScrollListCtrl::updateLayout()  		getRect().getWidth() - 2 * mBorderThickness,  		getRect().getHeight() - (2 * mBorderThickness ) - heading_size ); -	getChildView("comment_text")->setShape(mItemListRect); +	if (mCommentTextView == NULL) +	{ +		mCommentTextView = getChildView("comment_text"); +	} + +	mCommentTextView->setShape(mItemListRect);  	// how many lines of content in a single "page"  	S32 page_lines =  getLinesPerPage(); @@ -2501,7 +2504,7 @@ void	LLScrollListCtrl::copy()  	{  		buffer += (*itor)->getContentsCSV() + "\n";  	} -	gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); +	LLClipboard::instance().copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length());  }  // virtual @@ -2813,7 +2816,10 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS  		}  		S32 index = columnp->mIndex; -		cell_p.width.setIfNotProvided(columnp->getWidth()); +		if (!cell_p.width.isProvided()) +		{ +			cell_p.width = columnp->getWidth(); +		}  		LLScrollListCell* cell = LLScrollListCell::create(cell_p); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 09ab89960d..ae8aea9245 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -480,6 +480,8 @@ private:  	S32				mHighlightedItem;  	class LLViewBorder*	mBorder;  	LLContextMenu	*mPopupMenu; +	 +	LLView			*mCommentTextView;  	LLWString		mSearchString;  	LLFrameTimer	mSearchTimer; diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index d95752e31c..5a1e96ab03 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -138,7 +138,7 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const  		LLUI::pushMatrix();  		{ -			LLUI::translate((F32) cur_x, (F32) rect.mBottom, 0.0f); +			LLUI::translate((F32) cur_x, (F32) rect.mBottom);  			cell->draw( fg_color, highlight_color );  		} diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index 611df729b4..13655b5873 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -33,10 +33,10 @@  #include "v4color.h"  #include "llinitparam.h"  #include "llscrolllistcell.h" +#include "llcoord.h"  #include <vector> -class LLCoordGL;  class LLCheckBoxCtrl;  class LLResizeBar;  class LLScrollListCtrl; diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index 9ad13054cb..0e29873bb0 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -34,6 +34,9 @@  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; + +LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion");  //  // LLParamSDParser @@ -45,7 +48,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 +63,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 +98,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 +124,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 = &(*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 +211,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 69dab2b411..3dfc6d020e 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); @@ -83,22 +91,36 @@ private:  	LLSD*					mCurWriteSD;  }; + +extern LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR;  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); -		} +		LLFastTimer _(FTM_SD_PARAM_ADAPTOR); +		LLParamSDParser parser; +		// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it +		bool parse_silently = true; +		parser.readSD(sd, *this, parse_silently); +	} + +	operator LLSD() const +	{ +		LLParamSDParser parser; +		LLSD sd; +		parser.writeSD(sd, *this); +		return sd; +	} -		LLSDParamAdapter(const T& val) -		{ -			T::operator=(val); -		} -	}; +	LLSDParamAdapter(const T& val) +	: T(val) +	{ +		T::operator=(val); +	} +};  #endif // LL_LLSDPARAM_H diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index f5c3b532c4..c2d7916938 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -55,9 +55,7 @@ public:  			search_button_visible("search_button_visible"),  			clear_button("clear_button"),   			clear_button_visible("clear_button_visible") -		{ -			name = "search_editor"; -		} +		{}  	};  	void setCommitOnFocusLost(BOOL b)	{ if (mSearchEditor) mSearchEditor->setCommitOnFocusLost(b); } diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index 013950a5ad..db72234f94 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -54,9 +54,7 @@ LLSlider::Params::Params()  	track_highlight_vertical_image("track_highlight_vertical_image"),  	mouse_down_callback("mouse_down_callback"),  	mouse_up_callback("mouse_up_callback") -{ -	follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); -} +{}  LLSlider::LLSlider(const LLSlider::Params& p)  :	LLF32UICtrl(p), diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index d760178e35..583ed1ed2e 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -76,8 +76,14 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)  		}  		LLRect label_rect( left, top, label_width, bottom );  		LLTextBox::Params params(p.slider_label); -		params.rect.setIfNotProvided(label_rect); -		params.font.setIfNotProvided(p.font); +		if (!params.rect.isProvided()) +		{ +			params.rect = label_rect; +		} +		if (!params.font.isProvided()) +		{ +			params.font = p.font; +		}  		params.initial_value(p.label());  		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);  		addChild(mLabelBox); @@ -113,15 +119,33 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)  	S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0;  	LLSlider::Params slider_p(p.slider_bar);  	slider_p.name("slider_bar"); -	slider_p.rect.setIfNotProvided(LLRect(slider_left,top,slider_right,bottom)); -	slider_p.initial_value.setIfNotProvided(p.initial_value().asReal()); -	slider_p.min_value.setIfNotProvided(p.min_value); -	slider_p.max_value.setIfNotProvided(p.max_value); -	slider_p.increment.setIfNotProvided(p.increment); -	slider_p.orientation.setIfNotProvided(p.orientation); +	if (!slider_p.rect.isProvided()) +	{ +		slider_p.rect = LLRect(slider_left,top,slider_right,bottom); +	} +	if (!slider_p.initial_value.isProvided()) +	{ +		slider_p.initial_value = p.initial_value().asReal(); +	} +	if (!slider_p.min_value.isProvided()) +	{ +		slider_p.min_value = p.min_value; +	} +	if (!slider_p.max_value.isProvided()) +	{ +		slider_p.max_value = p.max_value; +	} +	if (!slider_p.increment.isProvided()) +	{ +		slider_p.increment = p.increment; +	} +	if (!slider_p.orientation.isProvided()) +	{ +		slider_p.orientation = p.orientation; +	} -	slider_p.commit_callback.function(&LLSliderCtrl::onSliderCommit); -	slider_p.control_name(p.control_name); +	slider_p.commit_callback.function = &LLSliderCtrl::onSliderCommit; +	slider_p.control_name = p.control_name;  	slider_p.mouse_down_callback( p.mouse_down_callback );  	slider_p.mouse_up_callback( p.mouse_up_callback );  	mSlider = LLUICtrlFactory::create<LLSlider> (slider_p); @@ -134,8 +158,15 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)  		if( p.can_edit_text() )  		{  			LLLineEditor::Params line_p(p.value_editor); -			line_p.rect.setIfNotProvided(text_rect); -			line_p.font.setIfNotProvided(p.font); +			if (!line_p.rect.isProvided()) +			{ +				line_p.rect = text_rect; +			} +			if (!line_p.font.isProvided()) +			{ +				line_p.font = p.font; +			} +			  			line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);  			line_p.prevalidate_callback(&LLTextValidate::validateFloat);  			mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); @@ -149,8 +180,14 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)  		else  		{  			LLTextBox::Params text_p(p.value_text); -			text_p.rect.setIfNotProvided(text_rect); -			text_p.font.setIfNotProvided(p.font); +			if (!text_p.rect.isProvided()) +			{ +				text_p.rect = text_rect; +			} +			if (!text_p.font.isProvided()) +			{ +				text_p.font = p.font; +			}  			mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p);  			addChild(mTextBox);  		} diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index d197084e38..87814f838e 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -96,6 +96,9 @@ public:  	void			onUpBtn(const LLSD& data);  	void			onDownBtn(const LLSD& data); +	 +	const LLColor4&	getEnabledTextColor() const	{ return mTextEnabledColor.get(); } +	const LLColor4&	getDisabledTextColor() const { return mTextDisabledColor.get(); }  private:  	void			updateLabelColor(); diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 62a9db82fe..513fff3234 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -65,7 +65,7 @@ public:  			  show_mean("show_mean", TRUE),  			  stat("stat")  		{ -			follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); +			changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT);  		}  	};  	LLStatBar(const Params&); diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h index 22a9fcd672..5abdc42448 100644 --- a/indra/llui/llstatview.h +++ b/indra/llui/llstatview.h @@ -46,7 +46,7 @@ public:  		Params()   		:	setting("setting")  		{ -			follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); +			changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT);  		}  	}; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 7f0d650403..5fc2cc350d 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -98,24 +98,25 @@ class LLCustomButtonIconCtrl : public LLButton  {  public:  	struct Params -	: public LLInitParam::Block<Params, LLButton::Params> +	:	public LLInitParam::Block<Params, LLButton::Params>  	{  		// LEFT, RIGHT, TOP, BOTTOM paddings of LLIconCtrl in this class has same value  		Optional<S32>					icon_ctrl_pad; -		Params(): -		icon_ctrl_pad("icon_ctrl_pad", 1) +		Params() +		:	icon_ctrl_pad("icon_ctrl_pad", 1)  		{}  	};  protected:  	friend class LLUICtrlFactory; -	LLCustomButtonIconCtrl(const Params& p): -		LLButton(p), + +	LLCustomButtonIconCtrl(const Params& p) +	:	LLButton(p),  		mIcon(NULL),  		mIconAlignment(LLFontGL::HCENTER),  		mIconCtrlPad(p.icon_ctrl_pad) -		{} +	{}  public: @@ -214,13 +215,11 @@ LLTabContainer::Params::Params()  	middle_tab("middle_tab"),  	last_tab("last_tab"),  	use_custom_icon_ctrl("use_custom_icon_ctrl", false), +	open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false),  	tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),  	use_ellipses("use_ellipses"),  	font_halign("halign") -{ -	name(std::string("tab_container")); -	mouse_opaque = false; -} +{}  LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)  :	LLPanel(p), @@ -253,6 +252,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)  	mMiddleTabParams(p.middle_tab),  	mLastTabParams(p.last_tab),  	mCustomIconCtrlUsed(p.use_custom_icon_ctrl), +	mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop),  	mTabIconCtrlPad(p.tab_icon_ctrl_pad),  	mUseTabEllipses(p.use_ellipses)  { @@ -551,23 +551,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 ) )  		{ @@ -684,7 +684,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); @@ -815,48 +815,62 @@ 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(mOpenTabsOnDragAndDrop && !getTabsHidden())  	{ -		if (has_scroll_arrows) +		// In that case, we'll open the hovered tab while dragging and dropping items. +		// This allows for drilling through tabs. +		if (mDragAndDropDelayTimer.getStarted())  		{ -			if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) -			{ -				S32	local_x	= x	- mJumpPrevArrowBtn->getRect().mLeft; -				S32	local_y	= y	- mJumpPrevArrowBtn->getRect().mBottom; -				mJumpPrevArrowBtn->handleHover(local_x,	local_y, mask); -			} -			if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) +			if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME)  			{ -				S32	local_x	= x	- mJumpNextArrowBtn->getRect().mLeft; -				S32	local_y	= y	- mJumpNextArrowBtn->getRect().mBottom; -				mJumpNextArrowBtn->handleHover(local_x,	local_y, mask); -			} -			if (mPrevArrowBtn->getRect().pointInRect(x,	y)) -			{ -				S32	local_x	= x	- mPrevArrowBtn->getRect().mLeft; -				S32	local_y	= y	- mPrevArrowBtn->getRect().mBottom; -				mPrevArrowBtn->handleHover(local_x,	local_y, mask); -			} -			else if	(mNextArrowBtn->getRect().pointInRect(x, y)) -			{ -				S32	local_x	= x	- mNextArrowBtn->getRect().mLeft; -				S32	local_y	= y	- mNextArrowBtn->getRect().mBottom; -				mNextArrowBtn->handleHover(local_x, local_y, mask); -			} -		} +				if (has_scroll_arrows) +				{ +					if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) +					{ +						S32	local_x	= x	- mJumpPrevArrowBtn->getRect().mLeft; +						S32	local_y	= y	- mJumpPrevArrowBtn->getRect().mBottom; +						mJumpPrevArrowBtn->handleHover(local_x,	local_y, mask); +					} +					if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) +					{ +						S32	local_x	= x	- mJumpNextArrowBtn->getRect().mLeft; +						S32	local_y	= y	- mJumpNextArrowBtn->getRect().mBottom; +						mJumpNextArrowBtn->handleHover(local_x,	local_y, mask); +					} +					if (mPrevArrowBtn->getRect().pointInRect(x,	y)) +					{ +						S32	local_x	= x	- mPrevArrowBtn->getRect().mLeft; +						S32	local_y	= y	- mPrevArrowBtn->getRect().mBottom; +						mPrevArrowBtn->handleHover(local_x,	local_y, mask); +					} +					else if	(mNextArrowBtn->getRect().pointInRect(x, y)) +					{ +						S32	local_x	= x	- mNextArrowBtn->getRect().mLeft; +						S32	local_y	= y	- mNextArrowBtn->getRect().mBottom; +						mNextArrowBtn->handleHover(local_x, local_y, mask); +					} +				} -		for(tuple_list_t::iterator iter	= mTabList.begin();	iter !=	 mTabList.end(); ++iter) -		{ -			LLTabTuple*	tuple =	*iter; -			tuple->mButton->setVisible(	TRUE ); -			S32	local_x	= x	- tuple->mButton->getRect().mLeft; -			S32	local_y	= y	- tuple->mButton->getRect().mBottom; -			if (tuple->mButton->pointInView(local_x, local_y) &&  tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) -			{ -				tuple->mButton->onCommit(); +				for(tuple_list_t::iterator iter	= mTabList.begin();	iter !=	 mTabList.end(); ++iter) +				{ +					LLTabTuple*	tuple =	*iter; +					tuple->mButton->setVisible(	TRUE ); +					S32	local_x	= x	- tuple->mButton->getRect().mLeft; +					S32	local_y	= y	- tuple->mButton->getRect().mBottom; +					if (tuple->mButton->pointInView(local_x, local_y) &&  tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) +					{ +						tuple->mButton->onCommit(); +					} +				} +				// Stop the timer whether successful or not. Don't let it run forever.  				mDragAndDropDelayTimer.stop();  			}  		} +		else  +		{ +			// Start a timer so we don't open tabs as soon as we hover on them +			mDragAndDropDelayTimer.start(); +		}  	}  	return LLView::handleDragAndDrop(x,	y, mask, drop, type, cargo_data,  accept, tooltip); @@ -1026,85 +1040,50 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  	}  	else  	{ +		LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params); +		 +		p.rect(btn_rect); +		p.font(mFont); +		p.font_halign = mFontHalign; +		p.label(trimmed_label); +		p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); +		if (indent) +		{ +			p.pad_left(indent); +		} +		p.pad_bottom( mLabelPadBottom ); +		p.scale_image(true); +		p.tab_stop(false); +		p.label_shadow(false); +		p.follows.flags = FOLLOWS_LEFT; +		  		if (mIsVertical)  		{ -			LLButton::Params& p = (mCustomIconCtrlUsed)? -					custom_btn_params:normal_btn_params; -  			p.name(std::string("vert tab button")); -			p.rect(btn_rect); -			p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); -			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(mFont); -			p.label(trimmed_label);  			p.image_unselected(mMiddleTabParams.tab_left_image_unselected);  			p.image_selected(mMiddleTabParams.tab_left_image_selected); -			p.scale_image(true); -			p.font_halign = mFontHalign; -			p.pad_bottom( mLabelPadBottom ); -			p.tab_stop(false); -			p.label_shadow(false); -			if (indent) -			{ -				p.pad_left(indent); -			} -			 -			 -			if(mCustomIconCtrlUsed) -			{ -				btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); -				 -			} -			else -			{ -				btn = LLUICtrlFactory::create<LLButton>(p); -			} +			p.follows.flags = p.follows.flags() | FOLLOWS_TOP;  		}  		else  		{ -			LLButton::Params& p = (mCustomIconCtrlUsed)? -					custom_btn_params:normal_btn_params;  			p.name(std::string(child->getName()) + " tab"); -			p.rect(btn_rect); -			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(mFont); -			p.label(trimmed_label);  			p.visible(false); -			p.scale_image(true);  			p.image_unselected(tab_img);  			p.image_selected(tab_selected_img); -			p.tab_stop(false); -			p.label_shadow(false); +			p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);  			// Try to squeeze in a bit more text  			p.pad_left( mLabelPadLeft );  			p.pad_right(2); -			p.pad_bottom( mLabelPadBottom ); -			p.font_halign = mFontHalign; -			p.follows.flags = FOLLOWS_LEFT; -			p.follows.flags = FOLLOWS_LEFT; -	 -			if (indent) -			{ -				p.pad_left(indent); -			} - -			if( getTabPosition() == TOP ) -			{ -				p.follows.flags = p.follows.flags() | FOLLOWS_TOP; -			} -			else -			{ -				p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM; -			} - -			if(mCustomIconCtrlUsed) -			{ -				btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); -			} -			else -			{ -				btn = LLUICtrlFactory::create<LLButton>(p); -			} +		} +		 +		// *TODO : It seems wrong not to use p in both cases considering the way p is initialized +		if (mCustomIconCtrlUsed) +		{ +			btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); +		} +		else +		{ +			btn = LLUICtrlFactory::create<LLButton>(p);  		}  	} @@ -1281,6 +1260,10 @@ void LLTabContainer::enableTabButton(S32 which, BOOL enable)  	{  		mTabList[which]->mButton->setEnabled(enable);  	} +	// Stop the DaD timer as it might run forever +	// enableTabButton() is typically called on refresh and draw when anything changed +	// in the tab container so it's a good time to reset that. +	mDragAndDropDelayTimer.stop();  }  void LLTabContainer::deleteAllTabs() diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index eaa2fd54e0..cebace2ceb 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -105,6 +105,11 @@ public:  		Optional<bool>						use_custom_icon_ctrl;  		/** +		 * Open tabs on hover in drag and drop situations +		 */ +		Optional<bool>						open_tabs_on_drag_and_drop; +		 +		/**  		 *  Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true)  		 */  		Optional<S32>						tab_icon_ctrl_pad; @@ -300,6 +305,7 @@ private:  	TabParams						mLastTabParams;  	bool							mCustomIconCtrlUsed; +	bool							mOpenTabsOnDragAndDrop;  	S32								mTabIconCtrlPad;  	bool							mUseTabEllipses;  }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 349dbc3405..7aeeae298f 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -598,7 +598,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s  	pos = getEditableIndex(pos, true); -	segment_set_t::iterator seg_iter = getSegIterContaining(pos); +	segment_set_t::iterator seg_iter = getEditableSegIterContaining(pos);  	LLTextSegmentPtr default_segment; @@ -1192,7 +1192,10 @@ void LLTextBase::reflow()  		// shrink document to minimum size (visible portion of text widget)  		// to force inlined widgets with follows set to shrink -		mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); +		if (mWordWrap) +		{ +			mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); +		}  		S32 cur_top = 0; @@ -1510,8 +1513,48 @@ void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg  	}  } +LLTextBase::segment_set_t::iterator LLTextBase::getEditableSegIterContaining(S32 index) +{ +	segment_set_t::iterator it = getSegIterContaining(index); +	segment_set_t::iterator orig_it = it; + +	if (it == mSegments.end()) return it; + +	if (!(*it)->canEdit()  +		&& index == (*it)->getStart()  +		&& it != mSegments.begin()) +	{ +		it--; +		if ((*it)->canEdit()) +		{ +			return it; +		} +	} +	return orig_it; +} + +LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaining(S32 index) const +{ +	segment_set_t::const_iterator it = getSegIterContaining(index); +	segment_set_t::const_iterator orig_it = it; +	if (it == mSegments.end()) return it; + +	if (!(*it)->canEdit()  +		&& index == (*it)->getStart()  +		&& it != mSegments.begin()) +	{ +		it--; +		if ((*it)->canEdit()) +		{ +			return it; +		} +	} +	return orig_it; +} +  LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)  { +  	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();  	if (index > getLength()) { return mSegments.end(); } @@ -2024,8 +2067,17 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,  		}  		else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd)  		{ -			// segment wraps to next line, so just set doc pos to the end of the line -			pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength()); +			if (getLineNumFromDocIndex(line_iter->mDocIndexEnd - 1) == line_iter->mLineNum) +			{ +				// if segment wraps to the next line we should step one char back +				// to compensate for the space char between words +				// which is removed due to wrapping +				pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength()); +			} +			else +			{ +				pos = llclamp(line_iter->mDocIndexEnd, 0, getLength()); +			}  			break;  		}  		start_x += text_width; @@ -2108,7 +2160,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const  	{   		// return default height rect in upper left  		local_rect = content_window_rect; -		local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight()); +		local_rect.mBottom = local_rect.mTop - mDefaultFont->getLineHeight();  		return local_rect;  	} @@ -2331,6 +2383,9 @@ S32 LLTextBase::getEditableIndex(S32 index, bool increasing_direction)  void LLTextBase::updateRects()  { +	LLRect old_text_rect = mVisibleTextRect; +	mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); +  	if (mLineInfoList.empty())   	{  		mTextBoundingRect = LLRect(0, mVPad, mHPad, 0); @@ -2346,10 +2401,24 @@ void LLTextBase::updateRects()  		}  		mTextBoundingRect.mTop += mVPad; -		// subtract a pixel off the bottom to deal with rounding errors in measuring font height -		mTextBoundingRect.mBottom -= 1; -		S32 delta_pos = -mTextBoundingRect.mBottom; +		S32 delta_pos = 0; +		 +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); +			break; +		case LLFontGL::VCENTER: +			delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; +			break; +		case LLFontGL::BOTTOM: +			delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; +			break; +		case LLFontGL::BASELINE: +			// do nothing +			break; +		}  		// move line segments to fit new document rect  		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)  		{ @@ -2359,8 +2428,9 @@ void LLTextBase::updateRects()  	}  	// update document container dimensions according to text contents -	LLRect doc_rect = mTextBoundingRect; +	LLRect doc_rect;  	// use old mVisibleTextRect constraint document to width of viewable region +	doc_rect.mBottom = llmin(mVisibleTextRect.mBottom,  mTextBoundingRect.mBottom);  	doc_rect.mLeft = 0;  	// allow horizontal scrolling? @@ -2370,11 +2440,22 @@ void LLTextBase::updateRects()  	doc_rect.mRight = mScroller   		? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)  		: mVisibleTextRect.getWidth(); +	doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop);  	if (!mScroller)  	{  		// push doc rect to top of text widget -		doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +			break; +		case LLFontGL::VCENTER: +			doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); +		case LLFontGL::BOTTOM: +		default: +			break; +		}  	}  	mDocumentView->setShape(doc_rect); @@ -2382,7 +2463,6 @@ void LLTextBase::updateRects()  	//update mVisibleTextRect *after* mDocumentView has been resized  	// so that scrollbars are added if document needs to scroll  	// since mVisibleTextRect does not include scrollbars -	LLRect old_text_rect = mVisibleTextRect;  	mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();  	//FIXME: replace border with image?  	if (mBorderVisible) @@ -2395,9 +2475,27 @@ void LLTextBase::updateRects()  	}  	// update document container again, using new mVisibleTextRect (that has scrollbars enabled as needed) +	doc_rect.mBottom = llmin(mVisibleTextRect.mBottom,  mTextBoundingRect.mBottom); +	doc_rect.mLeft = 0;  	doc_rect.mRight = mScroller   		? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)  		: mVisibleTextRect.getWidth(); +	doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop); +	if (!mScroller) +	{ +		// push doc rect to top of text widget +		switch(mVAlign) +		{ +		case LLFontGL::TOP: +			doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); +			break; +		case LLFontGL::VCENTER: +			doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); +		case LLFontGL::BOTTOM: +		default: +			break; +		} +	}  	mDocumentView->setShape(doc_rect);  } @@ -2509,7 +2607,10 @@ BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }  BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; }  BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }  BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; } -std::string	LLTextSegment::getName() const { return ""; } +const std::string&	LLTextSegment::getName() const  +{ +	return LLStringUtil::null; +}  void LLTextSegment::onMouseCaptureLost() {}  void LLTextSegment::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {}  void LLTextSegment::localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const {} @@ -2525,7 +2626,7 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e  	mToken(NULL),  	mEditor(editor)  { -	mFontHeight = llceil(mStyle->getFont()->getLineHeight()); +	mFontHeight = mStyle->getFont()->getLineHeight();  	LLUIImagePtr image = mStyle->getImage();  	if (image.notNull()) @@ -2541,7 +2642,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32  {  	mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); -	mFontHeight = llceil(mStyle->getFont()->getLineHeight()); +	mFontHeight = mStyle->getFont()->getLineHeight();  }  LLNormalTextSegment::~LLNormalTextSegment() @@ -2909,11 +3010,11 @@ LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1)  {  	LLStyleSP s( new LLStyle(LLStyle::Params().visible(true))); -	mFontHeight = llceil(s->getFont()->getLineHeight()); +	mFontHeight = s->getFont()->getLineHeight();  }  LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1)  { -	mFontHeight = llceil(style->getFont()->getLineHeight()); +	mFontHeight = style->getFont()->getLineHeight();  }  LLLineBreakTextSegment::~LLLineBreakTextSegment()  { @@ -2950,7 +3051,7 @@ static const S32 IMAGE_HPAD = 3;  bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const  {  	width = 0; -	height = llceil(mStyle->getFont()->getLineHeight());; +	height = mStyle->getFont()->getLineHeight();  	LLUIImagePtr image = mStyle->getImage();  	if( num_chars>0 && image.notNull()) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 7d545a1ba6..0549141b72 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -84,7 +84,7 @@ public:  	/*virtual*/ BOOL			handleHover(S32 x, S32 y, MASK mask);  	/*virtual*/ BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks);  	/*virtual*/ BOOL			handleToolTip(S32 x, S32 y, MASK mask); -	/*virtual*/ std::string		getName() const; +	/*virtual*/ const std::string&	getName() const;  	/*virtual*/ void			onMouseCaptureLost();  	/*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; @@ -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; @@ -461,6 +461,8 @@ protected:  	void                			getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const;  	void                			getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp );  	LLTextSegmentPtr    			getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line = true); +	segment_set_t::iterator			getEditableSegIterContaining(S32 index); +	segment_set_t::const_iterator	getEditableSegIterContaining(S32 index) const;  	segment_set_t::iterator			getSegIterContaining(S32 index);  	segment_set_t::const_iterator	getSegIterContaining(S32 index) const;  	void                			clearSegments(); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 9bd445988d..9720dded6c 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1332,7 +1332,7 @@ void LLTextEditor::cut()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID ); +	LLClipboard::instance().copyToClipboard( getWText(), left_pos, length);  	deleteSelection( FALSE );  	onKeyStroke(); @@ -1352,12 +1352,12 @@ void LLTextEditor::copy()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromSubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length);  }  BOOL LLTextEditor::canPaste() const  { -	return !mReadOnly && gClipboard.canPasteString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable();  }  // paste from clipboard @@ -1393,16 +1393,8 @@ void LLTextEditor::pasteHelper(bool is_primary)  		return;  	} -	LLUUID source_id;  	LLWString paste; -	if (is_primary) -	{ -		paste = gClipboard.getPastePrimaryWString(&source_id); -	} -	else  -	{ -		paste = gClipboard.getPasteWString(&source_id); -	} +	LLClipboard::instance().pasteFromClipboard(paste, is_primary);  	if (paste.empty())  	{ @@ -1475,12 +1467,12 @@ void LLTextEditor::copyPrimary()  	}  	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );  	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	gClipboard.copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID); +	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true);  }  BOOL LLTextEditor::canPastePrimary() const  { -	return !mReadOnly && gClipboard.canPastePrimaryString(); +	return !mReadOnly && LLClipboard::instance().isTextAvailable(true);  }  void LLTextEditor::updatePrimary() @@ -1992,7 +1984,7 @@ void LLTextEditor::drawPreeditMarker()  		return;  	} -	const S32 line_height = llround( mDefaultFont->getLineHeight() ); +	const S32 line_height = mDefaultFont->getLineHeight();  	S32 line_start = getLineStart(cur_line);  	S32 line_y = mVisibleTextRect.mTop - line_height; @@ -2250,6 +2242,22 @@ void LLTextEditor::insertText(const std::string &new_text)  	setEnabled( enabled );  } +void LLTextEditor::insertText(LLWString &new_text) +{ +	BOOL enabled = getEnabled(); +	setEnabled( TRUE ); + +	// Delete any selected characters (the insertion replaces them) +	if( hasSelection() ) +	{ +		deleteSelection(TRUE); +	} + +	setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + +	setEnabled( enabled ); +} +  void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)  {  	// Save old state @@ -2699,7 +2707,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect      const LLWString textString(getWText());  	const llwchar * const text = textString.c_str(); -	const S32 line_height = llround(mDefaultFont->getLineHeight()); +	const S32 line_height = mDefaultFont->getLineHeight();  	if (coord)  	{ @@ -2802,7 +2810,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length)  S32 LLTextEditor::getPreeditFontSize() const  { -	return llround(mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); +	return llround((F32)mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);  }  BOOL LLTextEditor::isDirty() const @@ -2838,3 +2846,13 @@ void LLTextEditor::clear()  	getViewModel()->setDisplay(LLWStringUtil::null);  	clearSegments();  } + +bool LLTextEditor::canLoadOrSaveToFile() +{ +	return !mReadOnly; +} + +S32 LLTextEditor::spacesPerTab() +{ +	return SPACES_PER_TAB; +} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 9e4b95003b..40821ae9fb 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -92,6 +92,8 @@ public:  	void	setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} +	static S32		spacesPerTab(); +  	// mousehandler overrides  	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);  	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); @@ -140,6 +142,8 @@ public:  	virtual void	selectAll();  	virtual BOOL	canSelectAll()	const; +	virtual bool	canLoadOrSaveToFile(); +  	void			selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE);  	BOOL			replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE);  	void			replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); @@ -158,6 +162,7 @@ public:  	// inserts text at cursor  	void			insertText(const std::string &text); +	void			insertText(LLWString &text);  	void			appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);  	// Non-undoable diff --git a/indra/llui/lltextparser.cpp b/indra/llui/lltextparser.cpp index a4fe4f6ca8..8a85f99e0c 100644 --- a/indra/llui/lltextparser.cpp +++ b/indra/llui/lltextparser.cpp @@ -46,8 +46,6 @@ LLTextParser::LLTextParser()  {} -// Moved triggerAlerts() to llfloaterchat.cpp to break llui/llaudio library dependency. -  S32 LLTextParser::findPattern(const std::string &text, LLSD highlight)  {  	if (!highlight.has("pattern")) return -1; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp new file mode 100644 index 0000000000..81ea0ebf0c --- /dev/null +++ b/indra/llui/lltoolbar.cpp @@ -0,0 +1,1230 @@ +/**  + * @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(), +	mRightMouseTargetButton(NULL), +	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)); +		commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this)); + +		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg; +		enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2)); + +		// Create the context menu +		LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + +		if (menu) +		{ +			menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); +			mPopupMenuHandle = menu->getHandle(); +			mRemoveButtonHandle = menu->getChild<LLView>("Remove button")->getHandle(); +		} +		else +		{ +			llwarns << "Unable to load toolbars context menu." << llendl; +		} +	} +	 +	if (mRemoveButtonHandle.get()) +	{ +		// Disable/Enable the "Remove button" menu item depending on whether or not a button was clicked +		mRemoveButtonHandle.get()->setEnabled(mRightMouseTargetButton != NULL); +	} +} + +void LLToolBar::initFromParams(const LLToolBar::Params& p) +{ +	// Initialize the base object +	LLUICtrl::initFromParams(p); +	 +	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) +	{ +		// Determine which button the mouse was over during the click in case the context menu action +		// is intended to affect the button. +		mRightMouseTargetButton = NULL; +		BOOST_FOREACH(LLToolBarButton* button, mButtons) +		{ +			LLRect button_rect; +			button->localRectToOtherView(button->getLocalRect(), &button_rect, this); + +			if (button_rect.pointInRect(x, y)) +			{ +				mRightMouseTargetButton = button; +				break; +			} +		} + +		createContextMenu(); + +		LLContextMenu * menu = (LLContextMenu *) mPopupMenuHandle.get(); + +		if (menu) +		{ +			menu->show(x, y); + +			LLMenuGL::showPopup(this, menu, x, y); +		} +	} + +	return handle_it_here; +} + +BOOL LLToolBar::isSettingChecked(const LLSD& userdata) +{ +	BOOL retval = FALSE; + +	const std::string setting_name = userdata.asString(); + +	if (setting_name == "icons_with_text") +	{ +		retval = (mButtonType == BTNTYPE_ICONS_WITH_TEXT); +	} +	else if (setting_name == "icons_only") +	{ +		retval = (mButtonType == BTNTYPE_ICONS_ONLY); +	} + +	return retval; +} + +void LLToolBar::onSettingEnable(const LLSD& userdata) +{ +	llassert(!mReadOnly); + +	const std::string setting_name = userdata.asString(); + +	if (setting_name == "icons_with_text") +	{ +		setButtonType(BTNTYPE_ICONS_WITH_TEXT); +	} +	else if (setting_name == "icons_only") +	{ +		setButtonType(BTNTYPE_ICONS_ONLY); +	} +} + +void LLToolBar::onRemoveSelectedCommand() +{ +	llassert(!mReadOnly); + +	if (mRightMouseTargetButton) +	{ +		removeCommand(mRightMouseTargetButton->getCommandId()); + +		mRightMouseTargetButton = NULL; +	} +} + +void LLToolBar::setButtonType(LLToolBarEnums::ButtonType button_type) +{ +	bool regenerate_buttons = (mButtonType != button_type); +	 +	mButtonType = button_type; + +	if (regenerate_buttons) +	{ +		createButtons(); +	} +} + +void LLToolBar::resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth) +{ +	// make buttons in current row all same girth +	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(); + +	if (!mButtons.empty()) +	{ +		mButtonPanel->setVisible(TRUE); +		mButtonPanel->setMouseOpaque(TRUE); +	} + +	// don't clear flag until after we've resized ourselves, to avoid laying out every frame +	mNeedsLayout = false; +} + + +void LLToolBar::draw() +{ +	if (mButtons.empty()) +	{ +		mButtonPanel->setVisible(FALSE); +		mButtonPanel->setMouseOpaque(FALSE); +	} +	else +	{ +		mButtonPanel->setVisible(TRUE); +		mButtonPanel->setMouseOpaque(TRUE); +	} + +	// Update enable/disable state and highlight state for editable toolbars +	if (!mReadOnly) +	{ +		for (toolbar_button_list::iterator btn_it = mButtons.begin(); btn_it != mButtons.end(); ++btn_it) +		{ +			LLToolBarButton* btn = *btn_it; +			LLCommand* command = LLCommandManager::instance().getCommand(btn->mId); + +			if (command && btn->mIsEnabledSignal) +			{ +				const bool button_command_enabled = (*btn->mIsEnabledSignal)(btn, command->isEnabledParameters()); +				btn->setEnabled(button_command_enabled); +			} + +			if (command && btn->mIsRunningSignal) +			{ +				const bool button_command_running = (*btn->mIsRunningSignal)(btn, command->isRunningParameters()); +				btn->setToggleState(button_command_running); +			} +		} +	} + +	updateLayoutAsNeeded(); +	// rect may have shifted during layout +	LLUI::popMatrix(); +	LLUI::pushMatrix(); +	LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); + +	// Position the caret  +	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(); +	mRightMouseTargetButton = NULL; +	 +	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..a50c60282c --- /dev/null +++ b/indra/llui/lltoolbar.h @@ -0,0 +1,290 @@ +/**  + * @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; } +	LLCommandId getCommandId() { return mId; } + +	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; + +		// default command set +		Multiple<LLCommandId::Params>			commands; + +		Optional<LLPanel::Params>				button_panel; + +		Params(); +	}; + +	// virtuals +	void draw(); +	void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); +	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;	// is this command bound to a button in this toolbar +	bool enableCommand(const LLCommandId& commandId, bool enabled);	// enable/disable button bound to the specified command, if it exists in this toolbar +	bool stopCommandInProgress(const LLCommandId& commandId);	// stop command if it is currently active +	bool flashCommand(const LLCommandId& commandId, bool flash); // flash button associated with given command, if in this toolbar + +	void setStartDragCallback(tool_startdrag_callback_t cb)   { mStartDragItemCallback  = cb; } // connects drag and drop behavior to external logic +	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); + +	// append the specified string to end of tooltip +	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; } + +	int  getRankFromPosition(S32 x, S32 y);	 +	int  getRankFromPosition(const LLCommandId& id);	 + +	// 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: +	friend class LLUICtrlFactory; +	LLToolBar(const Params&); +	~LLToolBar(); + +	void initFromParams(const Params&); +	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); +	void onRemoveSelectedCommand(); + +private: +	// static layout state +	const bool						mReadOnly; +	const LLToolBarEnums::SideType	mSideType; +	const bool						mWrap; +	const S32						mPadLeft, +									mPadRight, +									mPadTop, +									mPadBottom, +									mPadBetween, +									mMinGirth; + +	// drag and drop state +	tool_startdrag_callback_t		mStartDragItemCallback; +	tool_handledrag_callback_t		mHandleDragItemCallback; +	tool_handledrop_callback_t		mHandleDropCallback; +	bool							mDragAndDropTarget; +	int								mDragRank; +	S32								mDragx, +									mDragy, +									mDragGirth; + +	typedef std::list<LLToolBarButton*> toolbar_button_list; +	typedef std::map<LLUUID, LLToolBarButton*> command_id_map; +	toolbar_button_list				mButtons; +	command_id_list_t				mButtonCommands; +	command_id_map					mButtonMap; + +	LLToolBarEnums::ButtonType		mButtonType; +	LLToolBarButton::Params			mButtonParams[LLToolBarEnums::BTNTYPE_COUNT]; + +	// related widgets +	LLLayoutStack*					mCenteringStack; +	LLPanel*						mButtonPanel; +	LLHandle<class LLContextMenu>	mPopupMenuHandle; +	LLHandle<class LLView>			mRemoveButtonHandle; + +	LLToolBarButton*				mRightMouseTargetButton; + +	bool							mNeedsLayout; +	bool							mModified; + +	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 6390039794..f737d48abf 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -55,7 +55,7 @@ static LLDefaultChildRegistry::Register<LLToolTipView> register_tooltip_view("to  LLToolTipView::Params::Params()  { -	mouse_opaque = false; +	changeDefault(mouse_opaque, false);  }  LLToolTipView::LLToolTipView(const LLToolTipView::Params& p) @@ -156,7 +156,7 @@ LLToolTip::Params::Params()  	web_based_media("web_based_media", false),  	media_playing("media_playing", false)  { -	chrome = true; +	changeDefault(chrome, true);  }  LLToolTip::LLToolTip(const LLToolTip::Params& p) @@ -180,6 +180,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  	params.font = p.font;  	params.use_ellipses = true;  	params.wrap = p.wrap; +	params.font_valign = LLFontGL::VCENTER;  	params.parse_urls = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips  	mTextBox = LLUICtrlFactory::create<LLTextBox> (params);  	addChild(mTextBox); @@ -190,7 +191,6 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  	{  		LLButton::Params icon_params;  		icon_params.name = "tooltip_info"; -		icon_params.label(""); // provid label but set to empty so name does not overwrite it -angela  		LLRect icon_rect;  		LLUIImage* imagep = p.image;  		TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16); @@ -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())  		{ @@ -291,6 +291,12 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth());  	S32 text_height = mTextBox->getTextPixelHeight();  	mTextBox->reshape(text_width, text_height); +	if (mInfoButton) +	{ +		LLRect text_rect = mTextBox->getRect(); +		LLRect icon_rect = mInfoButton->getRect(); +		mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY()); +	}  	// reshape tooltip panel to fit text box  	LLRect tooltip_rect = calcBoundingRect(); @@ -299,6 +305,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	tooltip_rect.mBottom = 0;  	tooltip_rect.mLeft = 0; +	mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); +  	setShape(tooltip_rect);  } @@ -402,12 +410,12 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)  	LLToolTip::Params tooltip_params(params);  	// block mouse events if there is a click handler registered (specifically, hover) -	if (params.click_callback.isProvided()) +	if (params.click_callback.isProvided() && !params.mouse_opaque.isProvided())  	{  		// set mouse_opaque to true if it wasn't already set to something else  		// this prevents mouse down from going "through" the tooltip and ultimately  		// causing the tooltip to disappear -		tooltip_params.mouse_opaque.setIfNotProvided(true); +		tooltip_params.mouse_opaque = true;  	}  	tooltip_params.rect = LLRect (0, 1, 1, 0); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 8020ca802b..b5e27616b7 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,14 +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 @@ -104,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  	{ @@ -115,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;	  			}  		} @@ -128,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);  		} @@ -151,11 +153,11 @@ void gl_state_for_2d(S32 width, S32 height)  	F32 window_width = (F32) width;//gViewerWindow->getWindowWidth();  	F32 window_height = (F32) height;//gViewerWindow->getWindowHeight(); -	glMatrixMode(GL_PROJECTION); -	glLoadIdentity(); -	glOrtho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f); -	glMatrixMode(GL_MODELVIEW); -	glLoadIdentity(); +	gGL.matrixMode(LLRender::MM_PROJECTION); +	gGL.loadIdentity(); +	gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f); +	gGL.matrixMode(LLRender::MM_MODELVIEW); +	gGL.loadIdentity();  	stop_glerror();  } @@ -472,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); @@ -524,11 +526,18 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex  	if (solid_color)  	{ -		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); -		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); +		if (LLGLSLShader::sNoFixedFunction) +		{ +			gSolidColorProgram.bind(); +		} +		else +		{ +			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); +			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); +		}  	} -	gGL.getTexUnit(0)->bind(image); +	gGL.getTexUnit(0)->bind(image, true);  	gGL.color4fv(color.mV); @@ -699,7 +708,14 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex  	if (solid_color)  	{ -		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +		if (LLGLSLShader::sNoFixedFunction) +		{ +			gUIProgram.bind(); +		} +		else +		{ +			gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +		}  	}  } @@ -719,7 +735,7 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre  	LLGLSUIDefault gls_ui; -	gGL.getTexUnit(0)->bind(image); +	gGL.getTexUnit(0)->bind(image, true);  	gGL.color4fv(color.mV); @@ -772,7 +788,7 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre  		LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD); -		gGL.getTexUnit(0)->bind(image); +		gGL.getTexUnit(0)->bind(image, true);  		gGL.color4fv(color.mV); @@ -939,10 +955,12 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor  		if( render_center )  		{  			gGL.color4fv(center_color.mV); +			gGL.diffuseColor4fv(center_color.mV);  			gl_deep_circle( radius, width, steps );  		}  		else  		{ +			gGL.diffuseColor4fv(side_color.mV);  			gl_washer_2d(radius, radius - width, steps, side_color, side_color);  			gGL.translateUI(0.f, 0.f, width);  			gl_washer_2d(radius - width, radius, steps, side_color, side_color); @@ -954,35 +972,53 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor  // Draw gray and white checkerboard with black border  void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)  { -	// Initialize the first time this is called. -	const S32 PIXELS = 32; -	static GLubyte checkerboard[PIXELS * PIXELS]; -	static BOOL first = TRUE; -	if( first ) -	{ -		for( S32 i = 0; i < PIXELS; i++ ) +	if (!LLGLSLShader::sNoFixedFunction) +	{  +		// Initialize the first time this is called. +		const S32 PIXELS = 32; +		static GLubyte checkerboard[PIXELS * PIXELS]; +		static BOOL first = TRUE; +		if( first )  		{ -			for( S32 j = 0; j < PIXELS; j++ ) +			for( S32 i = 0; i < PIXELS; i++ )  			{ -				checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; +				for( S32 j = 0; j < PIXELS; j++ ) +				{ +					checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; +				}  			} +			first = FALSE;  		} -		first = FALSE; -	} -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -	// ...white squares -	gGL.color4f( 1.f, 1.f, 1.f, alpha ); -	gl_rect_2d(rect); +		// ...white squares +		gGL.color4f( 1.f, 1.f, 1.f, alpha ); +		gl_rect_2d(rect); -	// ...gray squares -	gGL.color4f( .7f, .7f, .7f, alpha ); -	gGL.flush(); -	glPolygonStipple( checkerboard ); +		// ...gray squares +		gGL.color4f( .7f, .7f, .7f, alpha ); +		gGL.flush(); + +		glPolygonStipple( checkerboard ); + +		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE); +		gl_rect_2d(rect); +	} +	else +	{ //polygon stipple is deprecated, use "Checker" texture +		LLPointer<LLUIImage> img = LLUI::getUIImage("Checker"); +		gGL.getTexUnit(0)->bind(img->getImage()); +		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); +		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); -	LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE); -	gl_rect_2d(rect); +		LLColor4 color(1.f, 1.f, 1.f, alpha); +		LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); + +		gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), +			img->getImage(), color, uv_rect); +	} +	  	gGL.flush();  } @@ -1600,16 +1636,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 @@ -1618,8 +1654,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() @@ -1658,21 +1698,22 @@ void LLUI::translate(F32 x, F32 y, F32 z)  	gGL.translateUI(x,y,z);  	LLFontGL::sCurOrigin.mX += (S32) x;  	LLFontGL::sCurOrigin.mY += (S32) y; -	LLFontGL::sCurOrigin.mZ += z; +	LLFontGL::sCurDepth += z;  }  //static  void LLUI::pushMatrix()  {  	gGL.pushUIMatrix(); -	LLFontGL::sOriginStack.push_back(LLFontGL::sCurOrigin); +	LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth));  }  //static  void LLUI::popMatrix()  {  	gGL.popUIMatrix(); -	LLFontGL::sCurOrigin = *LLFontGL::sOriginStack.rbegin(); +	LLFontGL::sCurOrigin = LLFontGL::sOriginStack.back().first; +	LLFontGL::sCurDepth = LLFontGL::sOriginStack.back().second;  	LLFontGL::sOriginStack.pop_back();  } @@ -1682,7 +1723,7 @@ void LLUI::loadIdentity()  	gGL.loadUIIdentity();   	LLFontGL::sCurOrigin.mX = 0;  	LLFontGL::sCurOrigin.mY = 0; -	LLFontGL::sCurOrigin.mZ = 0; +	LLFontGL::sCurDepth = 0.f;  }  //static @@ -1705,10 +1746,7 @@ void LLUI::setMousePositionScreen(S32 x, S32 y)  	screen_x = llround((F32)x * sGLScaleFactor.mV[VX]);  	screen_y = llround((F32)y * sGLScaleFactor.mV[VY]); -	LLCoordWindow window_point; -	LLView::getWindow()->convertCoords(LLCoordGL(screen_x, screen_y), &window_point); - -	LLView::getWindow()->setCursorPosition(window_point); +	LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert());  }  //static  @@ -1716,8 +1754,7 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y)  {  	LLCoordWindow cursor_pos_window;  	getWindow()->getCursorPosition(&cursor_pos_window); -	LLCoordGL cursor_pos_gl; -	getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl); +	LLCoordGL cursor_pos_gl(cursor_pos_window.convert());  	*x = llround((F32)cursor_pos_gl.mX / sGLScaleFactor.mV[VX]);  	*y = llround((F32)cursor_pos_gl.mY / sGLScaleFactor.mV[VX]);  } @@ -1803,9 +1840,12 @@ void LLUI::setupPaths()  	LLXMLNodePtr root;  	BOOL success  = LLXMLNode::parseFile(filename, root, NULL);  	Paths paths; -	LLXUIParser parser; -	parser.readXUI(root, paths, filename); +	if(success) +	{ +		LLXUIParser parser; +		parser.readXUI(root, paths, filename); +	}  	sXUIPaths.clear();  	if (success && paths.validateBlock()) @@ -2013,13 +2053,13 @@ 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 -	view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE ); +	// Make sure we're on-screen and not overlapping the mouse +	view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect );  }  LLView* LLUI::resolvePath(LLView* context, const std::string& path) @@ -2082,12 +2122,12 @@ namespace LLInitParam  		alpha("alpha"),  		control("")  	{ -		updateBlockFromValue(); +		updateBlockFromValue(false);  	}  	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()  	{ -		if (control.isProvided()) +		if (control.isProvided() && !control().empty())  		{  			updateValue(LLUIColorTable::instance().getColor(control));  		} @@ -2097,14 +2137,14 @@ namespace LLInitParam  		}  	} -	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue() +	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue(bool make_block_authoritative)  	{  		LLColor4 color = getValue(); -		red.set(color.mV[VRED], false); -		green.set(color.mV[VGREEN], false); -		blue.set(color.mV[VBLUE], false); -		alpha.set(color.mV[VALPHA], false); -		control.set("", false); +		red.set(color.mV[VRED], make_block_authoritative); +		green.set(color.mV[VGREEN], make_block_authoritative); +		blue.set(color.mV[VBLUE], make_block_authoritative); +		alpha.set(color.mV[VALPHA], make_block_authoritative); +		control.set("", make_block_authoritative);  	}  	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) @@ -2124,7 +2164,7 @@ namespace LLInitParam  			updateValue(LLFontGL::getFontDefault());  		}  		addSynonym(name, ""); -		updateBlockFromValue(); +		updateBlockFromValue(false);  	}  	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock() @@ -2150,13 +2190,13 @@ namespace LLInitParam  		}  	} -	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue() +	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue(bool make_block_authoritative)  	{  		if (getValue())  		{ -			name.set(LLFontGL::nameFromFont(getValue()), false); -			size.set(LLFontGL::sizeFromFont(getValue()), false); -			style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), false); +			name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative); +			size.set(LLFontGL::sizeFromFont(getValue()), make_block_authoritative); +			style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), make_block_authoritative);  		}  	} @@ -2169,7 +2209,7 @@ namespace LLInitParam  		width("width"),  		height("height")  	{ -		updateBlockFromValue(); +		updateBlockFromValue(false);  	}  	void ParamValue<LLRect, TypeValues<LLRect> >::updateValueFromBlock() @@ -2236,19 +2276,21 @@ namespace LLInitParam  		updateValue(rect);  	} -	void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue() +	void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue(bool make_block_authoritative)  	{  		// because of the ambiguity in specifying a rect by position and/or dimensions -		// we clear the "provided" flag so that values from xui/etc have priority -		// over those calculated from the rect object - +		// we use the lowest priority pairing so that any valid pairing in xui  +		// will override those calculated from the rect object +		// in this case, that is left+width and bottom+height  		LLRect& value = getValue(); -		left.set(value.mLeft, false); +  		right.set(value.mRight, false); -		bottom.set(value.mBottom, false); +		left.set(value.mLeft, make_block_authoritative); +		width.set(value.getWidth(), make_block_authoritative); +  		top.set(value.mTop, false); -		width.set(value.getWidth(), false); -		height.set(value.getHeight(), false); +		bottom.set(value.mBottom, make_block_authoritative); +		height.set(value.getHeight(), make_block_authoritative);  	}  	ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::ParamValue(const LLCoordGL& coord) @@ -2256,7 +2298,7 @@ namespace LLInitParam  		x("x"),  		y("y")  	{ -		updateBlockFromValue(); +		updateBlockFromValue(false);  	}  	void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateValueFromBlock() @@ -2264,10 +2306,10 @@ namespace LLInitParam  		updateValue(LLCoordGL(x, y));  	} -	void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue() +	void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue(bool make_block_authoritative)  	{ -		x.set(getValue().mX, false); -		y.set(getValue().mY, false); +		x.set(getValue().mX, make_block_authoritative); +		y.set(getValue().mY, make_block_authoritative);  	} diff --git a/indra/llui/llui.h b/indra/llui/llui.h index c583d58d5a..28e84fa444 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -33,6 +33,7 @@  #include "llrect.h"  #include "llcontrol.h"  #include "llcoord.h" +#include "llglslshader.h"  #include "llinitparam.h"  #include "llregistry.h"  #include "lluicolor.h" @@ -40,6 +41,7 @@  #include <boost/signals2.hpp>  #include "lllazyvalue.h"  #include "llframetimer.h" +#include <limits>  // LLUIFactory  #include "llsd.h" @@ -47,6 +49,7 @@  // for initparam specialization  #include "llfontgl.h" +  class LLColor4;   class LLVector3;  class LLVector2; @@ -146,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; @@ -363,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; @@ -408,7 +527,7 @@ namespace LLInitParam  		ParamValue(const LLRect& value);  		void updateValueFromBlock(); -		void updateBlockFromValue(); +		void updateBlockFromValue(bool make_block_authoritative);  	};  	template<> @@ -426,7 +545,7 @@ namespace LLInitParam  		ParamValue(const LLUIColor& color);  		void updateValueFromBlock(); -		void updateBlockFromValue(); +		void updateBlockFromValue(bool make_block_authoritative);  	};  	template<> @@ -441,7 +560,7 @@ namespace LLInitParam  		ParamValue(const LLFontGL* value);  		void updateValueFromBlock(); -		void updateBlockFromValue(); +		void updateBlockFromValue(bool make_block_authoritative);  	};  	template<> @@ -480,8 +599,11 @@ namespace LLInitParam  		ParamValue(const LLCoordGL& val);  		void updateValueFromBlock(); -		void updateBlockFromValue(); +		void updateBlockFromValue(bool make_block_authoritative);  	};  } +extern LLGLSLShader gSolidColorProgram; +extern LLGLSLShader gUIProgram; +  #endif 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..b9c843e931 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -118,7 +118,6 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)  	mDoubleClickSignal(NULL),  	mTransparencyType(TT_DEFAULT)  { -	mUICtrlHandle.bind(this);  }  void LLUICtrl::initFromParams(const Params& p) @@ -460,7 +459,7 @@ void LLUICtrl::setControlVariable(LLControlVariable* control)  	if (control)  	{  		mControlVariable = control; -		mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("value"))); +		mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value")));  		setValue(mControlVariable->getValue());  	}  } @@ -491,7 +490,7 @@ void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)  	if (control)  	{  		mEnabledControlVariable = control; -		mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("enabled"))); +		mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled")));  		setEnabled(mEnabledControlVariable->getValue().asBoolean());  	}  } @@ -506,7 +505,7 @@ void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)  	if (control)  	{  		mDisabledControlVariable = control; -		mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("disabled"))); +		mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled")));  		setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));  	}  } @@ -521,7 +520,7 @@ void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)  	if (control)  	{  		mMakeVisibleControlVariable = control; -		mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("visible"))); +		mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible")));  		setVisible(mMakeVisibleControlVariable->getValue().asBoolean());  	}  } @@ -536,7 +535,7 @@ void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)  	if (control)  	{  		mMakeInvisibleControlVariable = control; -		mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("invisible"))); +		mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible")));  		setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean()));  	}  } @@ -992,6 +991,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 +1054,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..fb2196bb16 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; @@ -223,7 +223,7 @@ public:  	BOOL	focusLastItem(BOOL prefer_text_fields = FALSE);  	// Non Virtuals -	LLHandle<LLUICtrl> getUICtrlHandle() const { return mUICtrlHandle; } +	LLHandle<LLUICtrl> getHandle() const { return getDerivedHandle<LLUICtrl>(); }  	BOOL			getIsChrome() const;  	void			setTabStop( BOOL b ); @@ -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,14 +304,15 @@ protected:  	static F32 sActiveControlTransparency;  	static F32 sInactiveControlTransparency; - +	 +	virtual void addInfo(LLSD & info); +	  private:  	BOOL			mIsChrome;  	BOOL			mRequestsFront;  	BOOL			mTabStop;  	BOOL			mTentative; -	LLRootHandle<LLUICtrl> mUICtrlHandle;  	ETypeTransparency mTransparencyType; diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 499b97f52d..d612ad5005 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -104,14 +104,17 @@ private:  	public:  		ParamDefaults()  		{ -			// recursively initialize from base class param block -			((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY>::instance().get()); -			// after initializing base classes, look up template file for this param block +			// look up template file for this param block...  			const std::string* param_block_tag = getWidgetTag(&typeid(PARAM_BLOCK));  			if (param_block_tag) -			{ -				LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype); +			{	// ...and if it exists, back fill values using the most specific template first +				PARAM_BLOCK params; +				LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, params); +				mPrototype.fillFrom(params);  			} +			// recursively fill from base class param block +			((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY>::instance().get()); +  		}  		const PARAM_BLOCK& get() { return mPrototype; } @@ -169,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);  		{ @@ -198,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/lluiimage.cpp b/indra/llui/lluiimage.cpp index f37947a50b..1d9ce29ba9 100644 --- a/indra/llui/lluiimage.cpp +++ b/indra/llui/lluiimage.cpp @@ -172,15 +172,15 @@ namespace LLInitParam  		}  	} -	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue() +	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue(bool make_block_authoritative)  	{  		if (getValue() == NULL)  		{ -			name.set("none", false); +			name.set("none", make_block_authoritative);  		}  		else  		{ -			name.set(getValue()->getName(), false); +			name.set(getValue()->getName(), make_block_authoritative);  		}  	} diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h index 139d88e0ac..f07e8fa746 100644 --- a/indra/llui/lluiimage.h +++ b/indra/llui/lluiimage.h @@ -103,12 +103,12 @@ namespace LLInitParam  		ParamValue(LLUIImage* const& image)  		:	super_t(image)  		{ -			updateBlockFromValue(); +			updateBlockFromValue(false);  			addSynonym(name, "name");  		}  		void updateValueFromBlock(); -		void updateBlockFromValue(); +		void updateBlockFromValue(bool make_block_authoritative);  	};  	// Need custom comparison function for our test app, which only loads diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index ac69d3bf85..c4e073ccdb 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -128,17 +128,13 @@ void LLUIString::updateResult() const  	}  	mResult = mOrig; -	// get the defailt args + local args -	if (!mArgs || mArgs->empty()) +	// get the default args + local args +	LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); +	if (mArgs && !mArgs->empty())  	{ -		LLStringUtil::format(mResult, LLTrans::getDefaultArgs()); -	} -	else -	{ -		LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs();  		combined_args.insert(mArgs->begin(), mArgs->end()); -		LLStringUtil::format(mResult, combined_args);  	} +	LLStringUtil::format(mResult, combined_args);  }  void LLUIString::updateWResult() const diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 42b779bd28..fd9b3d9a6d 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -33,28 +33,28 @@  #include "llurlregistry.h"  // global state for the callback functions -void (*LLUrlAction::sOpenURLCallback) (const std::string& url) = NULL; -void (*LLUrlAction::sOpenURLInternalCallback) (const std::string& url) = NULL; -void (*LLUrlAction::sOpenURLExternalCallback) (const std::string& url) = NULL; -bool (*LLUrlAction::sExecuteSLURLCallback) (const std::string& url) = NULL; +LLUrlAction::url_callback_t 		LLUrlAction::sOpenURLCallback; +LLUrlAction::url_callback_t 		LLUrlAction::sOpenURLInternalCallback; +LLUrlAction::url_callback_t 		LLUrlAction::sOpenURLExternalCallback; +LLUrlAction::execute_url_callback_t LLUrlAction::sExecuteSLURLCallback; -void LLUrlAction::setOpenURLCallback(void (*cb) (const std::string& url)) +void LLUrlAction::setOpenURLCallback(url_callback_t cb)  {  	sOpenURLCallback = cb;  } -void LLUrlAction::setOpenURLInternalCallback(void (*cb) (const std::string& url)) +void LLUrlAction::setOpenURLInternalCallback(url_callback_t cb)  {  	sOpenURLInternalCallback = cb;  } -void LLUrlAction::setOpenURLExternalCallback(void (*cb) (const std::string& url)) +void LLUrlAction::setOpenURLExternalCallback(url_callback_t cb)  {  	sOpenURLExternalCallback = cb;  } -void LLUrlAction::setExecuteSLURLCallback(bool (*cb) (const std::string& url)) +void LLUrlAction::setExecuteSLURLCallback(execute_url_callback_t cb)  {  	sExecuteSLURLCallback = cb;  } @@ -63,7 +63,7 @@ void LLUrlAction::openURL(std::string url)  {  	if (sOpenURLCallback)  	{ -		(*sOpenURLCallback)(url); +		sOpenURLCallback(url);  	}  } @@ -71,7 +71,7 @@ void LLUrlAction::openURLInternal(std::string url)  {  	if (sOpenURLInternalCallback)  	{ -		(*sOpenURLInternalCallback)(url); +		sOpenURLInternalCallback(url);  	}  } @@ -79,7 +79,7 @@ void LLUrlAction::openURLExternal(std::string url)  {  	if (sOpenURLExternalCallback)  	{ -		(*sOpenURLExternalCallback)(url); +		sOpenURLExternalCallback(url);  	}  } @@ -87,18 +87,18 @@ void LLUrlAction::executeSLURL(std::string url)  {  	if (sExecuteSLURLCallback)  	{ -		(*sExecuteSLURLCallback)(url); +		sExecuteSLURLCallback(url);  	}  }  void LLUrlAction::clickAction(std::string url)  {  	// Try to handle as SLURL first, then http Url -	if ( (sExecuteSLURLCallback) && !(*sExecuteSLURLCallback)(url) ) +	if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url) )  	{  		if (sOpenURLCallback)  		{ -			(*sOpenURLCallback)(url); +			sOpenURLCallback(url);  		}  	}  } diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index 0132dbaaf0..c34960b826 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -29,6 +29,7 @@  #define LL_LLURLACTION_H  #include <string> +#include <boost/function.hpp>  ///  /// The LLUrlAction class provides a number of static functions that @@ -77,17 +78,21 @@ public:  	static void showProfile(std::string url);  	/// specify the callbacks to enable this class's functionality -	static void	setOpenURLCallback(void (*cb) (const std::string& url)); -	static void	setOpenURLInternalCallback(void (*cb) (const std::string& url)); -	static void	setOpenURLExternalCallback(void (*cb) (const std::string& url)); -	static void	setExecuteSLURLCallback(bool (*cb) (const std::string& url)); +	typedef boost::function<void (const std::string&)> url_callback_t; +	typedef boost::function<bool(const std::string& url)> execute_url_callback_t; + +	static void	setOpenURLCallback(url_callback_t cb); +	static void	setOpenURLInternalCallback(url_callback_t cb); +	static void	setOpenURLExternalCallback(url_callback_t cb); +	static void	setExecuteSLURLCallback(execute_url_callback_t cb);  private:  	// callbacks for operations we can perform on Urls -	static void (*sOpenURLCallback) (const std::string& url); -	static void (*sOpenURLInternalCallback) (const std::string& url); -	static void (*sOpenURLExternalCallback) (const std::string& url); -	static bool (*sExecuteSLURLCallback) (const std::string& url); +	static url_callback_t sOpenURLCallback; +	static url_callback_t sOpenURLInternalCallback; +	static url_callback_t sOpenURLExternalCallback; + +	static execute_url_callback_t sExecuteSLURLCallback;  };  #endif diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 9db1feafd1..a9e8fbb4e4 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -1134,7 +1134,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const  //  LLUrlEntryNoLink::LLUrlEntryNoLink()  { -	mPattern = boost::regex("<nolink>.*</nolink>", +	mPattern = boost::regex("<nolink>.*?</nolink>",  							boost::regex::perl|boost::regex::icase);  } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 8803d106ba..54843227b7 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; @@ -115,6 +121,7 @@ LLView::Params::Params()  LLView::LLView(const LLView::Params& p)  :	mVisible(p.visible), +	mInDraw(false),  	mName(p.name),  	mParentView(NULL),  	mReshapeFlags(FOLLOWS_NONE), @@ -219,9 +226,11 @@ BOOL LLView::getUseBoundingRect() const  }  // virtual -std::string LLView::getName() const +const std::string& LLView::getName() const  { -	return mName.empty() ? std::string("(no name)") : mName; +	static std::string no_name("(no name)"); + +	return mName.empty() ? no_name : mName;  }  void LLView::sendChildToFront(LLView* child) @@ -325,6 +334,8 @@ void LLView::removeChild(LLView* child)  	//llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs  	if (child->mParentView == this)   	{ +		// if we are removing an item we are currently iterating over, that would be bad +		llassert(child->mInDraw == false);  		mChildList.remove( child );  		child->mParentView = NULL;  		if (child->isCtrl()) @@ -346,13 +357,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 +437,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 +613,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 +640,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 +683,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()); -LLView*	LLView::childFromPoint(S32 x, S32 y) +		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, 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 +867,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 +975,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 +1024,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() @@ -1306,6 +1093,11 @@ void LLView::drawChildren()  		{  			child_list_reverse_iter_t child = child_iter++;  			LLView *viewp = *child; +			 +			if (viewp == NULL) +			{ +				continue; +			}  			if (viewp->getVisible() && viewp->getRect().isValid())  			{ @@ -1314,8 +1106,11 @@ void LLView::drawChildren()  				{  					LLUI::pushMatrix();  					{ -						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); +						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom); +						// flag the fact we are in draw here, in case overridden draw() method attempts to remove this widget +						viewp->mInDraw = true;  						viewp->draw(); +						viewp->mInDraw = false;  						if (sDebugRects)  						{ @@ -1364,7 +1159,7 @@ void LLView::drawDebugRect()  		if (getUseBoundingRect())  		{ -			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f); +			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom);  		}  		LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; @@ -1433,10 +1228,10 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr  		if ((childp->getVisible() && childp->getRect().isValid())   			|| force_draw)  		{ -			glMatrixMode(GL_MODELVIEW); +			gGL.matrixMode(LLRender::MM_MODELVIEW);  			LLUI::pushMatrix();  			{ -				LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset, 0.f); +				LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset);  				childp->draw();  			}  			LLUI::popMatrix(); @@ -1460,9 +1255,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()) @@ -1506,7 +1300,10 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)  			S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft;  			S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom;  			viewp->translate( delta_x, delta_y ); -			viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); +			if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight()) +			{ +				viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); +			}  		}  	} @@ -1525,10 +1322,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())  @@ -1655,15 +1450,19 @@ BOOL LLView::hasAncestor(const LLView* parentp) const  BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const  { -	LLView *child = findChildView(childname, TRUE); -	if (child) -	{ -		return gFocusMgr.childHasKeyboardFocus(child); -	} -	else +	LLView *focus = dynamic_cast<LLView *>(gFocusMgr.getKeyboardFocus()); +	 +	while (focus != NULL)  	{ -		return FALSE; +		if (focus->getName() == childname) +		{ +			return TRUE; +		} +		 +		focus = focus->getParent();  	} +	 +	return FALSE;  }  //----------------------------------------------------------------------------- @@ -1689,11 +1488,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)  		{ @@ -1703,9 +1500,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 ) @@ -1822,67 +1618,31 @@ 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) +LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S32 min_overlap_pixels)  {  	LLCoordGL delta; -	if (allow_partial_outside) -	{ -		const S32 KEEP_ONSCREEN_PIXELS = 16; +	const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth()); +	const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight()); -		if( input.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft ) -		{ -			delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS); -		} -		else -		if( input.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight ) -		{ -			delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS); -		} +	if( input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft ) +	{ +		delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); +	} +	else if( input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight ) +	{ +		delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); +	} -		if( input.mTop > constraint.mTop ) -		{ -			delta.mY = constraint.mTop - input.mTop; -		} -		else -		if( input.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom ) -		{ -			delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS); -		} +	if( input.mTop > constraint.mTop ) +	{ +		delta.mY = constraint.mTop - input.mTop;  	}  	else +	if( input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom )  	{ -		if( input.mLeft < constraint.mLeft ) -		{ -			delta.mX = constraint.mLeft - input.mLeft; -		} -		else -		if( input.mRight > constraint.mRight ) -		{ -			delta.mX = constraint.mRight - input.mRight; -			// compensate for left edge possible going off screen -			delta.mX += llmax( 0, input.getWidth() - constraint.getWidth() ); -		} - -		if( input.mTop > constraint.mTop ) -		{ -			delta.mY = constraint.mTop - input.mTop; -		} -		else -		if( input.mBottom < constraint.mBottom ) -		{ -			delta.mY = constraint.mBottom - input.mBottom; -			// compensate for top edge possible going off screen -			delta.mY -= llmax( 0, input.getHeight() - constraint.getHeight() ); -		} +		delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT);  	}  	return delta; @@ -1891,9 +1651,9 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BO  // Moves the view so that it is entirely inside of constraint.  // If the view will not fit because it's too big, aligns with the top and left.  // (Why top and left?  That's where the drag bars are for floaters.) -BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside ) +BOOL LLView::translateIntoRect(const LLRect& constraint, S32 min_overlap_pixels)  { -	LLCoordGL translation = getNeededTranslation(getRect(), constraint, allow_partial_outside); +	LLCoordGL translation = getNeededTranslation(getRect(), constraint, min_overlap_pixels);  	if (translation.mX != 0 || translation.mY != 0)  	{ @@ -1905,9 +1665,9 @@ BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outs  // move this view into "inside" but not onto "exclude"  // NOTE: if this view is already contained in "inside", we ignore the "exclude" rect -BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ) +BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels)  { -	LLCoordGL translation = getNeededTranslation(getRect(), inside, allow_partial_outside); +	LLCoordGL translation = getNeededTranslation(getRect(), inside, min_overlap_pixels);  	if (translation.mX != 0 || translation.mY != 0)  	{ @@ -2075,7 +1835,10 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()  void	LLView::setShape(const LLRect& new_rect, bool by_user)  { -	handleReshape(new_rect, by_user); +	if (new_rect != getRect()) +	{ +		handleReshape(new_rect, by_user); +	}  }  void LLView::handleReshape(const LLRect& new_rect, bool by_user) @@ -2465,110 +2228,163 @@ static bool get_last_child_rect(LLView* parent, LLRect *rect)  }  //static -void LLView::applyXUILayout(LLView::Params& p, LLView* parent) +void LLView::applyXUILayout(LLView::Params& p, LLView* parent, LLRect layout_rect)  { +	if (!parent) return; +  	const S32 VPAD = 4;  	const S32 MIN_WIDGET_HEIGHT = 10;  	// *NOTE:  This will confuse export of floater/panel coordinates unless  	// the default is also "topleft".  JC -	if (p.layout().empty() && parent) +	if (p.layout().empty())  	{  		p.layout = parent->getLayout();  	} -	if (parent) +	if (layout_rect.isEmpty())  	{ -		LLRect parent_rect = parent->getLocalRect(); -		// overwrite uninitialized rect params, using context -		LLRect last_rect = parent->getLocalRect(); +		layout_rect = parent->getLocalRect(); +	} -		bool layout_topleft = (p.layout() == "topleft"); +	// overwrite uninitialized rect params, using context +	LLRect default_rect = parent->getLocalRect(); -		// convert negative or centered coordinates to parent relative values -		// Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() -		if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth(); -		if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth(); -		if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight(); -		if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight(); +	bool layout_topleft = (p.layout() == "topleft"); +	// convert negative or centered coordinates to parent relative values +	// Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() +	if (p.rect.left.isProvided())  +	{ +		p.rect.left = p.rect.left + ((p.rect.left >= 0) ? layout_rect.mLeft : layout_rect.mRight); +	} +	if (p.rect.right.isProvided()) +	{ +		p.rect.right = p.rect.right + ((p.rect.right >= 0) ? layout_rect.mLeft : layout_rect.mRight); +	} +	if (p.rect.bottom.isProvided())  +	{ +		p.rect.bottom = p.rect.bottom + ((p.rect.bottom >= 0) ? layout_rect.mBottom : layout_rect.mTop);  		if (layout_topleft)  		{  			//invert top to bottom -			if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; -			if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom; +			p.rect.bottom = layout_rect.mBottom + layout_rect.mTop - p.rect.bottom;  		} - -		// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels -		if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) +	} +	if (p.rect.top.isProvided()) +	{ +		p.rect.top = p.rect.top + ((p.rect.top >= 0) ? layout_rect.mBottom : layout_rect.mTop); +		if (layout_topleft)  		{ -			p.rect.height = MIN_WIDGET_HEIGHT; +			//invert top to bottom +			p.rect.top = layout_rect.mBottom + layout_rect.mTop - p.rect.top;  		} +	} + +	// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels +	if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) +	{ +		p.rect.height = MIN_WIDGET_HEIGHT; +	} -		last_rect.translate(0, last_rect.getHeight()); +	default_rect.translate(0, default_rect.getHeight()); -		// If there was a recently constructed child, use its rectangle -		get_last_child_rect(parent, &last_rect); +	// If there was a recently constructed child, use its rectangle +	get_last_child_rect(parent, &default_rect); -		if (layout_topleft) +	if (layout_topleft) +	{ +		// Invert the sense of bottom_delta for topleft layout +		if (p.bottom_delta.isProvided())  		{ -			p.bottom_delta.setIfNotProvided(0, false); - -			// Invert the sense of bottom_delta for topleft layout -			if (p.bottom_delta.isProvided()) -			{ -				p.bottom_delta = -p.bottom_delta; -			} -			else if (p.top_pad.isProvided())  -			{ -				p.bottom_delta = -(p.rect.height + p.top_pad); -			} -			else if (p.top_delta.isProvided()) -			{ -				p.bottom_delta = -					-(p.top_delta + p.rect.height - last_rect.getHeight()); -			} -			else if (!p.bottom_delta.isProvided() -					 && !p.left_delta.isProvided() -					 && !p.top_pad.isProvided() -					 && !p.left_pad.isProvided()) -			{ -				// set default position is just below last rect -				p.bottom_delta.set(-(p.rect.height + VPAD), false); -			} +			p.bottom_delta = -p.bottom_delta; +		} +		else if (p.top_pad.isProvided())  +		{ +			p.bottom_delta = -(p.rect.height + p.top_pad); +		} +		else if (p.top_delta.isProvided()) +		{ +			p.bottom_delta = +				-(p.top_delta + p.rect.height - default_rect.getHeight()); +		} +		else if (!p.left_delta.isProvided() +					&& !p.left_pad.isProvided()) +		{ +			// set default position is just below last rect +			p.bottom_delta.set(-(p.rect.height + VPAD), false); +		} +		else +		{ +			p.bottom_delta.set(0, false); +		} -			// default to same left edge -			p.left_delta.setIfNotProvided(0, false); -			if (p.left_pad.isProvided()) -			{ -				// left_pad is based on prior widget's right edge -				p.left_delta.set(p.left_pad + last_rect.getWidth(), false); -			} +		// default to same left edge +		if (!p.left_delta.isProvided()) +		{ +			p.left_delta.set(0, false); +		} +		if (p.left_pad.isProvided()) +		{ +			// left_pad is based on prior widget's right edge +			p.left_delta.set(p.left_pad + default_rect.getWidth(), false); +		} -			last_rect.translate(p.left_delta, p.bottom_delta);				 +		default_rect.translate(p.left_delta, p.bottom_delta);				 +	} +	else +	{	 +		// set default position is just below last rect +		if (!p.bottom_delta.isProvided()) +		{ +			p.bottom_delta.set(-(p.rect.height + VPAD), false);  		} -		else -		{	 -			// set default position is just below last rect -			p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false); -			p.left_delta.setIfNotProvided(0, false); -			last_rect.translate(p.left_delta, p.bottom_delta); +		if (!p.left_delta.isProvided()) +		{ +			p.left_delta.set(0, false);  		} +		default_rect.translate(p.left_delta, p.bottom_delta); +	} -		// this handles case where *both* x and x_delta are provided -		// ignore x in favor of default x + x_delta -		if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); -		if (p.left_delta.isProvided()) p.rect.left.set(0, false); +	// this handles case where *both* x and x_delta are provided +	// ignore x in favor of default x + x_delta +	if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); +	if (p.left_delta.isProvided()) p.rect.left.set(0, false); -		// selectively apply rectangle defaults, making sure that -		// params are not flagged as having been "provided" -		// as rect params are overconstrained and rely on provided flags -		p.rect.left.setIfNotProvided(last_rect.mLeft, false); -		p.rect.bottom.setIfNotProvided(last_rect.mBottom, false); -		p.rect.top.setIfNotProvided(last_rect.mTop, false); -		p.rect.right.setIfNotProvided(last_rect.mRight, false); -		p.rect.width.setIfNotProvided(last_rect.getWidth(), false); -		p.rect.height.setIfNotProvided(last_rect.getHeight(), false); +	// selectively apply rectangle defaults, making sure that +	// params are not flagged as having been "provided" +	// as rect params are overconstrained and rely on provided flags +	if (!p.rect.left.isProvided()) +	{ +		p.rect.left.set(default_rect.mLeft, false); +		//HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value +		p.rect.paramChanged(p.rect.left, true); +	} +	if (!p.rect.bottom.isProvided()) +	{ +		p.rect.bottom.set(default_rect.mBottom, false); +		p.rect.paramChanged(p.rect.bottom, true); +	} +	if (!p.rect.top.isProvided()) +	{ +		p.rect.top.set(default_rect.mTop, false); +		p.rect.paramChanged(p.rect.top, true); +	} +	if (!p.rect.right.isProvided()) +	{ +		p.rect.right.set(default_rect.mRight, false); +		p.rect.paramChanged(p.rect.right, true); + +	} +	if (!p.rect.width.isProvided()) +	{ +		p.rect.width.set(default_rect.getWidth(), false); +		p.rect.paramChanged(p.rect.width, true); +	} +	if (!p.rect.height.isProvided()) +	{ +		p.rect.height.set(default_rect.getHeight(), false); +		p.rect.paramChanged(p.rect.height, true);  	}  } @@ -2811,9 +2627,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;  } @@ -2833,3 +2649,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..1c35349510 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,14 @@ private:  	static std::vector<LLViewDrawContext*> sDrawContextStack;  }; -class LLViewWidgetRegistry : public LLChildRegistry<LLViewWidgetRegistry> -{}; - -class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElement +class LLView  +:	public LLMouseHandler,			// handles mouse events +	public LLFocusableElement,		// handles keyboard events +	public LLMortician,				// lazy deletion +	public LLHandleProvider<LLView>	// passes out weak references to self  {  public: -	struct Follows : public LLInitParam::Choice<Follows> +	struct Follows : public LLInitParam::ChoiceBlock<Follows>  	{  		Alternative<std::string>	string;  		Alternative<U32>			flags; @@ -150,7 +153,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 +244,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); @@ -306,8 +310,6 @@ public:  	void			popVisible()				{ setVisible(mLastVisible); }  	BOOL			getLastVisible()	const	{ return mLastVisible; } -	LLHandle<LLView>	getHandle()				{ mHandle.bind(this); return mHandle; } -  	U32			getFollows() const				{ return mReshapeFlags; }  	BOOL		followsLeft() const				{ return mReshapeFlags & FOLLOWS_LEFT; }  	BOOL		followsRight() const			{ return mReshapeFlags & FOLLOWS_RIGHT; } @@ -368,8 +370,8 @@ public:  	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  	virtual void	translate( S32 x, S32 y );  	void			setOrigin( S32 x, S32 y )	{ mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } -	BOOL			translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside ); -	BOOL			translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside ); +	BOOL			translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); +	BOOL			translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX);  	void			centerWithin(const LLRect& bounds);  	void	setShape(const LLRect& new_rect, bool by_user = false); @@ -431,18 +433,21 @@ public:  	/*virtual*/ BOOL	handleRightMouseUp(S32 x, S32 y, MASK mask);	  	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, MASK mask); -	/*virtual*/ std::string	getName() const; +	/*virtual*/ const std::string& getName() const;  	/*virtual*/ void	onMouseCaptureLost();  	/*virtual*/ BOOL	hasMouseCapture();  	/*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 +472,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,12 +501,11 @@ 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(),  	// usually to adjust layout. -	static void applyXUILayout(Params& p, LLView* parent); +	static void applyXUILayout(Params& p, LLView* parent, LLRect layout_rect = LLRect());  	// For re-export of floaters and panels, convert the coordinate system  	// to be top-left based. @@ -511,11 +529,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 +562,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; @@ -569,11 +608,12 @@ private:  	BOOL		mIsFocusRoot;  	BOOL		mUseBoundingRect; // hit test against bounding rectangle that includes all child elements -	LLRootHandle<LLView> mHandle;  	BOOL		mLastVisible;  	S32			mNextInsertionOrdinal; +	bool		mInDraw; +  	static LLWindow* sWindow;	// All root views must know about their window.  	typedef std::map<std::string, LLView*> default_widget_map_t; @@ -582,7 +622,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/llviewborder.cpp b/indra/llui/llviewborder.cpp index 32d7ea7c25..919267dcc6 100644 --- a/indra/llui/llviewborder.cpp +++ b/indra/llui/llviewborder.cpp @@ -57,9 +57,6 @@ LLViewBorder::Params::Params()  {  	addSynonym(border_thickness, "thickness");  	addSynonym(render_style, "style"); -	name = "view_border"; -	mouse_opaque = false; -	follows.flags = FOLLOWS_ALL;  } 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/llwindowshade.cpp b/indra/llui/llwindowshade.cpp index 77e94385d4..f5c463c961 100644 --- a/indra/llui/llwindowshade.cpp +++ b/indra/llui/llwindowshade.cpp @@ -37,18 +37,20 @@  const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;  const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100; +static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade"); +  LLWindowShade::Params::Params()  :	bg_image("bg_image"),  	modal("modal", false),  	text_color("text_color"), +	shade_color("shade_color"),  	can_close("can_close", true)  { -	mouse_opaque = false; +	changeDefault(mouse_opaque, false);  }  LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)  :	LLUICtrl(params), -	mNotification(params.notification),  	mModal(params.modal),  	mFormHeight(0),  	mTextColor(params.text_color) @@ -72,7 +74,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  	addChild(stackp);  	LLLayoutPanel::Params panel_p; -	panel_p.rect = LLRect(0, 30, 800, 0); +	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0);  	panel_p.name = "notification_area";  	panel_p.visible = false;  	panel_p.user_resize = false; @@ -89,7 +91,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  	panel_p.name = "background_area";  	panel_p.mouse_opaque = false;  	panel_p.background_visible = false; -	panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f); +	panel_p.bg_alpha_color = params.shade_color;  	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);  	stackp->addChild(dummy_panel); @@ -107,11 +109,11 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  	LLIconCtrl::Params icon_p;  	icon_p.name = "notification_icon"; -	icon_p.rect = LLRect(5, 23, 21, 8); +	icon_p.rect = LLRect(5, 25, 21, 10);  	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));  	LLTextBox::Params text_p; -	text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0); +	text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3);  	text_p.follows.flags = FOLLOWS_ALL;  	text_p.text_color = mTextColor;  	text_p.font = LLFontGL::getFontSansSerifSmall(); @@ -125,41 +127,132 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  	panel_p.auto_resize = false;  	panel_p.user_resize = false;  	panel_p.name="form_elements"; -	panel_p.rect = LLRect(0, 30, 130, 0); +	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0);  	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);  	stackp->addChild(form_elements_panel); -	if (params.can_close) +	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); +	panel_p.auto_resize = false; +	panel_p.user_resize = false; +	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0); +	panel_p.name = "close_panel"; +	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); +	stackp->addChild(close_panel); + +	LLButton::Params button_p; +	button_p.name = "close_notification"; +	button_p.rect = LLRect(5, 23, 21, 7); +	button_p.image_color.control="DkGray_66"; +	button_p.image_unselected.name="Icon_Close_Foreground"; +	button_p.image_selected.name="Icon_Close_Press"; +	button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); + +	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); +	 +	close_panel->setVisible(params.can_close); +} + +void LLWindowShade::draw() +{ +	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); + +	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); + +	notification_area->reshape(notification_area->getRect().getWidth(),  +		llclamp(message_rect.getHeight() + 15,  +				llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT), +				MAX_NOTIFICATION_AREA_HEIGHT)); + +	LLUICtrl::draw(); + +	while(!mNotifications.empty() && !mNotifications.back()->isActive()) +	{ +		mNotifications.pop_back(); +		// go ahead and hide  +		hide(); +	} + +	if (mNotifications.empty()) +	{ +		hide(); +	} +	else if (notification_area->getVisibleAmount() < 0.01f) +	{ +		displayLatestNotification(); +	} + +	if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f))  	{ -		panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -		panel_p.auto_resize = false; -		panel_p.user_resize = false; -		panel_p.rect = LLRect(0, 30, 25, 0); -		LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -		stackp->addChild(close_panel); - -		LLButton::Params button_p; -		button_p.name = "close_notification"; -		button_p.rect = LLRect(5, 23, 21, 7); -		button_p.image_color.control="DkGray_66"; -		button_p.image_unselected.name="Icon_Close_Foreground"; -		button_p.image_selected.name="Icon_Close_Press"; -		button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); - -		close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); +		getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); +		setMouseOpaque(false);  	} +} + +void LLWindowShade::hide() +{ +	getChildRef<LLLayoutPanel>("notification_area").setVisible(false); +} + +void LLWindowShade::onCloseNotification() +{ +	if (!mNotifications.empty()) +		LLNotifications::instance().cancel(mNotifications.back()); +} + +void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +{ +	LLNotificationPtr notify = getCurrentNotification(); +	if (!notify) return; + +	bool check = ctrl->getValue().asBoolean(); +	if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) +	{ +		// question was "show again" so invert value to get "ignore" +		check = !check; +	} +	notify->setIgnored(check); +} + +void LLWindowShade::onClickNotificationButton(const std::string& name) +{ +	LLNotificationPtr notify = getCurrentNotification(); +	if (!notify) return; -	LLSD payload = mNotification->getPayload(); +	mNotificationResponse[name] = true; + +	notify->respond(mNotificationResponse); +} -	LLNotificationFormPtr formp = mNotification->getForm(); +void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) +{ +	mNotificationResponse[name] = ctrl->getValue().asString(); +} + +void LLWindowShade::show(LLNotificationPtr notification) +{ +	mNotifications.push_back(notification); + +	displayLatestNotification(); +} + +void LLWindowShade::displayLatestNotification() +{ +	if (mNotifications.empty()) return; + +	LLNotificationPtr notification = mNotifications.back(); + +	LLSD payload = notification->getPayload(); + +	LLNotificationFormPtr formp = notification->getForm();  	LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); -	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon()); -	notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage()); -	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage()); +	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon()); +	notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage()); +	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage());  	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();   	LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");  	form_elements.deleteAllChildren(); +	form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT);  	const S32 FORM_PADDING_HORIZONTAL = 10;  	const S32 FORM_PADDING_VERTICAL = 3; @@ -229,7 +322,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  			label_p.v_pad = 5;  			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);  			textbox->reshapeToFitText(); -			textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL);  +			textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL);   			form_elements.addChild(textbox);  			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; @@ -249,7 +342,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  		}  	} -	mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT; +	mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL);  	form_elements.reshape(form_width, mFormHeight);  	form_elements.setMinDim(form_width); @@ -261,68 +354,39 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)  	{  		(*it)->translate(0, delta_y);  	} -} -void LLWindowShade::show() -{  	getChildRef<LLLayoutPanel>("notification_area").setVisible(true);  	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);  	setMouseOpaque(mModal);  } -void LLWindowShade::draw() +void LLWindowShade::setBackgroundImage(LLUIImage* image)  { -	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); - -	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); - -	notification_area->reshape(notification_area->getRect().getWidth(),  -		llclamp(message_rect.getHeight() + 10,  -				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT), -				MAX_NOTIFICATION_AREA_HEIGHT)); - -	LLUICtrl::draw(); -	if (mNotification && !mNotification->isActive()) -	{ -		hide(); -	} +	getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image);  } -void LLWindowShade::hide() +void LLWindowShade::setTextColor(LLColor4 color)  { -	getChildRef<LLLayoutPanel>("notification_area").setVisible(false); -	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); - -	setMouseOpaque(false); +	getChild<LLTextBox>("notification_text")->setColor(color);  } -void LLWindowShade::onCloseNotification() +bool LLWindowShade::isShown() const  { -	LLNotifications::instance().cancel(mNotification); +	return getChildRef<LLLayoutPanel>("notification_area").getVisible();  } -void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +void LLWindowShade::setCanClose(bool can_close)  { -	bool check = ctrl->getValue().asBoolean(); -	if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) -	{ -		// question was "show again" so invert value to get "ignore" -		check = !check; -	} -	mNotification->setIgnored(check); +	getChildView("close_panel")->setVisible(can_close);  } -void LLWindowShade::onClickNotificationButton(const std::string& name) +LLNotificationPtr LLWindowShade::getCurrentNotification()  { -	if (!mNotification) return; - -	mNotificationResponse[name] = true; - -	mNotification->respond(mNotificationResponse); +	if (mNotifications.empty()) +	{ +		return LLNotificationPtr(); +	} +	return mNotifications.back();  } -void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) -{ -	mNotificationResponse[name] = ctrl->getValue().asString(); -} diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index 09ffc2cd54..6d753d1161 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -36,20 +36,28 @@ class LLWindowShade : public LLUICtrl  public:  	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>  	{ -		Mandatory<LLNotificationPtr>	notification;  		Optional<LLUIImage*>			bg_image; -		Optional<LLUIColor>				text_color; +		Optional<LLUIColor>				text_color, +										shade_color;  		Optional<bool>					modal,  										can_close;  		Params();  	}; -	void show(); +	void show(LLNotificationPtr);  	/*virtual*/ void draw();  	void hide(); +	 +	bool isShown() const; + +	void setBackgroundImage(LLUIImage* image); +	void setTextColor(LLColor4 color); +	void setCanClose(bool can_close);  private: +	void displayLatestNotification(); +	LLNotificationPtr getCurrentNotification();  	friend class LLUICtrlFactory;  	LLWindowShade(const Params& p); @@ -60,7 +68,7 @@ private:  	void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);  	void onClickIgnore(LLUICtrl* ctrl); -	LLNotificationPtr	mNotification; +	std::vector<LLNotificationPtr>	mNotifications;  	LLSD				mNotificationResponse;  	bool				mModal;  	S32					mFormHeight; diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index 26b3b17577..c75df86891 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -105,8 +105,6 @@ LLStyle::Params::Params()  namespace LLInitParam  { -	BaseBlock::BaseBlock() {} -	BaseBlock::~BaseBlock() {}  	Param::Param(BaseBlock* enclosing_block)  	:	mIsProvided(false)  	{ @@ -114,7 +112,6 @@ namespace LLInitParam  		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);  		mEnclosingBlockOffset = (U16)(my_addr - block_addr);  	} -	void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {}  	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}  	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} @@ -124,8 +121,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; } @@ -137,7 +134,7 @@ namespace LLInitParam  	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()   	{} -	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue() +	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue(bool)  	{}  	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) @@ -152,7 +149,7 @@ namespace LLInitParam  	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()  	{} -	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue() +	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue(bool)  	{}  	void TypeValues<LLFontGL::HAlign>::declareValues() @@ -167,7 +164,7 @@ namespace LLInitParam  	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()  	{} -	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue() +	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue(bool)  	{} 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 3cd61e574e..7183413463 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -63,11 +63,6 @@ S32 LLUIImage::getHeight() const  namespace LLInitParam  { -	BaseBlock::BaseBlock() {} -	BaseBlock::~BaseBlock() {} - -	S32 Parser::sNextParseGeneration = 0; -  	BlockDescriptor::BlockDescriptor() {}  	ParamDescriptor::ParamDescriptor(param_handle_t p,   						merge_func_t merge_func,  @@ -79,8 +74,6 @@ namespace LLInitParam  						S32 max_count){}  	ParamDescriptor::~ParamDescriptor() {} -	void BaseBlock::paramChanged(const Param& last_param, bool user_provided) {} -  	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){}  	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}  	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} @@ -98,8 +91,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; } @@ -111,7 +104,7 @@ namespace LLInitParam  	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()  	{} -	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue() +	void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue(bool)  	{}  	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) @@ -127,7 +120,7 @@ namespace LLInitParam  	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()  	{} -	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue() +	void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue(bool)  	{}  	void TypeValues<LLFontGL::HAlign>::declareValues() @@ -142,7 +135,7 @@ namespace LLInitParam  	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()  	{} -	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue() +	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue(bool)  	{}  	bool ParamCompare<LLUIImage*, false>::equals( | 
