diff options
| author | Matthew Breindel (Falcon) <falcon@lindenlab.com> | 2010-09-30 12:00:29 -0700 | 
|---|---|---|
| committer | Matthew Breindel (Falcon) <falcon@lindenlab.com> | 2010-09-30 12:00:29 -0700 | 
| commit | 60f8c8279071b791fbc7179d8bc2bb9ca4880a03 (patch) | |
| tree | 20a513fdb383dfd36ca0dbe0a99eacd72faad835 /indra/llui | |
| parent | 569f3f4b06fc2f5a0fa658a49d519428983403f9 (diff) | |
| parent | d95b08c4a6830fc8a2319e77242d8f76eb4cbdae (diff) | |
Merge
Diffstat (limited to 'indra/llui')
40 files changed, 1593 insertions, 1200 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 12df9ccae4..c59ef7819c 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -158,6 +158,7 @@ set(llui_HEADER_FILES      llnotifications.h      llnotificationslistener.h      llnotificationsutil.h +    llnotificationtemplate.h      llpanel.h      llprogressbar.h      llradiogroup.h diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index c3ef734823..5ce52185e3 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -89,7 +89,7 @@ LLAccordionCtrl::LLAccordionCtrl() : LLPanel()  	mSingleExpansion = false;  	mFitParent = false; -	LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");	 +	buildFromFile( "accordion_parent.xml");	  }  //--------------------------------------------------------------------------------- diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 00fb276f19..f87534fa76 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -91,10 +91,10 @@ public:  		Optional<bool>			selection_enabled; -		Optional<S32>			padding_left; -		Optional<S32>			padding_right; -		Optional<S32>			padding_top; -		Optional<S32>			padding_bottom; +		Optional<S32>			padding_left, +								padding_right, +								padding_top, +								padding_bottom;  		Params();  	}; @@ -176,7 +176,7 @@ public:  	virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); -	virtual bool addChild(LLView* child, S32 tab_group); +	virtual bool addChild(LLView* child, S32 tab_group = 0 );  	bool isExpanded() const { return mDisplayChildren; } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index f0f34ebd4f..f26711065a 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -114,7 +114,6 @@ LLButton::LLButton(const LLButton::Params& p)  	mFlashing( FALSE ),  	mCurGlowStrength(0.f),  	mNeedsHighlight(FALSE), -	mMouseOver(false),  	mUnselectedLabel(p.label()),  	mSelectedLabel(p.label_selected()),  	mGLFont(p.font), @@ -499,19 +498,14 @@ void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)  	LLUICtrl::onMouseEnter(x, y, mask);  	if (isInEnabledChain()) -	{  		mNeedsHighlight = TRUE;  	} -	mMouseOver = true; -} -  void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)  {  	LLUICtrl::onMouseLeave(x, y, mask);  	mNeedsHighlight = FALSE; -	mMouseOver = true;  }  void LLButton::setHighlight(bool b) @@ -564,11 +558,19 @@ void LLButton::draw()  		pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));  	} -	// Unselected image assignments +	bool mouse_pressed_and_over = false; +	if (hasMouseCapture()) +	{ +		S32 local_mouse_x ; +		S32 local_mouse_y; +		LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); +		mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); +	} +  	bool enabled = isInEnabledChain();  	bool pressed = pressed_by_keyboard  -					|| (hasMouseCapture() && mMouseOver) +					|| mouse_pressed_and_over  					|| mForcePressedState;  	bool selected = getToggleState(); @@ -1117,7 +1119,7 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)  	// Get the visibility control name for the floater  	std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());  	// Set the button control value (toggle state) to the floater visibility control (Sets the value as well) -	button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); +	button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));  	// Set the clicked callback to toggle the floater  	button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));  } @@ -1131,7 +1133,7 @@ void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)  	// Get the visibility control name for the floater  	std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());  	// Set the button control value (toggle state) to the floater visibility control (Sets the value as well) -	button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); +	button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));  	// Set the clicked callback to toggle the floater  	button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname));  } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index d87ceb7c42..2d5fefa78c 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -350,7 +350,6 @@ private:  	BOOL						mCommitOnReturn;  	BOOL						mFadeWhenDisabled;  	bool						mForcePressedState; -	bool						mMouseOver;  	LLFrameTimer				mFlashingTimer;  }; diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index 0c524cd470..c2a27c2dfd 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -56,9 +56,7 @@ template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(  	const std::string& name, BOOL recurse) const;  LLCheckBoxCtrl::Params::Params() -:	text_enabled_color("text_enabled_color"), -	text_disabled_color("text_disabled_color"), -	initial_value("initial_value", false), +:	initial_value("initial_value", false),  	label_text("label_text"),  	check_button("check_button"),  	radio_style("radio_style") @@ -67,8 +65,8 @@ LLCheckBoxCtrl::Params::Params()  LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)  :	LLUICtrl(p), -	mTextEnabledColor(p.text_enabled_color()), -	mTextDisabledColor(p.text_disabled_color()), +	mTextEnabledColor(p.label_text.text_color()), +	mTextDisabledColor(p.label_text.text_readonly_color()),  	mFont(p.font())  {  	mViewModel->setValue(LLSD(p.initial_value)); @@ -95,7 +93,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)  	{  		tbparams.font(p.font);  	} -	tbparams.text_color( p.enabled() ? p.text_enabled_color() : p.text_disabled_color() );  	mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);  	addChild(mLabel); diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 28d50f957d..88f306aff3 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -58,8 +58,6 @@ public:  	struct Params   	:	public LLInitParam::Block<Params, LLUICtrl::Params>  	{ -		Optional<LLUIColor>		text_enabled_color; -		Optional<LLUIColor>		text_disabled_color;  		Optional<bool>			initial_value;	// override LLUICtrl initial_value  		Optional<LLTextBox::Params> label_text; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index cc107c972d..22b4ba87bc 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -145,8 +145,8 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)  	// Grab the mouse-up event and make sure the button state is correct  	mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this)); -	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin(); -		it != p.items().end(); +	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); +		it != p.items.end();  		++it)  	{  		LLScrollListItem::Params item_params = *it; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 838f93d3f9..62669f3823 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -42,6 +42,7 @@  #include "lluictrlfactory.h"  #include "llbutton.h"  #include "llcheckboxctrl.h" +#include "lldir.h"  #include "lldraghandle.h"  #include "llfloaterreg.h"  #include "llfocusmgr.h" @@ -505,7 +506,7 @@ void LLFloater::storeRectControl()  {  	if( mRectControl.size() > 1 )  	{ -		LLUI::sSettingGroups["floater"]->setRect( mRectControl, getRect() ); +		getControlGroup()->setRect( mRectControl, getRect() );  	}  } @@ -513,7 +514,7 @@ void LLFloater::storeVisibilityControl()  {  	if( !sQuitting && mVisibilityControl.size() > 1 )  	{ -		LLUI::sSettingGroups["floater"]->setBOOL( mVisibilityControl, getVisible() ); +		getControlGroup()->setBOOL( mVisibilityControl, getVisible() );  	}  } @@ -521,10 +522,47 @@ void LLFloater::storeDockStateControl()  {  	if( !sQuitting && mDocStateControl.size() > 1 )  	{ -		LLUI::sSettingGroups["floater"]->setBOOL( mDocStateControl, isDocked() ); +		getControlGroup()->setBOOL( mDocStateControl, isDocked() );  	}  } +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) +{ +	std::string ctrl_name = name; + +	// Add the key to the control name if appropriate. +	if (key.isString() && !key.asString().empty()) +	{ +		ctrl_name += "_" + key.asString(); +	} + +	return ctrl_name; +} + +// static +LLControlGroup*	LLFloater::getControlGroup() +{ +	// Floater size, position, visibility, etc are saved in per-account settings. +	return LLUI::sSettingGroups["account"]; +}  void LLFloater::setVisible( BOOL visible )  { @@ -781,7 +819,7 @@ void LLFloater::applyRectControl()  	// override center if we have saved rect control  	if (mRectControl.size() > 1)  	{ -		const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl); +		const LLRect& rect = getControlGroup()->getRect(mRectControl);  		if (rect.getWidth() > 0 && rect.getHeight() > 0)  		{  			translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); @@ -797,7 +835,7 @@ void LLFloater::applyDockState()  {  	if (mDocStateControl.size() > 1)  	{ -		bool dockState = LLUI::sSettingGroups["floater"]->getBOOL(mDocStateControl); +		bool dockState = getControlGroup()->getBOOL(mDocStateControl);  		setDocked(dockState);  	} @@ -1960,6 +1998,7 @@ LLFloaterView::LLFloaterView (const Params& p)  :	LLUICtrl (p),  	mFocusCycleMode(FALSE), +	mMinimizePositionVOffset(0),  	mSnapOffsetBottom(0),  	mSnapOffsetRight(0)  { @@ -2358,7 +2397,9 @@ void LLFloaterView::closeAllChildren(bool app_quitting)  		// Attempt to close floater.  This will cause the "do you want to save"  		// dialogs to appear. -		if (floaterp->canClose() && !floaterp->isDead()) +		// Skip invisible floaters if we're not quitting (STORM-192). +		if (floaterp->canClose() && !floaterp->isDead() && +			(app_quitting || floaterp->getVisible()))  		{  			floaterp->closeFloater(app_quitting);  		} @@ -2670,18 +2711,20 @@ void LLFloater::setInstanceName(const std::string& name)  	mInstanceName = name;  	if (!mInstanceName.empty())  	{ +		std::string ctrl_name = getControlName(mInstanceName, mKey); +  		// save_rect and save_visibility only apply to registered floaters  		if (!mRectControl.empty())  		{ -			mRectControl = LLFloaterReg::declareRectControl(mInstanceName); +			mRectControl = LLFloaterReg::declareRectControl(ctrl_name);  		}  		if (!mVisibilityControl.empty())  		{ -			mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName); +			mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name);  		}  		if(!mDocStateControl.empty())  		{ -			mDocStateControl = LLFloaterReg::declareDockStateControl(mInstanceName); +			mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);  		}  	} @@ -2779,7 +2822,8 @@ LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build");  bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)  {  	Params params(LLUICtrlFactory::getDefaultParams<LLFloater>()); -	LLXUIParser::instance().readXUI(node, params, filename); // *TODO: Error checking +	LLXUIParser parser; +	parser.readXUI(node, params, filename); // *TODO: Error checking  	if (output_node)  	{ @@ -2787,8 +2831,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str  		setupParamsForExport(output_params, parent);          Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());  		output_node->setName(node->getName()->mString); -		LLXUIParser::instance().writeXUI( -			output_node, output_params, &default_params); +		parser.writeXUI(output_node, output_params, &default_params);  	}  	// Default floater position to top-left corner of screen @@ -2883,3 +2926,64 @@ bool LLFloater::isVisible(const LLFloater* floater)  {      return floater && floater->getVisible();  } + +static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters"); + +bool LLFloater::buildFromFile(const std::string& filename, LLXMLNodePtr output_node) +{ +	LLFastTimer timer(FTM_BUILD_FLOATERS); +	LLXMLNodePtr root; + +	//if exporting, only load the language being exported,  +	//instead of layering localized version on top of english +	if (output_node) +	{ +		if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root)) +		{ +			llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; +			return false; +		} +	} +	else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) +	{ +		llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; +		return false; +	} +	 +	// root must be called floater +	if( !(root->hasName("floater") || root->hasName("multi_floater")) ) +	{ +		llwarns << "Root node should be named floater in: " << filename << llendl; +		return false; +	} +	 +	bool res = true; +	 +	lldebugs << "Building floater " << filename << llendl; +	LLUICtrlFactory::instance().pushFileName(filename); +	{ +		if (!getFactoryMap().empty()) +		{ +			LLPanel::sFactoryStack.push_front(&getFactoryMap()); +		} + +		 // for local registry callbacks; define in constructor, referenced in XUI or postBuild +		getCommitCallbackRegistrar().pushScope(); +		getEnableCallbackRegistrar().pushScope(); +		 +		res = initFloaterXML(root, getParent(), filename, output_node); + +		setXMLFilename(filename); +		 +		getCommitCallbackRegistrar().popScope(); +		getEnableCallbackRegistrar().popScope(); +		 +		if (!getFactoryMap().empty()) +		{ +			LLPanel::sFactoryStack.pop_front(); +		} +	} +	LLUICtrlFactory::instance().popFileName(); +	 +	return res; +} diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 5e482cbac3..c02587d9d8 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -141,6 +141,7 @@ public:  	// Don't export top/left for rect, only height/width  	static void setupParamsForExport(Params& p, LLView* parent); +	bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);  	void initFromParams(const LLFloater::Params& p);  	bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL); @@ -203,6 +204,11 @@ public:  	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();  	bool			isMinimizeable() const{ return mCanMinimize; }  	bool			isCloseable() const{ return mCanClose; } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index 85f9af126c..547a3cf578 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -127,7 +127,7 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)  				res = build_func(key); -				bool success = LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, NULL); +				bool success = res->buildFromFile(xui_file, NULL);  				if (!success)  				{  					llwarns << "Failed to build floater type: '" << name << "'." << llendl; @@ -290,9 +290,9 @@ void LLFloaterReg::showInitialVisibleInstances()  	{  		const std::string& name = iter->first;  		std::string controlname = getVisibilityControlName(name); -		if (LLUI::sSettingGroups["floater"]->controlExists(controlname)) +		if (LLFloater::getControlGroup()->controlExists(controlname))  		{ -			BOOL isvis = LLUI::sSettingGroups["floater"]->getBOOL(controlname); +			BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname);  			if (isvis)  			{  				showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true @@ -346,7 +346,7 @@ std::string LLFloaterReg::getRectControlName(const std::string& name)  std::string LLFloaterReg::declareRectControl(const std::string& name)  {  	std::string controlname = getRectControlName(name); -	LLUI::sSettingGroups["floater"]->declareRect(controlname, LLRect(), +	LLFloater::getControlGroup()->declareRect(controlname, LLRect(),  												 llformat("Window Position and Size for %s", name.c_str()),  												 TRUE);  	return controlname; @@ -364,7 +364,7 @@ std::string LLFloaterReg::getVisibilityControlName(const std::string& name)  std::string LLFloaterReg::declareVisibilityControl(const std::string& name)  {  	std::string controlname = getVisibilityControlName(name); -	LLUI::sSettingGroups["floater"]->declareBOOL(controlname, FALSE, +	LLFloater::getControlGroup()->declareBOOL(controlname, FALSE,  												 llformat("Window Visibility for %s", name.c_str()),  												 TRUE);  	return controlname; @@ -374,7 +374,7 @@ std::string LLFloaterReg::declareVisibilityControl(const std::string& name)  std::string LLFloaterReg::declareDockStateControl(const std::string& name)  {  	std::string controlname = getDockStateControlName(name); -	LLUI::sSettingGroups["floater"]->declareBOOL(controlname, TRUE, +	LLFloater::getControlGroup()->declareBOOL(controlname, TRUE,  												 llformat("Window Docking state for %s", name.c_str()),  												 TRUE);  	return controlname; @@ -397,11 +397,11 @@ void LLFloaterReg::registerControlVariables()  	for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)  	{  		const std::string& name = iter->first; -		if (LLUI::sSettingGroups["floater"]->controlExists(getRectControlName(name))) +		if (LLFloater::getControlGroup()->controlExists(getRectControlName(name)))  		{  			declareRectControl(name);  		} -		if (LLUI::sSettingGroups["floater"]->controlExists(getVisibilityControlName(name))) +		if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))  		{  			declareVisibilityControl(name);  		} @@ -425,7 +425,7 @@ void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LL  	// 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(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); +	ctrl->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));  }  // callback args may use "floatername.key" format diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index b3af258456..589e1ff01a 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -321,6 +321,20 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f  	}  } +bool LLFocusMgr::keyboardFocusHasAccelerators() const +{ +	LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); +	while( focus_view ) +	{ +		if(focus_view->hasAccelerators()) +		{ +			return true; +		} + +		focus_view = focus_view->getParent(); +	} +	return false; +}  void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )  { diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 86d3ccf111..01f1a690b1 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -124,6 +124,8 @@ public:  	void			unlockFocus();  	BOOL			focusLocked() const { return mLockedView != NULL; } +	bool			keyboardFocusHasAccelerators() const; +  private:  	LLUICtrl*			mLockedView; diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 4512091371..2ef77af13d 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -41,95 +41,66 @@  #include "llresizebar.h"  #include "llcriticaldamp.h" -static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML); - +static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack"); +static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");  // -// LLLayoutStack +// LLLayoutPanel  // -struct LLLayoutStack::LayoutPanel -{ -	LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize)	:	mPanel(panelp),  -		mMinWidth(min_width),  -		mMinHeight(min_height), -		mMaxWidth(max_width),  -		mMaxHeight(max_height), -		mAutoResize(auto_resize), -		mUserResize(user_resize), -		mOrientation(orientation), +LLLayoutPanel::LLLayoutPanel(const Params& p)	 +:	LLPanel(p), + 	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)   	{ -		LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; -		LLRect resize_bar_rect = panelp->getRect(); - -		S32 min_dim; -		if (orientation == HORIZONTAL) +	// panels initialized as hidden should not start out partially visible +	if (!getVisible())  		{ -			min_dim = mMinHeight; +		mVisibleAmt = 0.f;  		} -		else -		{ -			min_dim = mMinWidth; -		} -		LLResizeBar::Params p; -		p.name("resize"); -			p.resizing_view(mPanel); -		p.min_size(min_dim); -		p.side(side); -		p.snapping_enabled(false); -		mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p); -		// panels initialized as hidden should not start out partially visible -		if (!mPanel->getVisible()) -		{ -			mVisibleAmt = 0.f;  		} + +void LLLayoutPanel::initFromParams(const Params& p) +		{ +	LLPanel::initFromParams(p); +	setFollowsNone();  	} -	~LayoutPanel() + +LLLayoutPanel::~LLLayoutPanel()  	{  		// probably not necessary, but...  		delete mResizeBar;  		mResizeBar = NULL;  	} -	F32 getCollapseFactor() +F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)  	{ -		if (mOrientation == HORIZONTAL) +	if (orientation == LLLayoutStack::HORIZONTAL)  		{  			F32 collapse_amt =  -				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth())); +			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));  			return mVisibleAmt * collapse_amt;  		}  		else  	{  			F32 collapse_amt =  -				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight()))); +			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));  			return mVisibleAmt * collapse_amt;  		}  	} -	LLPanel* mPanel; -	S32 mMinWidth; -	S32 mMinHeight; - -	// mMaxWidth & mMaxHeight are added to make configurable max width of the nearby chat bar. EXT-5589 -	// they are not processed by LLLayoutStack but they can be if necessary -	S32 mMaxWidth; -	S32 mMaxHeight; -	BOOL mAutoResize; -	BOOL mUserResize; -	BOOL mCollapsed; -	LLResizeBar* mResizeBar; -	ELayoutOrientation mOrientation; -	F32 mVisibleAmt; -	F32 mCollapseAmt; -}; +// +// LLLayoutStack +//  LLLayoutStack::Params::Params() -:	orientation("orientation", std::string("vertical")), +:	orientation("orientation"),  	animate("animate", true),  	clip("clip", true),  	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) @@ -163,18 +134,18 @@ void LLLayoutStack::draw()  	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{  		// clip to layout rectangle, not bounding rectangle -		LLRect clip_rect = (*panel_it)->mPanel->getRect(); +		LLRect clip_rect = (*panel_it)->getRect();  		// scale clipping rectangle by visible amount  		if (mOrientation == HORIZONTAL)  		{ -			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); +			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation));  		}  		else  		{ -			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); +			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation));  		} -		LLPanel* panelp = (*panel_it)->mPanel; +		LLPanel* panelp = (*panel_it);  		LLLocalClipRect clip(clip_rect, mClip);  		// only force drawing invisible children if visible amount is non-zero @@ -185,7 +156,7 @@ void LLLayoutStack::draw()  void LLLayoutStack::removeChild(LLView* view)  { -	LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view)); +	LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));  	if (embedded_panelp)  	{ @@ -206,149 +177,16 @@ BOOL LLLayoutStack::postBuild()  	return TRUE;  } -static void get_attribute_s32_and_write(LLXMLNodePtr node, -										const char* name, -										S32 *value, -										S32 default_value, -										LLXMLNodePtr output_child) -{ -	BOOL has_attr = node->getAttributeS32(name, *value); -	if (has_attr && *value != default_value && output_child) -	{ -		// create an attribute child node -		LLXMLNodePtr child_attr = output_child->createChild(name, TRUE); -		child_attr->setIntValue(*value); -	} -} - -static void get_attribute_bool_and_write(LLXMLNodePtr node, -										const char* name, -										BOOL *value, -										BOOL default_value, -										LLXMLNodePtr output_child) -{ -	BOOL has_attr = node->getAttributeBOOL(name, *value); -	if (has_attr && *value != default_value && output_child) -	{ -		LLXMLNodePtr child_attr = output_child->createChild(name, TRUE); -		child_attr->setBoolValue(*value); -	} -} -//static  -LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) -{ -	LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack>()); -	LLXUIParser::instance().readXUI(node, p, LLUICtrlFactory::getInstance()->getCurFileName()); - -	// Export must happen before setupParams() mungles rectangles and before -	// this item gets added to parent (otherwise screws up last_child_rect -	// logic). JC -	if (output_node) -	{ -		Params output_params(p); -		setupParamsForExport(output_params, parent); -		LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams<LLLayoutStack>()); -		output_node->setName(node->getName()->mString); -		LLXUIParser::instance().writeXUI( -			output_node, output_params, &default_params); -	} - -	p.from_xui = true; -	applyXUILayout(p, parent); -	LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p); - -	if (parent && layout_stackp) -	{ -		S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup(); - -		parent->addChild(layout_stackp, tab_group); -	} - -	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) -	{ -		const S32 DEFAULT_MIN_WIDTH = 0; -		const S32 DEFAULT_MIN_HEIGHT = 0; -		const S32 DEFAULT_MAX_WIDTH = S32_MAX; -		const S32 DEFAULT_MAX_HEIGHT = S32_MAX; -		const BOOL DEFAULT_AUTO_RESIZE = TRUE; - -		S32 min_width = DEFAULT_MIN_WIDTH; -		S32 min_height = DEFAULT_MIN_HEIGHT; -		S32 max_width = DEFAULT_MAX_WIDTH; -		S32 max_height = DEFAULT_MAX_HEIGHT; -		BOOL auto_resize = DEFAULT_AUTO_RESIZE; - -		LLXMLNodePtr output_child; -		if (output_node)  +bool LLLayoutStack::addChild(LLView* child, S32 tab_group)  		{ -			output_child = output_node->createChild("", FALSE); -		} - -		// Layout stack allows child nodes to acquire additional attributes, -		// such as "min_width" in:  <button label="Foo" min_width="100"/> -		// If these attributes exist and have non-default values, write them -		// to the output node. -		get_attribute_s32_and_write(child_node, "min_width", &min_width, -			DEFAULT_MIN_WIDTH, output_child); -		get_attribute_s32_and_write(child_node, "min_height", &min_height, -			DEFAULT_MIN_HEIGHT, output_child); -		get_attribute_s32_and_write(child_node, "max_width", &max_width, -			DEFAULT_MAX_WIDTH, output_child); -		get_attribute_s32_and_write(child_node, "max_height", &max_height, -			DEFAULT_MAX_HEIGHT, output_child); -		get_attribute_bool_and_write(child_node, "auto_resize", &auto_resize, -			DEFAULT_AUTO_RESIZE, output_child); - -		if (child_node->hasName("layout_panel")) -		{ -			BOOL user_resize = TRUE; -			get_attribute_bool_and_write(child_node, "user_resize", &user_resize, -				TRUE, output_child); -			LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child_node, layout_stackp, output_child); +	LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);  			if (panelp)  			{ -				panelp->setFollowsNone(); -				layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize); +		mPanels.push_back(panelp);  			} +	return LLView::addChild(child, tab_group);  		} -		else -		{ -			BOOL user_resize = FALSE; -			get_attribute_bool_and_write(child_node, "user_resize", &user_resize, -				FALSE, output_child); - -			LLPanel::Params p; -			p.mouse_opaque(false); -			LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p); -			LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, LLPanel::child_registry_t::instance(), output_child); -			if (new_child) -			{ -				// put child in new embedded panel -				layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize); -				// resize panel to contain widget and move widget to be contained in panel -				panelp->setRect(new_child->getRect()); -				new_child->setOrigin(0, 0); -			} -			else -			{ -				panelp->die(); -			} -		} -		 -		if (output_child && !output_child->mChildren && output_child->mAttributes.empty() && output_child->getValue().empty()) -		{ -			output_node->deleteChild(output_child); -		} -	} - -	if (!layout_stackp->postBuild()) -	{ -		delete layout_stackp; -		return NULL; -	} -	return layout_stackp; -}  S32 LLLayoutStack::getDefaultHeight(S32 cur_height)  { @@ -374,34 +212,30 @@ S32 LLLayoutStack::getDefaultWidth(S32 cur_width)  	return cur_width;  } -void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index) +void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)  { -	// panel starts off invisible (collapsed) -	if (animate == ANIMATE) -	{ -		panel->setVisible(FALSE); -	} -	LayoutPanel* embedded_panel = new LayoutPanel(panel, mOrientation, min_width, min_height, max_width, max_height, auto_resize, user_resize); -	 -	mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel); -	 -	if (panel->getParent() != this)  -	{ -		addChild(panel); -	} -	addChild(embedded_panel->mResizeBar); +	LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move); +	LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel); -	// 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) +	if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel)  	{ -		LLResizeBar* resize_barp = (*panel_it)->mResizeBar; -		sendChildToFront(resize_barp); +		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); +} + +void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate) +{ +	addChild(panel); -	// start expanding panel animation +	// panel starts off invisible (collapsed)  	if (animate == ANIMATE)  	{ +		panel->mVisibleAmt = 0.f;  		panel->setVisible(TRUE);  	}  } @@ -413,7 +247,7 @@ void LLLayoutStack::removePanel(LLPanel* panel)  void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)  { -	LayoutPanel* panel_container = findEmbeddedPanel(panel); +	LLLayoutPanel* panel_container = findEmbeddedPanel(panel);  	if (!panel_container) return;  	panel_container->mCollapsed = collapsed; @@ -421,7 +255,7 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)  void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)  { -	LayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);  	if (panel)  	{ @@ -431,7 +265,7 @@ void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL au  void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)  { -	LayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);  	if (panel)  	{ @@ -439,27 +273,25 @@ void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_  	}  } -bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp) +bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp)  { -	LayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);  	if (panel)  	{ -		if (min_widthp) *min_widthp = panel->mMinWidth; -		if (min_heightp) *min_heightp = panel->mMinHeight; +		if (min_dimp) *min_dimp = panel->mMinDim;  	}  	return NULL != panel;  } -bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_widthp, S32* max_heightp) +bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp)  { -	LayoutPanel* panel = findEmbeddedPanelByName(panel_name); +	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);  	if (panel)  	{ -		if (max_widthp) *max_widthp = panel->mMaxWidth; -		if (max_heightp) *max_heightp = panel->mMaxHeight; +		if (max_dimp) *max_dimp = panel->mMaxDim;  	}  	return NULL != panel; @@ -471,6 +303,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	LLFastTimer ft(FTM_UPDATE_LAYOUT);  	static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);  	calcMinExtents(); +	createResizeBars();  	// calculate current extents  	S32 total_width = 0; @@ -482,7 +315,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	e_panel_list_t::iterator panel_it;  	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)  	{ -		LLPanel* panelp = (*panel_it)->mPanel; +		LLPanel* panelp = (*panel_it);  		if (panelp->getVisible())   		{  			if (mAnimate) @@ -532,11 +365,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  		if (mOrientation == HORIZONTAL)  		{  			// enforce minimize size constraint by default -			if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth) +			if (panelp->getRect().getWidth() < (*panel_it)->mMinDim)  			{ -				panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight()); +				panelp->reshape((*panel_it)->mMinDim, panelp->getRect().getHeight());  			} -        	total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor()); +        	total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor(mOrientation));          	// want n-1 panel gaps for n panels  			if (panel_it != mPanels.begin())  			{ @@ -546,11 +379,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  		else //VERTICAL  		{  			// enforce minimize size constraint by default -			if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight) +			if (panelp->getRect().getHeight() < (*panel_it)->mMinDim)  			{ -				panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight); +				panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinDim);  			} -			total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor()); +			total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor(mOrientation));  			if (panel_it != mPanels.begin())  			{  				total_height += mPanelSpacing; @@ -564,7 +397,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{  		// panels that are not fully visible do not count towards shrink headroom -		if ((*panel_it)->getCollapseFactor() < 1.f)  +		if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f)   		{  			continue;  		} @@ -577,11 +410,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  		{  			if (mOrientation == HORIZONTAL)  			{ -				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; +				shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;  			}  			else //VERTICAL  			{ -				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; +				shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;  			}  		}  		else @@ -589,13 +422,13 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  			num_resizable_panels++;  			if (mOrientation == HORIZONTAL)  			{ -				shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; -				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth; +				shrink_headroom_available += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim; +				shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;  			}  			else //VERTICAL  			{ -				shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; -				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight; +				shrink_headroom_available += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim; +				shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;  			}  		}  	} @@ -618,17 +451,25 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{ -		LLPanel* panelp = (*panel_it)->mPanel; +		LLPanel* panelp = (*panel_it);  		S32 cur_width = panelp->getRect().getWidth();  		S32 cur_height = panelp->getRect().getHeight(); -		S32 new_width = llmax((*panel_it)->mMinWidth, cur_width); -		S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);  +		S32 new_width = cur_width; +		S32 new_height = cur_height;  +		if (mOrientation == HORIZONTAL) +		{ +			new_width = llmax((*panel_it)->mMinDim, new_width); +		} +		else +		{ +			new_height = llmax((*panel_it)->mMinDim, new_height); +		}  		S32 delta_size = 0;  		// if panel can automatically resize (not animating, and resize flag set)... -		if ((*panel_it)->getCollapseFactor() == 1.f  +		if ((*panel_it)->getCollapseFactor(mOrientation) == 1.f   			&& (force_resize || (*panel_it)->mAutoResize)   			&& !(*panel_it)->mResizeBar->hasMouseCapture())   		{ @@ -639,8 +480,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  				{  					// 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 - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0; -					shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth); +					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0; +					shrink_headroom_available -= (cur_width - (*panel_it)->mMinDim);  				}  				else  				{ @@ -649,7 +490,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  					num_resizable_panels--;  				}  				pixels_to_distribute -= delta_size; -				new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size); +				new_width = llmax((*panel_it)->mMinDim, cur_width + delta_size);  			}  			else  			{ @@ -662,8 +503,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  				{  					// 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 - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0; -					shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight); +					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0; +					shrink_headroom_available -= (cur_height - (*panel_it)->mMinDim);  				}  				else  				{ @@ -671,7 +512,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  					num_resizable_panels--;  				}  				pixels_to_distribute -= delta_size; -				new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size); +				new_height = llmax((*panel_it)->mMinDim, cur_height + delta_size);  			}  			else  			{ @@ -712,11 +553,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  		if (mOrientation == HORIZONTAL)  		{ -			cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing; +			cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;  		}  		else //VERTICAL  		{ -			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing; +			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;  		}  	} @@ -724,19 +565,19 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	LLResizeBar* last_resize_bar = NULL;  	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{ -		LLPanel* panelp = (*panel_it)->mPanel; +		LLPanel* panelp = (*panel_it);  		if (mOrientation == HORIZONTAL)  		{  			(*panel_it)->mResizeBar->setResizeLimits( -				(*panel_it)->mMinWidth,  -				(*panel_it)->mMinWidth + shrink_headroom_total); +				(*panel_it)->mMinDim,  +				(*panel_it)->mMinDim + shrink_headroom_total);  		}  		else //VERTICAL  		{  			(*panel_it)->mResizeBar->setResizeLimits( -				(*panel_it)->mMinHeight,  -				(*panel_it)->mMinHeight + shrink_headroom_total); +				(*panel_it)->mMinDim,  +				(*panel_it)->mMinDim + shrink_headroom_total);  		}  		// toggle resize bars based on panel visibility, resizability, etc @@ -772,14 +613,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  } // end LLLayoutStack::updateLayout -LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const +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)->mPanel == panelp) +		if ((*panel_it) == panelp)  		{  			return *panel_it;  		} @@ -787,15 +628,15 @@ LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) co  	return NULL;  } -LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const +LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const  { -	LayoutPanel* result = NULL; +	LLLayoutPanel* result = NULL;  	for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)  	{ -		LayoutPanel* p = *panel_it; +		LLLayoutPanel* p = *panel_it; -		if (p->mPanel->getName() == name) +		if (p->getName() == name)  		{  			result = p;  			break; @@ -816,9 +657,7 @@ void LLLayoutStack::calcMinExtents()  	{  		if (mOrientation == HORIZONTAL)  		{ -			mMinHeight = llmax(	mMinHeight,  -								(*panel_it)->mMinHeight); -            mMinWidth += (*panel_it)->mMinWidth; +            mMinWidth += (*panel_it)->mMinDim;  			if (panel_it != mPanels.begin())  			{  				mMinWidth += mPanelSpacing; @@ -826,9 +665,7 @@ void LLLayoutStack::calcMinExtents()  		}  		else //VERTICAL  		{ -	        mMinWidth = llmax(	mMinWidth,  -								(*panel_it)->mMinWidth); -			mMinHeight += (*panel_it)->mMinHeight; +			mMinHeight += (*panel_it)->mMinDim;  			if (panel_it != mPanels.begin())  			{  				mMinHeight += mPanelSpacing; @@ -837,6 +674,37 @@ void LLLayoutStack::calcMinExtents()  	}  } +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) +		{ +			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->mMinDim); +			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); +			} +		} +	} +} +  // 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 diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index e454454fe2..e405962cd3 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -34,16 +34,21 @@  #ifndef LL_LLLAYOUTSTACK_H  #define LL_LLLAYOUTSTACK_H -#include "llview.h" +#include "llpanel.h"  class LLPanel; +class LLLayoutPanel; +  class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>  {  public: +	struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry> +	{}; +  	struct Params : public LLInitParam::Block<Params, LLView::Params>  	{ -		Optional<std::string>	orientation; +		Mandatory<std::string>	orientation;  		Optional<S32>			border_size;  		Optional<bool>			animate,  								clip; @@ -51,6 +56,8 @@ public:  		Params();  	}; +	typedef LayoutStackRegistry child_registry_t; +  	typedef enum e_layout_orientation  	{  		HORIZONTAL, @@ -62,6 +69,7 @@ public:  	/*virtual*/ void draw();  	/*virtual*/ void removeChild(LLView*);  	/*virtual*/ BOOL postBuild(); +	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);  	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); @@ -74,29 +82,32 @@ public:  		ANIMATE  	} EAnimate; -	void addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX); +	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 width and/or height of the specified by name panel. +	 * Gets minimal dimension along layout_stack axis of the specified by name panel.  	 * -	 * If it is necessary to get only the one dimension pass NULL for another one.  	 * @returns true if specified by panel_name internal panel exists, false otherwise.  	 */ -	bool getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp); +	bool getPanelMinSize(const std::string& panel_name, S32* min_dimp);  	/** -	 * Gets maximal width and/or height of the specified by name panel. +	 * Gets maximal dimension along layout_stack axis of the specified by name panel.  	 * -	 * If it is necessary to get only the one dimension pass NULL for another one.  	 * @returns true if specified by panel_name internal panel exists, false otherwise.  	 */ -	bool getPanelMaxSize(const std::string& panel_name, S32* max_width, S32* max_height); +	bool getPanelMaxSize(const std::string& panel_name, S32* max_dim);  	void updateLayout(BOOL force_resize = FALSE); @@ -111,19 +122,18 @@ protected:  	friend class LLUICtrlFactory;  private: -	struct LayoutPanel; - +	void createResizeBars();  	void calcMinExtents();  	S32 getDefaultHeight(S32 cur_height);  	S32 getDefaultWidth(S32 cur_width);  	const ELayoutOrientation mOrientation; -	typedef std::vector<LayoutPanel*> e_panel_list_t; +	typedef std::vector<LLLayoutPanel*> e_panel_list_t;  	e_panel_list_t mPanels; -	LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const; -	LayoutPanel* findEmbeddedPanelByName(const std::string& name) const; +	LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const; +	LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const;  	S32 mMinWidth;  // calculated by calcMinExtents  	S32 mMinHeight;  // calculated by calcMinExtents @@ -135,4 +145,49 @@ private:  	bool mClip;  }; // end class LLLayoutStack +class LLLayoutPanel : public LLPanel +{ +friend class LLLayoutStack; +friend class LLUICtrlFactory; +public: +	struct Params : public LLInitParam::Block<Params, LLPanel::Params> +	{ +		Optional<S32>			min_dim, +								max_dim; +		Optional<bool>			user_resize, +								auto_resize; + +		Params() +		:	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"); +		} +	}; + +	~LLLayoutPanel(); + +	void initFromParams(const Params& p); +protected: +	LLLayoutPanel(const Params& p)	; + +	 +	F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation); + +	S32 mMinDim; +	S32 mMaxDim; +	BOOL mAutoResize; +	BOOL mUserResize; +	BOOL mCollapsed; +	class LLResizeBar* mResizeBar; +	F32 mVisibleAmt; +	F32 mCollapseAmt; +}; + +  #endif diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 6564158ccc..9822d8172e 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1281,7 +1281,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)  			if( mCurrentHistoryLine > mLineHistory.begin() )  			{  				mText.assign( *(--mCurrentHistoryLine) ); -				setCursor(llmin((S32)mText.length(), getCursor())); +				setCursorToEnd();  			}  			else  			{ @@ -1298,7 +1298,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)  			if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 )  			{  				mText.assign( *(++mCurrentHistoryLine) ); -				setCursor(llmin((S32)mText.length(), getCursor())); +				setCursorToEnd();  			}  			else  			{ diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 46a7215707..d4b698a7bf 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -77,10 +77,6 @@ S32 MENU_BAR_WIDTH = 0;  /// Local function declarations, constants, enums, and typedefs  ///============================================================================ -const std::string SEPARATOR_NAME("separator"); -const std::string SEPARATOR_LABEL( "-----------" ); -const std::string VERTICAL_SEPARATOR_LABEL( "|" ); -  const S32 LABEL_BOTTOM_PAD_PIXELS = 2;  const U32 LEFT_PAD_PIXELS = 3; @@ -99,10 +95,14 @@ const U32 SEPARATOR_HEIGHT_PIXELS = 8;  const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;  const S32 MENU_ITEM_PADDING = 4; -const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK -const std::string BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE -const std::string ARROW_UP  ("^^^^^^^"); -const std::string ARROW_DOWN("vvvvvvv"); +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 +const std::string LLMenuGL::BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE +const std::string LLMenuGL::ARROW_UP  ("^^^^^^^"); +const std::string LLMenuGL::ARROW_DOWN("vvvvvvv");  const F32 MAX_MOUSE_SLOPE_SUB_MENU = 0.9f; @@ -921,7 +921,7 @@ void LLMenuItemCheckGL::setValue(const LLSD& value)  	LLUICtrl::setValue(value);  	if(value.asBoolean())  	{ -		mDrawBoolLabel = BOOLEAN_TRUE_PREFIX; +		mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX;  	}  	else  	{ @@ -954,7 +954,7 @@ void LLMenuItemCheckGL::buildDrawLabel( void )  	}  	if(getValue().asBoolean())  	{ -		mDrawBoolLabel = BOOLEAN_TRUE_PREFIX; +		mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX;  	}  	else  	{ @@ -1064,7 +1064,7 @@ void LLMenuItemBranchGL::buildDrawLabel( void )  	std::string st = mDrawAccelLabel;  	appendAcceleratorString( st );  	mDrawAccelLabel = st; -	mDrawBranchLabel = BRANCH_SUFFIX; +	mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX;  }  void LLMenuItemBranchGL::onCommit( void ) @@ -3744,8 +3744,7 @@ void LLContextMenuBranch::buildDrawLabel( void )  	appendAcceleratorString( st );  	mDrawAccelLabel = st; -	// No special branch suffix -	mDrawBranchLabel.clear(); +	mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX;  }  void	LLContextMenuBranch::showSubMenu() diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index bf40163dac..5090cb0260 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -397,6 +397,12 @@ public:  	void initFromParams(const Params&); +	// textual artwork which menugl-imitators may want to match +	static const std::string BOOLEAN_TRUE_PREFIX; +	static const std::string BRANCH_SUFFIX; +	static const std::string ARROW_UP; +	static const std::string ARROW_DOWN; +  protected:  	LLMenuGL(const LLMenuGL::Params& p);  	friend class LLUICtrlFactory; diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 27a727fdf5..3b89b138c3 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -107,8 +107,8 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)  		setMouseUpCallback(initCommitCallback(p.mouse_up_callback));  	} -	for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders().begin(); -		it != p.sliders().end(); +	for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin(); +		it != p.sliders.end();  		++it)  	{  		if (it->name.isProvided()) diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7fa3c2cf65..8581881735 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -33,6 +33,7 @@  #include "linden_common.h"  #include "llnotifications.h" +#include "llnotificationtemplate.h"  #include "llinstantmessage.h"  #include "llxmlnode.h" @@ -43,6 +44,8 @@  #include "lltrans.h"  #include "llnotificationslistener.h"  #include "llstring.h" +#include "llsdparam.h" +#include "llsdutil.h"  #include <algorithm>  #include <boost/regex.hpp> @@ -50,6 +53,56 @@  const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; +void NotificationPriorityValues::declareValues() +{ +	declare("low", NOTIFICATION_PRIORITY_LOW); +	declare("normal", NOTIFICATION_PRIORITY_NORMAL); +	declare("high", NOTIFICATION_PRIORITY_HIGH); +	declare("critical", NOTIFICATION_PRIORITY_CRITICAL); +} + +LLNotificationForm::FormElementBase::FormElementBase() +:	name("name") +{} + +LLNotificationForm::FormIgnore::FormIgnore() +:	text("text"), +	control("control"), +	invert_control("invert_control", true), +	save_option("save_option", false) +{} + +LLNotificationForm::FormButton::FormButton() +:	index("index"), +	text("text"), +	ignore("ignore"), +	is_default("default"), +	type("type") +{ +	// set type here so it gets serialized +	type = "button"; +} + +LLNotificationForm::FormInput::FormInput() +:	type("type"), +	width("width", 0) +{} + +LLNotificationForm::FormElement::FormElement() +:	button("button"), +	input("input") +{} + +LLNotificationForm::FormElements::FormElements() +:	elements("") +{} + +LLNotificationForm::Params::Params() +:	name("name"), +	ignore("ignore"), +	form_elements("") +{} +  // Local channel for persistent notifications  // Stores only persistent notifications.  // Class users can use connectChanged() to process persistent notifications @@ -94,12 +147,7 @@ bool filterIgnoredNotifications(LLNotificationPtr notification)  	LLNotificationFormPtr form = notification->getForm();  	// Check to see if the user wants to ignore this alert -	if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO) -	{ -		return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName()); -	} - -	return true; +	return !notification->getForm()->getIgnored();  }  bool handleIgnoredNotification(const LLSD& payload) @@ -141,63 +189,68 @@ namespace LLNotificationFilters  };  LLNotificationForm::LLNotificationForm() -:	mFormData(LLSD::emptyArray()), -	mIgnore(IGNORE_NO) +:	mIgnore(IGNORE_NO)  {  } -LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node)  -:	mFormData(LLSD::emptyArray()), -	mIgnore(IGNORE_NO) +LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)  +:	mIgnore(IGNORE_NO), +	mInvertSetting(true) // ignore settings by default mean true=show, false=ignore  { -	if (!xml_node->hasName("form")) +	if (p.ignore.isProvided())  	{ -		llwarns << "Bad xml node for form: " << xml_node->getName() << llendl; -	} -	LLXMLNodePtr child = xml_node->getFirstChild(); -	while(child) -	{ -		child = LLNotifications::instance().checkForXMLTemplate(child); +		mIgnoreMsg = p.ignore.text; -		LLSD item_entry; -		std::string element_name = child->getName()->mString; +		if (!p.ignore.save_option) +		{ +			mIgnore = IGNORE_WITH_DEFAULT_RESPONSE; +		} +		else +		{ +			// remember last option chosen by user and automatically respond with that in the future +			mIgnore = IGNORE_WITH_LAST_RESPONSE; +			LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); +		} -		if (element_name == "ignore" ) +		BOOL show_notification = TRUE; +		if (p.ignore.control.isProvided())  		{ -			bool save_option = false; -			child->getAttribute_bool("save_option", save_option); -			if (!save_option) -			{ -				mIgnore = IGNORE_WITH_DEFAULT_RESPONSE; -			} -			else -			{ -				// remember last option chosen by user and automatically respond with that in the future -				mIgnore = IGNORE_WITH_LAST_RESPONSE; -				LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); -			} -			child->getAttributeString("text", mIgnoreMsg); -			BOOL show_notification = TRUE; -			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE); +			mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control); +			mInvertSetting = p.ignore.invert_control;  		}  		else  		{ -			// flatten xml form entry into single LLSD map with type==name -			item_entry["type"] = element_name; -			const LLXMLAttribList::iterator attrib_end = child->mAttributes.end(); -			for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin(); -				attrib_it != attrib_end; -				++attrib_it) -			{ -				item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue(); -			} -			item_entry["value"] = child->getTextContents(); -			mFormData.append(item_entry); +			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE); +			mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);  		} +	} + +	LLParamSDParser parser; +	parser.writeSD(mFormData, p.form_elements); + +	mFormData = mFormData[""]; +	if (!mFormData.isArray()) +	{ +		// change existing contents to a one element array +		LLSD new_llsd_array = LLSD::emptyArray(); +		new_llsd_array.append(mFormData); +		mFormData = new_llsd_array; +	} -		child = child->getNextSibling(); +	for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray(); +		it != end_it; +		++it) +	{ +		// lift contents of form element up a level, since element type is already encoded in "type" param +		if (it->isMap() && it->beginMap() != it->endMap()) +		{ +			*it = it->beginMap()->second; +		}  	} + +	LL_DEBUGS("Notifications") << name << LL_ENDL; +	LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL;  }  LLNotificationForm::LLNotificationForm(const LLSD& sd) @@ -299,16 +352,64 @@ std::string LLNotificationForm::getDefaultOption()  	return "";  } -LLNotificationTemplate::LLNotificationTemplate() : -	mExpireSeconds(0), -	mExpireOption(-1), -	mURLOption(-1), -	mURLOpenExternally(-1), -	mPersist(false), -	mUnique(false), -	mPriority(NOTIFICATION_PRIORITY_NORMAL) +LLControlVariablePtr LLNotificationForm::getIgnoreSetting()  +{  +	return mIgnoreSetting;  +} + +bool LLNotificationForm::getIgnored() +{ +	bool ignored = false; +	if (mIgnore != LLNotificationForm::IGNORE_NO +		&& mIgnoreSetting)  +	{ +		ignored = mIgnoreSetting->getValue().asBoolean(); +		if (mInvertSetting) ignored = !ignored; +	} + +	return ignored; +} + +void LLNotificationForm::setIgnored(bool ignored)  { -	mForm = LLNotificationFormPtr(new LLNotificationForm());  +	if (mIgnoreSetting) +	{ +		if (mInvertSetting) ignored = !ignored; +		mIgnoreSetting->setValue(ignored); +	} +} + +LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p) +:	mName(p.name), +	mType(p.type), +	mMessage(p.value), +	mLabel(p.label), +	mIcon(p.icon), +	mURL(p.url.value), +	mExpireSeconds(p.duration), +	mExpireOption(p.expire_option), +	mURLOption(p.url.option), +	mURLTarget(p.url.target), +	mUnique(p.unique.isProvided()), +	mPriority(p.priority), +	mPersist(p.persist), +	mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()) +{ +	if (p.sound.isProvided() +		&& LLUI::sSettingGroups["config"]->controlExists(p.sound)) +	{ +		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) +	{ +		mUniqueContext.push_back(it->key); +	} + +	mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));  }  LLNotification::LLNotification(const LLNotification::Params& p) :  @@ -505,7 +606,7 @@ void LLNotification::respond(const LLSD& response)  	{  		mResponder->handleRespond(asLLSD(), response);  	} -	else +	else if (!mResponseFunctorName.empty())  	{  		// look up the functor  		LLNotificationFunctorRegistry::ResponseFunctor functor = @@ -513,6 +614,11 @@ void LLNotification::respond(const LLSD& response)  		// and then call it  		functor(asLLSD(), response);  	} +	else +	{ +		// no registered responder +		return; +	}  	if (mTemporaryResponder && !isReusable())  	{ @@ -523,8 +629,7 @@ void LLNotification::respond(const LLSD& response)  	if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)  	{ -		BOOL show_notification = mIgnored ? FALSE : TRUE; -		LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification); +		mForm->setIgnored(mIgnored);  		if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)  		{  			LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response); @@ -534,6 +639,49 @@ void LLNotification::respond(const LLSD& response)  	update();  } +void LLNotification::respondWithDefault() +{ +	respond(getResponseTemplate(WITH_DEFAULT_BUTTON)); +} + + +const std::string& LLNotification::getName() const +{ +	return mTemplatep->mName; +} + +const std::string& LLNotification::getIcon() const +{ +	return mTemplatep->mIcon; +} + + +bool LLNotification::isPersistent() const +{ +	return mTemplatep->mPersist; +} + +std::string LLNotification::getType() const +{ +	return (mTemplatep ? mTemplatep->mType : ""); +} + +S32 LLNotification::getURLOption() const +{ +	return (mTemplatep ? mTemplatep->mURLOption : -1); +} + +S32 LLNotification::getURLOpenExternally() const +{ +	return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); +} + +bool LLNotification::hasUniquenessConstraints() const  +{  +	return (mTemplatep ? mTemplatep->mUnique : false); +} + +  void LLNotification::setIgnored(bool ignore)  {  	mIgnored = ignore; @@ -613,6 +761,8 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele  	// apply substitution to form labels  	mForm->formatElements(mSubstitutions); +	mIgnored = mForm->getIgnored(); +  	LLDate rightnow = LLDate::now();  	if (mTemplatep->mExpireSeconds)  	{ @@ -1101,11 +1251,6 @@ bool LLNotifications::templateExists(const std::string& name)  	return (mTemplates.count(name) != 0);  } -void LLNotifications::clearTemplates() -{ -	mTemplates.clear(); -} -  void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)  {  	LLNotificationPtr temp_notify(new LLNotification(params)); @@ -1168,190 +1313,88 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)  	}  } -// private to this file -// returns true if the template request was invalid and there's nothing else we -// can do with this node, false if you should keep processing (it may have -// replaced the contents of the node referred to) -LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item) +void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace)  { -	if (item->hasName("usetemplate")) +	if (form.ignore.isProvided() && form.ignore.text() == pattern)  	{ -		std::string replacementName; -		if (item->getAttributeString("name", replacementName)) +		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) +	{ +		if (it->button.isChosen() && it->button.text() == pattern)  		{ -			StringMap replacements; -			for (LLXMLAttribList::const_iterator it=item->mAttributes.begin();  -				 it != item->mAttributes.end(); ++it) -			{ -				replacements[it->second->getName()->mString] = it->second->getValue(); -			} -			if (mXmlTemplates.count(replacementName)) -			{ -				item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]); -				 -				// walk the nodes looking for $(substitution) here and replace -				replaceSubstitutionStrings(item, replacements); -			} -			else -			{ -				llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl; -			} +			it->button.text = replace;  		}  	} -	return item;  }  bool LLNotifications::loadTemplates()  {  	const std::string xml_filename = "notifications.xml"; +	std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename); +  	LLXMLNodePtr root; -	  	BOOL success  = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);  	if (!success || root.isNull() || !root->hasName( "notifications" ))  	{ -		llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; +		llerrs << "Problem reading UI Notifications file: " << full_filename << llendl;  		return false;  	} -	 -	clearTemplates(); -	 -	for (LLXMLNodePtr item = root->getFirstChild(); -		 item.notNull(); item = item->getNextSibling()) -	{ -		// we do this FIRST so that item can be changed if we  -		// encounter a usetemplate -- we just replace the -		// current xml node and keep processing -		item = checkForXMLTemplate(item); -		 -		if (item->hasName("global")) -		{ -			std::string global_name; -			if (item->getAttributeString("name", global_name)) -			{ -				mGlobalStrings[global_name] = item->getTextContents(); -			} -			continue; -		} -		 -		if (item->hasName("template")) -		{ -			// store an xml template; templates must have a single node (can contain -			// other nodes) -			std::string name; -			item->getAttributeString("name", name); -			LLXMLNodePtr ptr = item->getFirstChild(); -			mXmlTemplates[name] = ptr; -			continue; -		} -		 -		if (!item->hasName("notification")) -		{ -            llwarns << "Unexpected entity " << item->getName()->mString <<  -                       " found in " << xml_filename << llendl; -			continue; -		} -		 -		// now we know we have a notification entry, so let's build it -		LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate()); -		if (!item->getAttributeString("name", pTemplate->mName)) -		{ -			llwarns << "Unable to parse notification with no name" << llendl; -			continue; -		} -		 -		//llinfos << "Parsing " << pTemplate->mName << llendl; -		 -		pTemplate->mMessage = item->getTextContents(); -		pTemplate->mDefaultFunctor = pTemplate->mName; -		item->getAttributeString("type", pTemplate->mType); -		item->getAttributeString("icon", pTemplate->mIcon); -		item->getAttributeString("label", pTemplate->mLabel); -		item->getAttributeU32("duration", pTemplate->mExpireSeconds); -		item->getAttributeU32("expireOption", pTemplate->mExpireOption); - -		std::string priority; -		item->getAttributeString("priority", priority); -		pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; -		if (!priority.empty()) -		{ -			if (priority == "low")      pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW; -			if (priority == "normal")   pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; -			if (priority == "high")     pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH; -			if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL; -		} -		 -		item->getAttributeString("functor", pTemplate->mDefaultFunctor); - -		BOOL persist = false; -		item->getAttributeBOOL("persist", persist); -		pTemplate->mPersist = persist; -		 -		std::string sound; -		item->getAttributeString("sound", sound); -		if (!sound.empty()) +	LLNotificationTemplate::Notifications params; +	LLXUIParser parser; +	parser.readXUI(root, params, full_filename); + +	mTemplates.clear(); + +	for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings.begin(), end_it = params.strings.end(); +		it != end_it; +		++it) +	{ +		mGlobalStrings[it->name] = it->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) +	{ +		form_templates[it->name] = it->form; +	} + +	for(LLInitParam::ParamIterator<LLNotificationTemplate::Params>::iterator it = params.notifications.begin(), end_it = params.notifications.end(); +		it != end_it; +		++it) +	{ +		if (it->form_ref.form_template.isChosen())  		{ -			// test for bad sound effect name / missing effect -			if (LLUI::sSettingGroups["config"]->controlExists(sound)) +			// 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())  			{ -				pTemplate->mSoundEffect =  -					LLUUID(LLUI::sSettingGroups["config"]->getString(sound)); +				replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text);  			} -			else +			if(it->form_ref.form_template.no_text.isProvided())  			{ -				llwarns << "Unknown sound effect control name " << sound -					<< llendl; +				replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text);  			} -		} - -		for (LLXMLNodePtr child = item->getFirstChild(); -			 !child.isNull(); child = child->getNextSibling()) -		{ -			child = checkForXMLTemplate(child); -			 -			// <url> -			if (child->hasName("url")) +			if(it->form_ref.form_template.cancel_text.isProvided())  			{ -				pTemplate->mURL = child->getTextContents(); -				child->getAttributeU32("option", pTemplate->mURLOption); -				child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally); +				replaceFormText(it->form_ref.form, "$canceltext", it->form_ref.form_template.cancel_text);  			} -			 -            if (child->hasName("unique")) -            { -                pTemplate->mUnique = true; -                for (LLXMLNodePtr formitem = child->getFirstChild(); -                     !formitem.isNull(); formitem = formitem->getNextSibling()) -                { -                    if (formitem->hasName("context")) -                    { -                        std::string key; -                        formitem->getAttributeString("key", key); -                        pTemplate->mUniqueContext.push_back(key); -                        //llwarns << "adding " << key << " to unique context" << llendl; -                    } -                    else -                    { -                        llwarns << "'unique' has unrecognized subelement "  -                        << formitem->getName()->mString << llendl; -                    } -                } -            } -             -			// <form> -			if (child->hasName("form")) +			if(it->form_ref.form_template.ignore_text.isProvided())  			{ -                pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child)); +				replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text);  			}  		} -		addTemplate(pTemplate->mName, pTemplate); +		addTemplate(it->name, LLNotificationTemplatePtr(new LLNotificationTemplate(*it)));  	} -	 -	//std::ostringstream ostream; -	//root->writeToOstream(ostream, "\n  "); -	//llwarns << ostream.str() << llendl; -	 +  	return true;  } @@ -1402,6 +1445,8 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)  void LLNotifications::add(const LLNotificationPtr pNotif)  { +	if (pNotif == NULL) return; +  	// first see if we already have it -- if so, that's a problem  	LLNotificationSet::iterator it=mItems.find(pNotif);  	if (it != mItems.end()) @@ -1414,6 +1459,8 @@ void LLNotifications::add(const LLNotificationPtr pNotif)  void LLNotifications::cancel(LLNotificationPtr pNotif)  { +	if (pNotif == NULL) return; +  	LLNotificationSet::iterator it=mItems.find(pNotif);  	if (it == mItems.end())  	{ @@ -1423,6 +1470,30 @@ void LLNotifications::cancel(LLNotificationPtr pNotif)  	updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);  } +void LLNotifications::cancelByName(const std::string& name) +{ +	std::vector<LLNotificationPtr> notifs_to_cancel; +	for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); +		it != end_it; +		++it) +	{ +		LLNotificationPtr pNotif = *it; +		if (pNotif->getName() == name) +		{ +			notifs_to_cancel.push_back(pNotif); +		} +	} + +	for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); +		it != end_it; +		++it) +	{ +		LLNotificationPtr pNotif = *it; +		pNotif->cancel(); +		updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); +	} +} +  void LLNotifications::update(const LLNotificationPtr pNotif)  {  	LLNotificationSet::iterator it=mItems.find(pNotif); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1cdd744a68..045f94ab12 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -106,7 +106,6 @@  #include "llnotificationptr.h"  #include "llcachename.h" -	  typedef enum e_notification_priority  {  	NOTIFICATION_PRIORITY_UNSPECIFIED, @@ -116,6 +115,11 @@ typedef enum e_notification_priority  	NOTIFICATION_PRIORITY_CRITICAL  } ENotificationPriority; +struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues> +{ +	static void declareValues(); +}; +  class LLNotificationResponderInterface  {  public: @@ -163,6 +167,66 @@ class LLNotificationForm  	LOG_CLASS(LLNotificationForm);  public: +	struct FormElementBase : public LLInitParam::Block<FormElementBase> +	{ +		Optional<std::string>	name; + +		FormElementBase(); +	}; + +	struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase> +	{ +		Optional<std::string>	text; +		Optional<bool>			save_option; +		Optional<std::string>	control; +		Optional<bool>			invert_control; + +		FormIgnore(); +	}; + +	struct FormButton : public LLInitParam::Block<FormButton, FormElementBase> +	{ +		Mandatory<S32>			index; +		Mandatory<std::string>	text; +		Optional<std::string>	ignore; +		Optional<bool>			is_default; + +		Mandatory<std::string>	type; + +		FormButton(); +	}; + +	struct FormInput : public LLInitParam::Block<FormInput, FormElementBase> +	{ +		Mandatory<std::string>	type; +		Optional<S32>			width; + +		FormInput(); +	}; + +	struct FormElement : public LLInitParam::Choice<FormElement> +	{ +		Alternative<FormButton> button; +		Alternative<FormInput>	input; + +		FormElement(); +	}; + +	struct FormElements : public LLInitParam::Block<FormElements> +	{ +		Multiple<FormElement> elements; +		FormElements(); +	}; + +	struct Params : public LLInitParam::Block<Params> +	{ +		Optional<std::string>	name; +		Optional<FormIgnore>	ignore; +		Optional<FormElements>	form_elements; + +		Params(); +	}; +  	typedef enum e_ignore_type  	{   		IGNORE_NO, @@ -173,8 +237,7 @@ public:  	LLNotificationForm();  	LLNotificationForm(const LLSD& sd); -	LLNotificationForm(const std::string& name,  -		const LLPointer<class LLXMLNode> xml_node); +	LLNotificationForm(const std::string& name, const Params& p);  	LLSD asLLSD() const; @@ -187,92 +250,25 @@ public:  	// appends form elements from another form serialized as LLSD  	void append(const LLSD& sub_form);  	std::string getDefaultOption(); +	LLPointer<class LLControlVariable> getIgnoreSetting(); +	bool getIgnored(); +	void setIgnored(bool ignored);  	EIgnoreType getIgnoreType() { return mIgnore; }  	std::string getIgnoreMessage() { return mIgnoreMsg; }  private: -	LLSD	mFormData; -	EIgnoreType mIgnore; -	std::string mIgnoreMsg; +	LLSD								mFormData; +	EIgnoreType							mIgnore; +	std::string							mIgnoreMsg; +	LLPointer<class LLControlVariable>	mIgnoreSetting; +	bool								mInvertSetting;  };  typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr; -// This is the class of object read from the XML file (notifications.xml,  -// from the appropriate local language directory). -struct LLNotificationTemplate -{ -	LLNotificationTemplate(); -    // the name of the notification -- the key used to identify it -    // Ideally, the key should follow variable naming rules  -    // (no spaces or punctuation). -    std::string mName; -    // The type of the notification -    // used to control which queue it's stored in -    std::string mType; -    // The text used to display the notification. Replaceable parameters -    // are enclosed in square brackets like this []. -    std::string mMessage; -	// The label for the notification; used for  -	// certain classes of notification (those with a window and a window title).  -	// Also used when a notification pops up underneath the current one. -	// Replaceable parameters can be used in the label. -	std::string mLabel; -	// The name of the icon image. This should include an extension. -	std::string mIcon; -    // This is the Highlander bit -- "There Can Be Only One" -    // An outstanding notification with this bit set -    // is updated by an incoming notification with the same name, -    // rather than creating a new entry in the queue. -    // (used for things like progress indications, or repeating warnings -    // like "the grid is going down in N minutes") -    bool mUnique; -    // if we want to be unique only if a certain part of the payload is constant -    // specify the field names for the payload. The notification will only be -    // combined if all of the fields named in the context are identical in the -    // new and the old notification; otherwise, the notification will be -    // duplicated. This is to support suppressing duplicate offers from the same -    // sender but still differentiating different offers. Example: Invitation to -    // conference chat. -    std::vector<std::string> mUniqueContext; -    // If this notification expires automatically, this value will be  -    // nonzero, and indicates the number of seconds for which the notification -    // will be valid (a teleport offer, for example, might be valid for  -    // 300 seconds).  -    U32 mExpireSeconds; -    // if the offer expires, one of the options is chosen automatically -    // based on its "value" parameter. This controls which one.  -    // If expireSeconds is specified, expireOption should also be specified. -    U32 mExpireOption; -    // if the notification contains a url, it's stored here (and replaced  -    // into the message where [_URL] is found) -    std::string mURL; -    // if there's a URL in the message, this controls which option visits -    // that URL. Obsolete this and eliminate the buttons for affected -    // messages when we allow clickable URLs in the UI -    U32 mURLOption; -	 -	U32 mURLOpenExternally; -	//This is a flag that tells if the url needs to open externally dispite  -	//what the user setting is. -	 -	// does this notification persist across sessions? if so, it will be -	// serialized to disk on first receipt and read on startup -	bool mPersist; -	// This is the name of the default functor, if present, to be -	// used for the notification's callback. It is optional, and used only if  -	// the notification is constructed without an identified functor. -	std::string mDefaultFunctor; -	// The form data associated with a given notification (buttons, text boxes, etc) -    LLNotificationFormPtr mForm; -	// default priority for notifications of this type -	ENotificationPriority mPriority; -	// UUID of the audio file to be played when this notification arrives -	// this is loaded as a name, but looked up to get the UUID upon template load. -	// If null, it wasn't specified. -	LLUUID mSoundEffect; -}; + +struct LLNotificationTemplate;  // we want to keep a map of these by name, and it's best to manage them  // with smart pointers @@ -308,7 +304,7 @@ public:  		// optional  		Optional<LLSD>							substitutions;  		Optional<LLSD>							payload; -		Optional<ENotificationPriority>			priority; +		Optional<ENotificationPriority, NotificationPriorityValues>	priority;  		Optional<LLSD>							form_elements;  		Optional<LLDate>						time_stamp;  		Optional<LLNotificationContext*>		context; @@ -451,6 +447,7 @@ public:  	LLSD asLLSD();  	void respond(const LLSD& sd); +	void respondWithDefault();  	void* getResponder() { return mResponderObj; } @@ -468,6 +465,13 @@ public:  		return mRespondedTo;  	} +	bool isActive() const +	{ +		return !isRespondedTo() +			&& !isCancelled() +			&& !isExpired(); +	} +  	const LLSD& getResponse() { return mResponse; }  	bool isIgnored() const @@ -475,15 +479,11 @@ public:  		return mIgnored;  	} -	const std::string& getName() const -	{ -		return mTemplatep->mName; -	} +	const std::string& getName() const; -	bool isPersistent() const -	{ -		return mTemplatep->mPersist; -	} +	const std::string& getIcon() const; + +	bool isPersistent() const;  	const LLUUID& id() const  	{ @@ -505,28 +505,12 @@ public:  		return mTimestamp;  	} -	std::string getType() const -	{ -		return (mTemplatep ? mTemplatep->mType : ""); -	} - +	std::string getType() const;  	std::string getMessage() const;  	std::string getLabel() const; -  	std::string getURL() const; -//	{ -//		return (mTemplatep ? mTemplatep->mURL : ""); -//	} - -	S32 getURLOption() const -	{ -		return (mTemplatep ? mTemplatep->mURLOption : -1); -	} -     -	S32 getURLOpenExternally() const -	{ -		return(mTemplatep? mTemplatep->mURLOpenExternally : -1); -	} +	S32 getURLOption() const; +    S32 getURLOpenExternally() const;  	const LLNotificationFormPtr getForm(); @@ -596,7 +580,7 @@ public:  	std::string summarize() const; -	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);} +	bool hasUniquenessConstraints() const;  	virtual ~LLNotification() {}  }; @@ -878,7 +862,6 @@ public:  	// load notification descriptions from file;   	// OK to call more than once because it will reload  	bool loadTemplates();   -	LLPointer<class LLXMLNode> checkForXMLTemplate(LLPointer<class LLXMLNode> item);  	// Add a simple notification (from XUI)  	void addFromCallback(const LLSD& name); @@ -900,6 +883,7 @@ public:  	void add(const LLNotificationPtr pNotif);  	void cancel(LLNotificationPtr pNotif); +	void cancelByName(const std::string& name);  	void update(const LLNotificationPtr pNotif);  	LLNotificationPtr find(LLUUID uuid); @@ -923,8 +907,6 @@ public:  	// test for existence  	bool templateExists(const std::string& name); -	// useful if you're reloading the file -	void clearTemplates();   // erase all templates  	void forceResponse(const LLNotification::Params& params, S32 option); @@ -962,9 +944,6 @@ private:  	std::string mFileName; -	typedef std::map<std::string, LLPointer<class LLXMLNode> > XMLTemplateMap; -	XMLTemplateMap mXmlTemplates; -  	LLNotificationMap mUniqueNotifications;  	typedef std::map<std::string, std::string> GlobalStringMap; diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index ee6ec0f88f..19dec53b80 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -12,6 +12,7 @@  #include "linden_common.h"  #include "llnotificationslistener.h"  #include "llnotifications.h" +#include "llnotificationtemplate.h"  #include "llsd.h"  #include "llui.h" @@ -165,7 +166,11 @@ void LLNotificationsListener::ignore(const LLSD& params) const      if (params["name"].isDefined())      {          // ["name"] was passed: ignore just that notification -        LLUI::sSettingGroups["ignores"]->setBOOL(params["name"], ignore); +		LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]); +		if (templatep) +		{ +			templatep->mForm->setIgnored(ignore); +		}      }      else      { diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h new file mode 100644 index 0000000000..6bc0d2aaff --- /dev/null +++ b/indra/llui/llnotificationtemplate.h @@ -0,0 +1,282 @@ +/** +* @file llnotificationtemplate.h +* @brief Description of notification contents +* @author Q (with assistance from Richard and Coco) +* +* $LicenseInfo:firstyear=2008&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_LLNOTIFICATION_TEMPLATE_H +#define LL_LLNOTIFICATION_TEMPLATE_H + +//#include <string> +//#include <list> +//#include <vector> +//#include <map> +//#include <set> +//#include <iomanip> +//#include <sstream> +// +//#include <boost/utility.hpp> +//#include <boost/shared_ptr.hpp> +//#include <boost/enable_shared_from_this.hpp> +//#include <boost/type_traits.hpp> +// +//// we want to minimize external dependencies, but this one is important +//#include "llsd.h" +// +//// and we need this to manage the notification callbacks +//#include "llevents.h" +//#include "llfunctorregistry.h" +//#include "llpointer.h" +#include "llinitparam.h" +//#include "llnotificationslistener.h" +//#include "llnotificationptr.h" +//#include "llcachename.h" +#include "llnotifications.h" + + +typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr; + +// This is the class of object read from the XML file (notifications.xml,  +// from the appropriate local language directory). +struct LLNotificationTemplate +{ +	struct GlobalString : public LLInitParam::Block<GlobalString> +	{ +		Mandatory<std::string>	name, +								value; + +		GlobalString() +		:	name("name"), +			value("value") +		{} +	}; + +	struct UniquenessContext : public LLInitParam::Block<UniquenessContext> +	{ +		Mandatory<std::string>	key; + +		UniquenessContext() +		:	key("key") +		{} +		 +	}; + +	struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint> +	{ +	private: +		// this idiom allows  +		// <notification unique="true"> +		// as well as +		// <notification> <unique> <context key=""/> </unique>... +		Optional<bool>			dummy_val; +	public: +		Multiple<UniquenessContext>	contexts; + +		UniquenessConstraint() +		:	contexts("context"), +			dummy_val("") +		{} +	}; + +	// Templates are used to define common form types, such as OK/Cancel dialogs, etc. + +	struct Template : public LLInitParam::Block<Template> +	{ +		Mandatory<std::string>					name; +		Mandatory<LLNotificationForm::Params>	form; + +		Template() +		:	name("name"), +			form("form") +		{} +	}; + +	// Reference a template to use its form elements +	struct TemplateRef : public LLInitParam::Block<TemplateRef> +	{ +		Mandatory<std::string>	name; +		Optional<std::string>	yes_text, +								no_text, +								cancel_text, +								ignore_text; + +		TemplateRef() +		:	name("name"), +			yes_text("yestext"), +			no_text("notext"), +			cancel_text("canceltext"), +			ignore_text("ignoretext") +		{} +	}; + +	struct URL : public LLInitParam::Block<URL> +	{ +		Mandatory<S32>			option; +		Mandatory<std::string>	value; +		Optional<std::string>	target; +		Ignored					name; + +		URL() +		:	option("option", -1), +			value("value"), +			target("target", "_blank"), +			name("name") +		{} +	}; + +	struct FormRef : public LLInitParam::Choice<FormRef> +	{ +		Alternative<LLNotificationForm::Params>		form; +		Alternative<TemplateRef>					form_template; + +		FormRef() +		:	form("form"), +			form_template("usetemplate") +		{} +	}; + +	struct Params : public LLInitParam::Block<Params> +	{ +		Mandatory<std::string>			name; +		Optional<bool>					persist; +		Optional<std::string>			functor, +										icon, +										label, +										sound, +										type, +										value; +		Optional<U32>					duration; +		Optional<S32>					expire_option; +		Optional<URL>					url; +		Optional<UniquenessConstraint>	unique; +		Optional<FormRef>				form_ref; +		Optional<ENotificationPriority,  +			NotificationPriorityValues> priority; + + +		Params() +		:	name("name"), +			persist("persist", false), +			functor("functor"), +			icon("icon"), +			label("label"), +			priority("priority"), +			sound("sound"), +			type("type"), +			value("value"), +			duration("duration"), +			expire_option("expireOption", -1), +			url("url"), +			unique("unique"), +			form_ref("") +		{} + +	}; + +	struct Notifications : public LLInitParam::Block<Notifications> +	{ +		Multiple<GlobalString>	strings; +		Multiple<Template>		templates; +		Multiple<Params>		notifications; + +		Notifications() +		:	strings("global"), +			notifications("notification"), +			templates("template") +		{} +	}; + +	LLNotificationTemplate(const Params& p); +    // the name of the notification -- the key used to identify it +    // Ideally, the key should follow variable naming rules  +    // (no spaces or punctuation). +    std::string mName; +    // The type of the notification +    // used to control which queue it's stored in +    std::string mType; +    // The text used to display the notification. Replaceable parameters +    // are enclosed in square brackets like this []. +    std::string mMessage; +	// The label for the notification; used for  +	// certain classes of notification (those with a window and a window title).  +	// Also used when a notification pops up underneath the current one. +	// Replaceable parameters can be used in the label. +	std::string mLabel; +	// The name of the icon image. This should include an extension. +	std::string mIcon; +    // This is the Highlander bit -- "There Can Be Only One" +    // An outstanding notification with this bit set +    // is updated by an incoming notification with the same name, +    // rather than creating a new entry in the queue. +    // (used for things like progress indications, or repeating warnings +    // like "the grid is going down in N minutes") +    bool mUnique; +    // if we want to be unique only if a certain part of the payload is constant +    // specify the field names for the payload. The notification will only be +    // combined if all of the fields named in the context are identical in the +    // new and the old notification; otherwise, the notification will be +    // duplicated. This is to support suppressing duplicate offers from the same +    // sender but still differentiating different offers. Example: Invitation to +    // conference chat. +    std::vector<std::string> mUniqueContext; +    // If this notification expires automatically, this value will be  +    // nonzero, and indicates the number of seconds for which the notification +    // will be valid (a teleport offer, for example, might be valid for  +    // 300 seconds).  +    U32 mExpireSeconds; +    // if the offer expires, one of the options is chosen automatically +    // based on its "value" parameter. This controls which one.  +    // If expireSeconds is specified, expireOption should also be specified. +    U32 mExpireOption; +    // if the notification contains a url, it's stored here (and replaced  +    // into the message where [_URL] is found) +    std::string mURL; +    // if there's a URL in the message, this controls which option visits +    // that URL. Obsolete this and eliminate the buttons for affected +    // messages when we allow clickable URLs in the UI +    U32 mURLOption; +	 +	std::string mURLTarget; +	//This is a flag that tells if the url needs to open externally dispite  +	//what the user setting is. +	 +	// does this notification persist across sessions? if so, it will be +	// serialized to disk on first receipt and read on startup +	bool mPersist; +	// This is the name of the default functor, if present, to be +	// used for the notification's callback. It is optional, and used only if  +	// the notification is constructed without an identified functor. +	std::string mDefaultFunctor; +	// The form data associated with a given notification (buttons, text boxes, etc) +    LLNotificationFormPtr mForm; +	// default priority for notifications of this type +	ENotificationPriority mPriority; +	// UUID of the audio file to be played when this notification arrives +	// this is loaded as a name, but looked up to get the UUID upon template load. +	// If null, it wasn't specified. +	LLUUID mSoundEffect; +}; + +#endif //LL_LLNOTIFICATION_TEMPLATE_H + diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index b2e08c48c5..c8e56630f1 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -35,6 +35,7 @@  #include "llfontgl.h"  #include "llrect.h"  #include "llerror.h" +#include "lldir.h"  #include "lltimer.h"  #include "llaccordionctrltab.h" @@ -52,6 +53,8 @@  #include "lltabcontainer.h"  static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML); +LLPanel::factory_stack_t	LLPanel::sFactoryStack; +  // Compiler optimization, generate extern template  template class LLPanel* LLView::getChild<class LLPanel>( @@ -380,8 +383,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_  	LLPanel* panelp = NULL; -	{ -		LLFastTimer timer(FTM_PANEL_CONSTRUCTION); +	{	LLFastTimer _(FTM_PANEL_CONSTRUCTION);  		if(!class_attr.empty())  		{ @@ -394,7 +396,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_  		if (!panelp)  		{ -			panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name); +			panelp = createFactoryPanel(name);  			llassert(panelp);  			if (!panelp) @@ -407,20 +409,20 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_  	// factory panels may have registered their own factory maps  	if (!panelp->getFactoryMap().empty())  	{ -		LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap()); +		sFactoryStack.push_back(&panelp->getFactoryMap());  	}  	// for local registry callbacks; define in constructor, referenced in XUI or postBuild  	panelp->mCommitCallbackRegistrar.pushScope();   	panelp->mEnableCallbackRegistrar.pushScope(); -	panelp->initPanelXML(node, parent, output_node); +	panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>());  	panelp->mCommitCallbackRegistrar.popScope();  	panelp->mEnableCallbackRegistrar.popScope();  	if (!panelp->getFactoryMap().empty())  	{ -		LLUICtrlFactory::instance().popFactoryFunctions(); +		sFactoryStack.pop_back();  	}  	return panelp; @@ -444,8 +446,8 @@ void LLPanel::initFromParams(const LLPanel::Params& p)  		setVisibleCallback(initCommitCallback(p.visible_callback));  	} -	for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings().begin(); -		it != p.strings().end(); +	for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin(); +		it != p.strings.end();  		++it)  	{  		mUIStrings[it->name] = it->value; @@ -487,11 +489,9 @@ static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");  static LLFastTimer::DeclareTimer FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference");  static LLFastTimer::DeclareTimer FTM_PANEL_POSTBUILD("Panel PostBuild"); -BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) +BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params)  { -	const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel>());  	Params params(default_params); -  	{  		LLFastTimer timer(FTM_PANEL_SETUP); @@ -505,6 +505,8 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  			setXMLFilename(xml_filename);  		} +		LLXUIParser parser; +  		if (!xml_filename.empty())  		{  			LLUICtrlFactory::instance().pushFileName(xml_filename); @@ -514,12 +516,11 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  			{  				//if we are exporting, we want to export the current xml  				//not the referenced xml -				LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); +				parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());  				Params output_params(params);  				setupParamsForExport(output_params, parent);  				output_node->setName(node->getName()->mString); -				LLXUIParser::instance().writeXUI( -					output_node, output_params, &default_params); +				parser.writeXUI(output_node, output_params, &default_params);  				return TRUE;  			} @@ -530,7 +531,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  				return FALSE;  			} -			LLXUIParser::instance().readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); +			parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());  			// add children using dimensions from referenced xml for consistent layout  			setShape(params.rect); @@ -540,15 +541,14 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu  		}  		// ask LLUICtrlFactory for filename, since xml_filename might be empty -		LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); +		parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());  		if (output_node)  		{  			Params output_params(params);  			setupParamsForExport(output_params, parent);  			output_node->setName(node->getName()->mString); -			LLXUIParser::instance().writeXUI( -				output_node, output_params, &default_params); +			parser.writeXUI(output_node, output_params, &default_params);  		}  		params.from_xui = true; @@ -959,3 +959,89 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::  	return mVisibleSignal->connect(cb);  } + +static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels"); + +//----------------------------------------------------------------------------- +// buildPanel() +//----------------------------------------------------------------------------- +BOOL LLPanel::buildFromFile(const std::string& filename, LLXMLNodePtr output_node, const LLPanel::Params& default_params) +{ +	LLFastTimer timer(FTM_BUILD_PANELS); +	BOOL didPost = FALSE; +	LLXMLNodePtr root; + +	//if exporting, only load the language being exported,  +	//instead of layering localized version on top of english +	if (output_node) +	{	 +		if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root)) +		{ +			llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename  << llendl; +			return didPost; +		} +	} +	else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) +	{ +		llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; +		return didPost; +	} + +	// root must be called panel +	if( !root->hasName("panel" ) ) +	{ +		llwarns << "Root node should be named panel in : " << filename << llendl; +		return didPost; +	} + +	lldebugs << "Building panel " << filename << llendl; + +	LLUICtrlFactory::instance().pushFileName(filename); +	{ +		if (!getFactoryMap().empty()) +		{ +			sFactoryStack.push_back(&getFactoryMap()); +		} +		 +		 // for local registry callbacks; define in constructor, referenced in XUI or postBuild +		getCommitCallbackRegistrar().pushScope(); +		getEnableCallbackRegistrar().pushScope(); +		 +		didPost = initPanelXML(root, NULL, output_node, default_params); + +		getCommitCallbackRegistrar().popScope(); +		getEnableCallbackRegistrar().popScope(); +		 +		setXMLFilename(filename); + +		if (!getFactoryMap().empty()) +		{ +			sFactoryStack.pop_back(); +		} +	} +	LLUICtrlFactory::instance().popFileName(); +	return didPost; +} + +//----------------------------------------------------------------------------- +// createFactoryPanel() +//----------------------------------------------------------------------------- +LLPanel* LLPanel::createFactoryPanel(const std::string& name) +{ +	std::deque<const LLCallbackMap::map_t*>::iterator itor; +	for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor) +	{ +		const LLCallbackMap::map_t* factory_map = *itor; + +		// Look up this panel's name in the map. +		LLCallbackMap::map_const_iter_t iter = factory_map->find( name ); +		if (iter != factory_map->end()) +		{ +			// Use the factory to create the panel, instead of using a default LLPanel. +			LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData ); +			return ret; +		} +	} +	LLPanel::Params panel_p; +	return LLUICtrlFactory::create<LLPanel>(panel_p); +} diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index a7224648c1..c1a1a06f39 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -104,7 +104,10 @@ protected:  	LLPanel(const LLPanel::Params& params = getDefaultParams());  public: -// 	LLPanel(const std::string& name, const LLRect& rect = LLRect(), BOOL bordered = TRUE); +	BOOL buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL, const LLPanel::Params&default_params = getDefaultParams()); + +	static LLPanel* createFactoryPanel(const std::string& name); +  	/*virtual*/ ~LLPanel();  	// LLView interface @@ -157,7 +160,7 @@ public:  	EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }  	void initFromParams(const Params& p); -	BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); +	BOOL initPanelXML(	LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params);  	bool hasString(const std::string& name);  	std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const; @@ -256,6 +259,8 @@ protected:  	commit_signal_t* mVisibleSignal;		// Called when visibility changes, passes new visibility as LLSD()  	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;  private:  	BOOL			mBgVisible;				// any background at all? @@ -285,4 +290,57 @@ extern template class LLPanel* LLView::getChild<class LLPanel>(  	const std::string& name, BOOL recurse) const;  #endif +typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc; + +// local static instance for registering a particular panel class + +class LLRegisterPanelClass +:	public LLSingleton< LLRegisterPanelClass > +{ +public: +	// reigister with either the provided builder, or the generic templated builder +	void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func) +	{ +		mPanelClassesNames[tag] = func; +	} + +	LLPanel* createPanelClass(const std::string& tag) +	{ +		param_name_map_t::iterator iT =  mPanelClassesNames.find(tag); +		if(iT == mPanelClassesNames.end()) +			return 0; +		return iT->second(); +	} +	template<typename T> +	static T* defaultPanelClassBuilder() +	{ +		T* pT = new T(); +		return pT; +	} + +private: +	typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t; +	 +	param_name_map_t mPanelClassesNames; +}; + + +// local static instance for registering a particular panel class +template<typename T> +class LLRegisterPanelClassWrapper +:	public LLRegisterPanelClass +{ +public: +	// reigister with either the provided builder, or the generic templated builder +	LLRegisterPanelClassWrapper(const std::string& tag); +}; + + +template<typename T> +LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)  +{ +	LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>); +} + +  #endif diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index e27792dc1d..8e17311bee 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -106,8 +106,8 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)  void LLRadioGroup::initFromParams(const Params& p)  { -	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin(); -		it != p.items().end(); +	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); +		it != p.items.end();  		++it)  	{  		LLRadioGroup::ItemParams item_params(*it); diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp index 7e3d4b92d3..718c10d2f8 100644 --- a/indra/llui/llrngwriter.cpp +++ b/indra/llui/llrngwriter.cpp @@ -36,10 +36,15 @@  #include "lluicolor.h"  #include "lluictrlfactory.h" +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; +  //  // LLRNGWriter - writes Relax NG schema files based on a param block  //  LLRNGWriter::LLRNGWriter() +: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)  {  	// register various callbacks for inspecting the contents of a param block  	registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4)); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 84e438cfb7..7df7c13dc0 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -259,15 +259,15 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)  	} -	for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns().begin(); -		row_it != p.contents.columns().end(); +	for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns.begin(); +		row_it != p.contents.columns.end();  		++row_it)  	{  		addColumn(*row_it);  	} -	for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows().begin(); -		row_it != p.contents.rows().end(); +	for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows.begin(); +		row_it != p.contents.rows.end();  		++row_it)  	{  		addRow(*row_it); @@ -537,23 +537,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r  			setNeedsSort();  			break; -		case ADD_SORTED: -			{ -				// sort by column 0, in ascending order -				std::vector<sort_column_t> single_sort_column; -				single_sort_column.push_back(std::make_pair(0, TRUE)); - -				mItemList.push_back(item); -				std::stable_sort( -					mItemList.begin(),  -					mItemList.end(),  -					SortScrollListItem(single_sort_column,mSortCallback)); -				 -				// ADD_SORTED just sorts by first column... -				// this might not match user sort criteria, so flag list as being in unsorted state -				setNeedsSort(); -				break; -			}	 +		case ADD_DEFAULT:  		case ADD_BOTTOM:  			mItemList.push_back(item);  			setNeedsSort(); @@ -2578,7 +2562,8 @@ BOOL	LLScrollListCtrl::canDeselect() const  void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)  {  	LLScrollListColumn::Params p; -	LLParamSDParser::instance().readSD(column, p); +	LLParamSDParser parser; +	parser.readSD(column, p);  	addColumn(p, pos);  } @@ -2764,31 +2749,35 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)  	return NULL;  } - +LLFastTimer::DeclareTimer FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item");  LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)  { +	LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);  	LLScrollListItem::Params item_params; -	LLParamSDParser::instance().readSD(element, item_params); +	LLParamSDParser parser; +	parser.readSD(element, item_params);  	item_params.userdata = userdata;  	return addRow(item_params, pos);  }  LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)  { +	LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);  	LLScrollListItem *new_item = new LLScrollListItem(item_p);  	return addRow(new_item, item_p, pos);  }  LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)  { +	LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);  	if (!item_p.validateBlock() || !new_item) return NULL;  	new_item->setNumColumns(mColumns.size());  	// Add any columns we don't already have  	S32 col_index = 0; -	for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns().begin(); -		itor != item_p.columns().end(); +	for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns.begin(); +		itor != item_p.columns.end();  		++itor)  	{  		LLScrollListCell::Params cell_p = *itor; @@ -2839,7 +2828,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS  		col_index++;  	} -	if (item_p.columns().empty()) +	if (item_p.columns.empty())  	{  		if (mColumns.empty())  		{ diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index 4bb45a3065..35e5ac1b87 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -35,49 +35,42 @@  // Project includes  #include "llsdparam.h" +#include "llsdutil.h" + +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;  //  // LLParamSDParser  //  LLParamSDParser::LLParamSDParser() +: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)  {  	using boost::bind; -	registerParserFuncs<S32>(bind(&LLParamSDParser::readTypedValue<S32>, this, _1, &LLSD::asInteger), -							bind(&LLParamSDParser::writeTypedValue<S32>, this, _1, _2)); -	registerParserFuncs<U32>(bind(&LLParamSDParser::readTypedValue<U32>, this, _1, &LLSD::asInteger), -							bind(&LLParamSDParser::writeU32Param, this, _1, _2)); -	registerParserFuncs<F32>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asReal), -							bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2)); -	registerParserFuncs<F64>(bind(&LLParamSDParser::readTypedValue<F64>, this, _1, &LLSD::asReal), -							bind(&LLParamSDParser::writeTypedValue<F64>, this, _1, _2)); -	registerParserFuncs<bool>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asBoolean), -							bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2)); -	registerParserFuncs<std::string>(bind(&LLParamSDParser::readTypedValue<std::string>, this, _1, &LLSD::asString), -							bind(&LLParamSDParser::writeTypedValue<std::string>, this, _1, _2)); -	registerParserFuncs<LLUUID>(bind(&LLParamSDParser::readTypedValue<LLUUID>, this, _1, &LLSD::asUUID), -							bind(&LLParamSDParser::writeTypedValue<LLUUID>, this, _1, _2)); -	registerParserFuncs<LLDate>(bind(&LLParamSDParser::readTypedValue<LLDate>, this, _1, &LLSD::asDate), -							bind(&LLParamSDParser::writeTypedValue<LLDate>, this, _1, _2)); -	registerParserFuncs<LLURI>(bind(&LLParamSDParser::readTypedValue<LLURI>, this, _1, &LLSD::asURI), -							bind(&LLParamSDParser::writeTypedValue<LLURI>, this, _1, _2)); -	registerParserFuncs<LLSD>(bind(&LLParamSDParser::readSDParam, this, _1), -							bind(&LLParamSDParser::writeTypedValue<LLSD>, this, _1, _2)); -} - -bool LLParamSDParser::readSDParam(void* value_ptr) -{ -	if (!mCurReadSD) return false; -	*((LLSD*)value_ptr) = *mCurReadSD; -	return true; +	if (sReadFuncs.empty()) +	{ +		registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); +		registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); +		registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); +		registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); +		registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); +		registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); +		registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); +		registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); +		registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>); +		registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>); +	}  }  // special case handling of U32 due to ambiguous LLSD::assign overload -bool LLParamSDParser::writeU32Param(const void* val_ptr, const parser_t::name_stack_t& name_stack) +bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)  { -	if (!mWriteSD) return false; +	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); +	if (!sdparser.mWriteRootSD) return false; -	LLSD* sd_to_write = getSDWriteNode(name_stack); +	LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);  	if (!sd_to_write) return false;  	sd_to_write->assign((S32)*((const U32*)val_ptr)); @@ -95,7 +88,8 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool  void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)  { -	mWriteSD = &sd; +	mNameStack.clear(); +	mWriteRootSD = &sd;  	block.serializeBlock(*this);  } @@ -145,6 +139,155 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block  LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)  {  	//TODO: implement nested LLSD writing -	return mWriteSD; +	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::readS32(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +    *((S32*)val_ptr) = self.mCurReadSD->asInteger(); +    return true; +} + +bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +    *((U32*)val_ptr) = self.mCurReadSD->asInteger(); +    return true; +} + +bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +    *((F32*)val_ptr) = self.mCurReadSD->asReal(); +    return true; +} + +bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +    *((F64*)val_ptr) = self.mCurReadSD->asReal(); +    return true; +} + +bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +    *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); +    return true; +} + +bool LLParamSDParser::readString(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +	*((std::string*)val_ptr) = self.mCurReadSD->asString(); +    return true;  } +bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +	*((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); +    return true; +} + +bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +	*((LLDate*)val_ptr) = self.mCurReadSD->asDate(); +    return true; +} + +bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +	*((LLURI*)val_ptr) = self.mCurReadSD->asURI(); +    return true; +} + +bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + +	*((LLSD*)val_ptr) = *self.mCurReadSD; +    return true; +} diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h index 12f28f876f..c3ad889425 100644 --- a/indra/llui/llsdparam.h +++ b/indra/llui/llsdparam.h @@ -37,17 +37,14 @@  #include "llinitparam.h"  class LLParamSDParser  -:	public LLInitParam::Parser,  -	public LLSingleton<LLParamSDParser> +:	public LLInitParam::Parser  {  LOG_CLASS(LLParamSDParser);  typedef LLInitParam::Parser parser_t; -protected: -	LLParamSDParser(); -	friend class LLSingleton<LLParamSDParser>;  public: +	LLParamSDParser();  	void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);  	void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); @@ -57,20 +54,12 @@ private:  	void readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block);  	template<typename T> -	bool readTypedValue(void* val_ptr, boost::function<T(const LLSD&)> parser_func) -    { -	    if (!mCurReadSD) return false; - -	    *((T*)val_ptr) = parser_func(*mCurReadSD); -	    return true; -    } - -	template<typename T> -	bool writeTypedValue(const void* val_ptr, const parser_t::name_stack_t& name_stack) +	static bool writeTypedValue(Parser& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)  	{ -		if (!mWriteSD) return false; +		LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); +		if (!sdparser.mWriteRootSD) return false; -		LLSD* sd_to_write = getSDWriteNode(name_stack); +		LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);  		if (!sd_to_write) return false;  		sd_to_write->assign(*((const T*)val_ptr)); @@ -79,12 +68,23 @@ private:  	LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack); -	bool readSDParam(void* value_ptr); -	bool writeU32Param(const void* value_ptr, const parser_t::name_stack_t& name_stack); +	static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); + +	static bool readS32(Parser& parser, void* val_ptr); +	static bool readU32(Parser& parser, void* val_ptr); +	static bool readF32(Parser& parser, void* val_ptr); +	static bool readF64(Parser& parser, void* val_ptr); +	static bool readBool(Parser& parser, void* val_ptr); +	static bool readString(Parser& parser, void* val_ptr); +	static bool readUUID(Parser& parser, void* val_ptr); +	static bool readDate(Parser& parser, void* val_ptr); +	static bool readURI(Parser& parser, void* val_ptr); +	static bool readSD(Parser& parser, void* val_ptr);  	Parser::name_stack_t	mNameStack;  	const LLSD*				mCurReadSD; -	LLSD*					mWriteSD; +	LLSD*					mWriteRootSD; +	LLSD*					mCurWriteSD;  };  template<typename T> @@ -94,7 +94,8 @@ class LLSDParamAdapter : public T  		LLSDParamAdapter() {}  		LLSDParamAdapter(const LLSD& sd)  		{ -			LLParamSDParser::instance().readSD(sd, *this); +			LLParamSDParser parser; +			parser.readSD(sd, *this);  		}  		LLSDParamAdapter(const T& val) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index e5dfecad54..1fa449a182 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -235,6 +235,7 @@ class LLTextBase  public:  	friend class LLTextSegment;  	friend class LLNormalTextSegment; +	friend class LLUICtrlFactory;  	struct LineSpacingParams : public LLInitParam::Choice<LineSpacingParams>  	{ diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index b02d3122fe..6390039794 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -78,9 +78,9 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask)  	LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance(); -	if (x != last_x && y != last_y) +	if (x != last_x && y != last_y && !tooltip_mgr.getMouseNearRect().pointInRect(x, y))  	{ -		// allow new tooltips because mouse moved +		// allow new tooltips because mouse moved outside of mouse near rect  		tooltip_mgr.unblockToolTips();  	} @@ -276,8 +276,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	if (p.styled_message.isProvided())  	{ -		for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message().begin(); -			text_it != p.styled_message().end(); +		for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message.begin(); +			text_it != p.styled_message.end();  			++text_it)  		{  			mTextBox->appendText(text_it->text(), false, text_it->style); @@ -580,6 +580,7 @@ void LLToolTipMgr::updateToolTipVisibility()  		if (mToolTip->getVisibleTime() > tooltip_timeout)  		{  			hideToolTips(); +			unblockToolTips();  		}  	}  } diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index d33d8e3178..ff9af21e54 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1796,7 +1796,8 @@ void LLUI::setupPaths()  	LLXMLNodePtr root;  	BOOL success  = LLXMLNode::parseFile(filename, root, NULL);  	Paths paths; -	LLXUIParser::instance().readXUI(root, paths, filename); +	LLXUIParser parser; +	parser.readXUI(root, paths, filename);  	sXUIPaths.clear(); @@ -1805,14 +1806,14 @@ void LLUI::setupPaths()  		LLStringUtil::format_map_t path_args;  		path_args["[LANGUAGE]"] = LLUI::getLanguage(); -		for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories().begin(),  -				end_it = paths.directories().end(); +		for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories.begin(),  +				end_it = paths.directories.end();  			it != end_it;  			++it)  		{  			std::string path_val_ui; -			for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs().begin(), -					subdir_end_it = it->subdirs().end(); +			for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs.begin(), +					subdir_end_it = it->subdirs.end();  				subdir_it != subdir_end_it;)  			{  				path_val_ui += subdir_it->value(); diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 1b64ef3abe..c14efe90be 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -62,8 +62,8 @@ void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table  	typedef std::map<std::string, std::string> string_string_map_t;  	string_string_map_t unresolved_refs; -	for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries().begin(); -		it != p.color_entries().end(); +	for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin(); +		it != p.color_entries.end();  		++it)  	{  		ColorEntryParams color_entry = *it; @@ -243,7 +243,8 @@ void LLUIColorTable::saveUserSettings() const  	}  	LLXMLNodePtr output_node = new LLXMLNode("colors", false); -	LLXUIParser::instance().writeXUI(output_node, params); +	LLXUIParser parser; +	parser.writeXUI(output_node, params);  	if(!output_node->isNull())  	{ @@ -309,7 +310,8 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_  	}  	Params params; -	LLXUIParser::instance().readXUI(root, params, filename); +	LLXUIParser parser; +	parser.readXUI(root, params, filename);  	if(params.validateBlock())  	{ diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index a46d961709..2a2fa21ec0 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -48,7 +48,7 @@  #include "llquaternion.h"  // this library includes -#include "llfloater.h" +#include "llpanel.h"  LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");  LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams"); @@ -99,10 +99,12 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa  	std::string filename = std::string("widgets") + gDirUtilp->getDirDelimiter() + widget_tag + ".xml";  	LLXMLNodePtr root_node; -	if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) +	std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), filename); +	if (!full_filename.empty())  	{ -		LLUICtrlFactory::instance().pushFileName(filename); -		LLXUIParser::instance().readXUI(root_node, block, filename); +		LLUICtrlFactory::instance().pushFileName(full_filename); +		LLSimpleXUIParser parser; +		parser.readXUI(full_filename, block);  		LLUICtrlFactory::instance().popFileName();  	}  } @@ -177,70 +179,6 @@ bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXML  	}  } -static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters"); - -//----------------------------------------------------------------------------- -// buildFloater() -//----------------------------------------------------------------------------- -bool LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, LLXMLNodePtr output_node) -{ -	LLFastTimer timer(FTM_BUILD_FLOATERS); -	LLXMLNodePtr root; - -	//if exporting, only load the language being exported,  -	//instead of layering localized version on top of english -	if (output_node) -	{ -		if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root)) -		{ -			llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; -			return false; -		} -	} -	else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) -	{ -		llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; -		return false; -	} -	 -	// root must be called floater -	if( !(root->hasName("floater") || root->hasName("multi_floater")) ) -	{ -		llwarns << "Root node should be named floater in: " << filename << llendl; -		return false; -	} -	 -	bool res = true; -	 -	lldebugs << "Building floater " << filename << llendl; -	pushFileName(filename); -	{ -		if (!floaterp->getFactoryMap().empty()) -		{ -			mFactoryStack.push_front(&floaterp->getFactoryMap()); -		} - -		 // for local registry callbacks; define in constructor, referenced in XUI or postBuild -		floaterp->getCommitCallbackRegistrar().pushScope(); -		floaterp->getEnableCallbackRegistrar().pushScope(); -		 -		res = floaterp->initFloaterXML(root, floaterp->getParent(), filename, output_node); - -		floaterp->setXMLFilename(filename); -		 -		floaterp->getCommitCallbackRegistrar().popScope(); -		floaterp->getEnableCallbackRegistrar().popScope(); -		 -		if (!floaterp->getFactoryMap().empty()) -		{ -			mFactoryStack.pop_front(); -		} -	} -	popFileName(); -	 -	return res; -} -  //-----------------------------------------------------------------------------  // saveToXML()  //----------------------------------------------------------------------------- @@ -249,69 +187,6 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)  	return 0;  } -static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels"); - -//----------------------------------------------------------------------------- -// buildPanel() -//----------------------------------------------------------------------------- -BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node) -{ -	LLFastTimer timer(FTM_BUILD_PANELS); -	BOOL didPost = FALSE; -	LLXMLNodePtr root; - -	//if exporting, only load the language being exported,  -	//instead of layering localized version on top of english -	if (output_node) -	{	 -		if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root)) -		{ -			llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename  << llendl; -			return didPost; -		} -	} -	else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) -	{ -		llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; -		return didPost; -	} - -	// root must be called panel -	if( !root->hasName("panel" ) ) -	{ -		llwarns << "Root node should be named panel in : " << filename << llendl; -		return didPost; -	} - -	lldebugs << "Building panel " << filename << llendl; - -	pushFileName(filename); -	{ -		if (!panelp->getFactoryMap().empty()) -		{ -			mFactoryStack.push_front(&panelp->getFactoryMap()); -		} -		 -		 // for local registry callbacks; define in constructor, referenced in XUI or postBuild -		panelp->getCommitCallbackRegistrar().pushScope(); -		panelp->getEnableCallbackRegistrar().pushScope(); -		 -		didPost = panelp->initPanelXML(root, NULL, output_node); - -		panelp->getCommitCallbackRegistrar().popScope(); -		panelp->getEnableCallbackRegistrar().popScope(); -		 -		panelp->setXMLFilename(filename); - -		if (!panelp->getFactoryMap().empty()) -		{ -			mFactoryStack.pop_front(); -		} -	} -	popFileName(); -	return didPost; -} -  //-----------------------------------------------------------------------------  //----------------------------------------------------------------------------- @@ -343,29 +218,6 @@ LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const  	return view;  } -//----------------------------------------------------------------------------- -// createFactoryPanel() -//----------------------------------------------------------------------------- -LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name) -{ -	std::deque<const LLCallbackMap::map_t*>::iterator itor; -	for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor) -	{ -		const LLCallbackMap::map_t* factory_map = *itor; - -		// Look up this panel's name in the map. -		LLCallbackMap::map_const_iter_t iter = factory_map->find( name ); -		if (iter != factory_map->end()) -		{ -			// Use the factory to create the panel, instead of using a default LLPanel. -			LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData ); -			return ret; -		} -	} -	LLPanel::Params panel_p; -	return create<LLPanel>(panel_p); -} -  std::string LLUICtrlFactory::getCurFileName()   {   	return mFileNames.empty() ? "" : gDirUtilp->getWorkingDir() + gDirUtilp->getDirDelimiter() + mFileNames.back();  @@ -382,36 +234,6 @@ void LLUICtrlFactory::popFileName()  	mFileNames.pop_back();   } - -//----------------------------------------------------------------------------- - -//static -BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color) -{ -	std::string colorstring; -	BOOL res = node->getAttributeString(name.c_str(), colorstring); -	if (res) -	{ -		if (LLUIColorTable::instance().colorExists(colorstring)) -		{ -			color.setVec(LLUIColorTable::instance().getColor(colorstring)); -		} -		else -		{ -			res = FALSE; -		} -	} -	if (!res) -	{ -		res = LLColor4::parseColor(colorstring, &color); -	}	 -	if (!res) -	{ -		res = node->getAttributeColor(name.c_str(), color); -	} -	return res; -} -  //static  void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)  { @@ -427,28 +249,22 @@ std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename)  	return gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename);  } -void LLUICtrlFactory::pushFactoryFunctions(const LLCallbackMap::map_t* map) -{ -	mFactoryStack.push_back(map); -} - -void LLUICtrlFactory::popFactoryFunctions() -{ -	if (!mFactoryStack.empty()) -	{ -		mFactoryStack.pop_back(); -	} -} -  //static   void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest)  {  	dest->setName(src->getName()->mString);  } +template<typename T> +const LLInitParam::BaseBlock& get_empty_param_block() +{ +	static typename T::Params params; +	return params; +} +  // adds a widget and its param block to various registries  //static  -void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag) +void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag)  {  	// associate parameter block type with template .xml file  	std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type); @@ -468,17 +284,9 @@ void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const st  		}  	}  	LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, tag); -	// associate widget type with factory function -	LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type, creator_func);  	//FIXME: comment this in when working on schema generation  	//LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type); -	//LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &getEmptyParamBlock<T>); -} - -//static -dummy_widget_creator_func_t* LLUICtrlFactory::getDefaultWidgetFunc(const std::type_info* widget_type) -{ -	return LLDefaultWidgetRegistry::instance().getValue(widget_type); +	//LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>);  }  //static  diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index dc43b311a7..6b5d055b78 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -33,24 +33,13 @@  #ifndef LLUICTRLFACTORY_H  #define LLUICTRLFACTORY_H -#include "llcallbackmap.h" +#include "llfasttimer.h"  #include "llinitparam.h"  #include "llregistry.h" -#include "v4color.h" -#include "llfasttimer.h" -  #include "llxuiparser.h" -#include <boost/function.hpp> -#include <iosfwd> -#include <stack> -#include <set> - -class LLPanel; -class LLFloater;  class LLView; -  // sort functor for typeid maps  struct LLCompareTypeID  { @@ -91,12 +80,6 @@ class LLWidgetNameRegistry  :	public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID>  {}; -// lookup factory functions for default widget instances by widget type -typedef LLView* (*dummy_widget_creator_func_t)(const std::string&); -class LLDefaultWidgetRegistry -:	public LLRegistrySingleton<const std::type_info*, dummy_widget_creator_func_t, LLDefaultWidgetRegistry, LLCompareTypeID> -{}; -  // lookup function for generating empty param block by widget type  // this is used for schema generation  //typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)(); @@ -163,58 +146,21 @@ public:  		return ParamDefaults<typename T::Params, 0>::instance().get();  	} -	bool buildFloater(LLFloater* floaterp, const std::string &filename, LLXMLNodePtr output_node); -	BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL); -  	// Does what you want for LLFloaters and LLPanels  	// Returns 0 on success  	S32 saveToXML(LLView* viewp, const std::string& filename); +	// filename tracking for debugging info  	std::string getCurFileName();  	void pushFileName(const std::string& name);  	void popFileName(); -	static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color); - -	LLPanel* createFactoryPanel(const std::string& name); - -	void pushFactoryFunctions(const LLCallbackMap::map_t* map); -	void popFactoryFunctions(); - -	template<typename T> -	static T* createWidget(const typename T::Params& params, LLView* parent = NULL) -	{ -		T* widget = NULL; - -		if (!params.validateBlock()) -		{ -			llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; -			//return NULL; -		} - -		{ -			LLFastTimer timer(FTM_WIDGET_CONSTRUCTION); -			widget = new T(params);	 -		} -		{ -			LLFastTimer timer(FTM_INIT_FROM_PARAMS); -			widget->initFromParams(params); -		} - -		if (parent) -		{ -			S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX; -			setCtrlParent(widget, parent, tab_group); -		} -		return widget; -	} -  	template<typename T>  	static T* create(typename T::Params& params, LLView* parent = NULL)  	{  		params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get()); -		T* widget = createWidget<T>(params, parent); +		T* widget = createWidgetImpl<T>(params, parent);  		if (widget)  		{  			widget->postBuild(); @@ -272,21 +218,54 @@ fail:  	template<class T>  	static T* getDefaultWidget(const std::string& name)  	{ -		dummy_widget_creator_func_t* dummy_func = getDefaultWidgetFunc(&typeid(T)); -		return dummy_func ? dynamic_cast<T*>((*dummy_func)(name)) : NULL; +		typename T::Params widget_params; +		widget_params.name = name; +		return create<T>(widget_params);  	} -	template <class T>  -	static LLView* createDefaultWidget(const std::string& name)  -	{ -		typename T::Params params; -		params.name(name); -		 -		return create<T>(params); -	} +	static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL); + +	static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); +	static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root); + +private: +	//NOTE: both friend declarations are necessary to keep both gcc and msvc happy +	template <typename T> friend class LLChildRegistry; +	template <typename T> template <typename U> friend class LLChildRegistry<T>::Register;  	static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest); +	// helper function for adding widget type info to various registries +	static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag); + +	static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); + +	template<typename T> +	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL) +	{ +		T* widget = NULL; + +		if (!params.validateBlock()) +		{ +			llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; +			//return NULL; +		} + +		{ LLFastTimer _(FTM_WIDGET_CONSTRUCTION); +			widget = new T(params);	 +		} +		{ LLFastTimer _(FTM_INIT_FROM_PARAMS); +			widget->initFromParams(params); +		} + +		if (parent) +		{ +			S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX; +			setCtrlParent(widget, parent, tab_group); +		} +		return widget; +	} +  	template<typename T>  	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)  	{ @@ -294,7 +273,8 @@ fail:  		typename T::Params params(getDefaultParams<T>()); -		LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); +		LLXUIParser parser; +		parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());  		if (output_node)  		{ @@ -304,14 +284,13 @@ fail:  			// Export only the differences between this any default params  			typename T::Params default_params(getDefaultParams<T>());  			copyName(node, output_node); -			LLXUIParser::instance().writeXUI( -				output_node, output_params, &default_params); +			parser.writeXUI(output_node, output_params, &default_params);  		}  		// Apply layout transformations, usually munging rect  		params.from_xui = true;  		T::applyXUILayout(params, parent); -		T* widget = createWidget<T>(params, parent); +		T* widget = createWidgetImpl<T>(params, parent);  		typedef typename T::child_registry_t registry_t; @@ -326,20 +305,6 @@ fail:  		return widget;  	} -	static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL); - -	static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); -	 -	static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root); - -	static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); - -	// helper function for adding widget type info to various registries -	static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag); - -private: -	// return default widget instance factory func for a given type -	static dummy_widget_creator_func_t* getDefaultWidgetFunc(const std::type_info* widget_type);  	static const std::string* getWidgetTag(const std::type_info* widget_type); @@ -349,20 +314,10 @@ private:  	// Avoid directly using LLUI and LLDir in the template code  	static std::string findSkinnedFilename(const std::string& filename); -	typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t; -	factory_stack_t					mFactoryStack; - -	LLPanel*		mDummyPanel; +	class LLPanel*		mDummyPanel;  	std::vector<std::string>	mFileNames;  }; -template<typename T> -const LLInitParam::BaseBlock& getEmptyParamBlock() -{ -	static typename T::Params params; -	return params; -} -  // this is here to make gcc happy with reference to LLUICtrlFactory  template<typename DERIVED>  template<typename T>  @@ -370,7 +325,7 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator  :	LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)  {  	// add this widget to various registries -	LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), &LLUICtrlFactory::createDefaultWidget<T>, tag); +	LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);  	// since registry_t depends on T, do this in line here  	// TODO: uncomment this for schema generation @@ -378,58 +333,4 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator  	//LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());  } - -typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc; - -// local static instance for registering a particular panel class - -class LLRegisterPanelClass -:	public LLSingleton< LLRegisterPanelClass > -{ -public: -	// reigister with either the provided builder, or the generic templated builder -	void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func) -	{ -		mPanelClassesNames[tag] = func; -	} - -	LLPanel* createPanelClass(const std::string& tag) -	{ -		param_name_map_t::iterator iT =  mPanelClassesNames.find(tag); -		if(iT == mPanelClassesNames.end()) -			return 0; -		return iT->second(); -	} -	template<typename T> -	static T* defaultPanelClassBuilder() -	{ -		T* pT = new T(); -		return pT; -	} - -private: -	typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t; -	 -	param_name_map_t mPanelClassesNames; -}; - - -// local static instance for registering a particular panel class -template<typename T> -class LLRegisterPanelClassWrapper -:	public LLRegisterPanelClass -{ -public: -	// reigister with either the provided builder, or the generic templated builder -	LLRegisterPanelClassWrapper(const std::string& tag); -}; - - -template<typename T> -LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)  -{ -	LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>); -} - -  #endif //LLUICTRLFACTORY_H diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index ac9e71665f..e343df0063 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -40,7 +40,7 @@ LLFastTimer::DeclareTimer FTM_UI_STRING("UI String");  LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args)  :	mOrig(instring), -	mArgs(args) +	mArgs(new LLStringUtil::format_map_t(args))  {  	dirty();  } @@ -54,7 +54,7 @@ void LLUIString::assign(const std::string& s)  void LLUIString::setArgList(const LLStringUtil::format_map_t& args)  { -	mArgs = args; +	getArgs() = args;  	dirty();  } @@ -74,7 +74,7 @@ void LLUIString::setArgs(const LLSD& sd)  void LLUIString::setArg(const std::string& key, const std::string& replacement)  { -	mArgs[key] = replacement; +	getArgs()[key] = replacement;  	dirty();  } @@ -135,14 +135,14 @@ void LLUIString::updateResult() const  	mResult = mOrig;  	// get the defailt args + local args -	if (mArgs.empty()) +	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()); +		combined_args.insert(mArgs->begin(), mArgs->end());  		LLStringUtil::format(mResult, combined_args);  	}  } @@ -153,3 +153,12 @@ void LLUIString::updateWResult() const  	mWResult = utf8str_to_wstring(getUpdatedResult());  } + +LLStringUtil::format_map_t& LLUIString::getArgs() +{ +	if (!mArgs) +	{ +		mArgs = new LLStringUtil::format_map_t; +	} +	return *mArgs; +} diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 32cfc0d9cd..3f91856e26 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -64,9 +64,9 @@ class LLUIString  public:  	// These methods all perform appropriate argument substitution  	// and modify mOrig where appropriate -        LLUIString() : mNeedsResult(false), mNeedsWResult(false) {} +        LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}  	LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args); -	LLUIString(const std::string& instring) { assign(instring); } +	LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }  	void assign(const std::string& instring);  	LLUIString& operator=(const std::string& s) { assign(s); return *this; } @@ -86,7 +86,7 @@ public:  	S32 length() const { return getUpdatedWResult().size(); }  	void clear(); -	void clearArgs() { mArgs.clear(); } +	void clearArgs() { if (mArgs) mArgs->clear(); }  	// These utility functions are included for text editing.  	// They do not affect mOrig and do not perform argument substitution @@ -105,11 +105,12 @@ private:  	// do actual work of updating strings (non-inlined)  	void updateResult() const;  	void updateWResult() const; +	LLStringUtil::format_map_t& getArgs();  	std::string mOrig;  	mutable std::string mResult;  	mutable LLWString mWResult; // for displaying -	LLStringUtil::format_map_t mArgs; +	LLStringUtil::format_map_t* mArgs;  	// controls lazy evaluation  	mutable bool	mNeedsResult; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 323a600b5b..6061cc78eb 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -108,11 +108,7 @@ LLView::Params::Params()  	left_pad("left_pad"),  	left_delta("left_delta", S32_MAX),  	from_xui("from_xui", false), -	user_resize("user_resize"), -	auto_resize("auto_resize"),  	needs_translate("translate"), -	min_width("min_width"), -	max_width("max_width"),  	xmlns("xmlns"),  	xmlns_xsi("xmlns:xsi"),  	xsi_schemaLocation("xsi:schemaLocation"), @@ -224,7 +220,7 @@ void LLView::setUseBoundingRect( BOOL use_bounding_rect )  	}  } -BOOL LLView::getUseBoundingRect() +BOOL LLView::getUseBoundingRect() const  {  	return mUseBoundingRect;  } @@ -1382,12 +1378,12 @@ void LLView::drawDebugRect()  		// drawing solids requires texturing be disabled  		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -		if (mUseBoundingRect) +		if (getUseBoundingRect())  		{  			LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);  		} -		LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect; +		LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect;  		// draw red rectangle for the border  		LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f); @@ -1585,7 +1581,7 @@ void LLView::updateBoundingRect()  	LLRect cur_rect = mBoundingRect; -	if (mUseBoundingRect) +	if (getUseBoundingRect())  	{  		mBoundingRect = calcBoundingRect();  	} @@ -1595,7 +1591,7 @@ void LLView::updateBoundingRect()  	}  	// give parent view a chance to resize, in case we just moved, for example -	if (getParent() && getParent()->mUseBoundingRect) +	if (getParent() && getParent()->getUseBoundingRect())  	{  		getParent()->updateBoundingRect();  	} @@ -1619,7 +1615,7 @@ LLRect LLView::calcScreenBoundingRect() const  {  	LLRect screen_rect;  	// get bounding rect, if used -	LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect; +	LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect;  	// convert to local coordinates, as defined by mRect  	bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); @@ -1704,7 +1700,9 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const  		child = getDefaultWidget<LLView>(name);  		if (!child)  		{ -			 child = LLUICtrlFactory::createDefaultWidget<LLView>(name); +			LLView::Params view_params; +			view_params.name = name; +			child = LLUICtrlFactory::create<LLView>(view_params);  		}  	}  	return child; @@ -1748,14 +1746,14 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const  BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const   {  -	return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT) +	return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)  		? mBoundingRect.pointInRect( x, y )   		: mRect.pointInRect( x, y );   }  BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const   {  -	return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT) +	return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)  		? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom )   		: mRect.localPointInRect( x, y );   } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 483d22b28f..ddbcc4a5db 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -134,26 +134,22 @@ public:  		Optional<std::string>		layout;  		Optional<LLRect>			rect; +  		// Historical bottom-left layout used bottom_delta and left_delta  		// for relative positioning.  New layout "topleft" prefers specifying  		// based on top edge. -		Optional<S32>				bottom_delta,	// deprecated -									top_pad,	// from last bottom to my top -									top_delta,	// from last top to my top -									left_pad,	// from last right to my left -									left_delta;	// from last left to my left -								 -		// these are nested attributes for LLLayoutPanel +		Optional<S32>				bottom_delta,	// from last bottom to my bottom +									top_pad,		// from last bottom to my top +									top_delta,		// from last top to my top +									left_pad,		// from last right to my left +									left_delta;		// from last left to my left +  		//FIXME: get parent context involved in parsing traversal -		Ignored						user_resize, -									auto_resize, -									needs_translate, -									min_width, -									max_width, -									xmlns, -									xmlns_xsi, -									xsi_schemaLocation, -									xsi_type; +		Ignored						needs_translate,	// cue for translation tools +									xmlns,				// xml namespace +									xmlns_xsi,			// xml namespace +									xsi_schemaLocation,	// xml schema +									xsi_type;			// xml schema type  		Params();  	}; @@ -244,7 +240,7 @@ public:  	void        setSoundFlags(U8 flags)			{ mSoundFlags = flags; }  	void		setName(std::string name)			{ mName = name; }  	void		setUseBoundingRect( BOOL use_bounding_rect ); -	BOOL		getUseBoundingRect(); +	BOOL		getUseBoundingRect() const;  	ECursorType	getHoverCursor() { return mHoverCursor; } @@ -283,6 +279,11 @@ public:  	BOOL focusNextRoot();  	BOOL focusPrevRoot(); +	// Normally we want the app menus to get priority on accelerated keys +	// However, sometimes we want to give specific views a first chance +	// iat handling them. (eg. the script editor) +	virtual bool	hasAccelerators() const { return false; }; +  	// delete all children. Override this function if you need to  	// perform any extra clean up such as cached pointers to selected  	// children, etc. | 
