diff options
Diffstat (limited to 'indra/llui')
30 files changed, 567 insertions, 182 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index e98201ea63..864f3f699e 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -159,6 +159,7 @@ set(llui_HEADER_FILES      llnotificationslistener.h      llnotificationsutil.h      llnotificationtemplate.h +	llnotificationvisibilityrule.h      llpanel.h      llprogressbar.h      llradiogroup.h diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index bbd8db2645..4fe444c1a4 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -88,27 +88,19 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)  		tbparams.font(p.font);  	}  	mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams); +	mLabel->reshapeToFitText();  	addChild(mLabel); -	S32 text_width = mLabel->getTextBoundingRect().getWidth(); -	S32 text_height = llround(mFont->getLineHeight()); -	LLRect label_rect; -	label_rect.setOriginAndSize( -		llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, -		llcheckboxctrl_vpad + 1, // padding to get better alignment -		text_width + llcheckboxctrl_hpad, -		text_height ); -	mLabel->setShape(label_rect); - +	LLRect label_rect = mLabel->getRect();  	// Button  	// Note: button cover the label by extending all the way to the right. -	LLRect btn_rect; +	LLRect btn_rect = p.check_button.rect();  	btn_rect.setOriginAndSize( -		llcheckboxctrl_hpad, -		llcheckboxctrl_vpad, -		llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width + llcheckboxctrl_hpad, -		llmax( text_height, llcheckboxctrl_btn_size() ) + llcheckboxctrl_vpad); +		btn_rect.mLeft, +		btn_rect.mBottom, +		llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft), +		llmax( label_rect.getHeight(), btn_rect.mTop));  	std::string active_true_id, active_false_id;  	std::string inactive_true_id, inactive_false_id; @@ -174,31 +166,20 @@ void LLCheckBoxCtrl::clear()  void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)  { -	//stretch or shrink bounding rectangle of label when rebuilding UI at new scale -	static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); -	static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); -	static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); -	static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); -	S32 text_width = mLabel->getTextBoundingRect().getWidth(); -	S32 text_height = llround(mFont->getLineHeight()); -	LLRect label_rect; -	label_rect.setOriginAndSize( -		llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, -		llcheckboxctrl_vpad, -		text_width, -		text_height ); -	mLabel->setShape(label_rect); - -	LLRect btn_rect; +	mLabel->reshapeToFitText(); + +	LLRect label_rect = mLabel->getRect(); + +	// Button +	// Note: button cover the label by extending all the way to the right. +	LLRect btn_rect = mButton->getRect();  	btn_rect.setOriginAndSize( -		llcheckboxctrl_hpad, -		llcheckboxctrl_vpad, -		llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width, -		llmax( text_height, llcheckboxctrl_btn_size() ) ); -	mButton->setShape( btn_rect ); -	 -	LLUICtrl::reshape(width, height, called_from_parent); +		btn_rect.mLeft, +		btn_rect.mBottom, +		llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft), +		llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight())); +	mButton->setShape(btn_rect);  }  //virtual diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h index a43f095d67..8c000eee48 100644 --- a/indra/llui/llhandle.h +++ b/indra/llui/llhandle.h @@ -61,13 +61,6 @@ public:  		return *this;   	} -	template<typename Subclass> -	LLHandle<T>& operator =(const LLHandle<Subclass>& other)   -	{  -		mTombStone = other.mTombStone; -		return *this;  -	} -  	bool isDead() const   	{   		return mTombStone->getTarget() == NULL;  @@ -99,7 +92,6 @@ public:  	{  		return lhs.mTombStone > rhs.mTombStone;  	} -protected:  protected:  	LLPointer<LLTombStone<T> > mTombStone; diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 940c7e7e18..ac30fce392 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -97,6 +97,8 @@ LLLayoutStack::Params::Params()  :	orientation("orientation"),  	animate("animate", true),  	clip("clip", true), +	open_time_constant("open_time_constant", 0.02f), +	close_time_constant("close_time_constant", 0.03f),  	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))  {  	name="stack"; @@ -110,7 +112,9 @@ LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)  	mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),  	mAnimate(p.animate),  	mAnimatedThisFrame(false), -	mClip(p.clip) +	mClip(p.clip), +	mOpenTimeConstant(p.open_time_constant), +	mCloseTimeConstant(p.close_time_constant)  {}  LLLayoutStack::~LLLayoutStack() @@ -303,9 +307,6 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  	S32 total_width = 0;  	S32 total_height = 0; -	const F32 ANIM_OPEN_TIME = 0.02f; -	const F32 ANIM_CLOSE_TIME = 0.03f; -  	e_panel_list_t::iterator panel_it;  	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)  	{ @@ -316,7 +317,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  			{  				if (!mAnimatedThisFrame)  				{ -					(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME)); +					(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));  					if ((*panel_it)->mVisibleAmt > 0.99f)  					{  						(*panel_it)->mVisibleAmt = 1.f; @@ -334,7 +335,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  			{  				if (!mAnimatedThisFrame)  				{ -					(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); +					(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));  					if ((*panel_it)->mVisibleAmt < 0.001f)  					{  						(*panel_it)->mVisibleAmt = 0.f; @@ -349,11 +350,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)  		if ((*panel_it)->mCollapsed)  		{ -			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); +			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));  		}  		else  		{ -			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME)); +			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));  		}  		if (mOrientation == HORIZONTAL) diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index e19ef403ef..2fc6164d7a 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -46,6 +46,8 @@ public:  		Optional<S32>			border_size;  		Optional<bool>			animate,  								clip; +		Optional<F32>			open_time_constant, +								close_time_constant;  		Params();  	}; @@ -137,6 +139,8 @@ private:  	bool mAnimatedThisFrame;  	bool mAnimate;  	bool mClip; +	F32 mOpenTimeConstant; +	F32 mCloseTimeConstant;  }; // end class LLLayoutStack  class LLLayoutPanel : public LLPanel diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index ba73b74052..aed391c780 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1529,6 +1529,8 @@ void LLLineEditor::drawBackground()  	{  		image = mBgImage;  	} + +	if (!image) return;  	F32 alpha = getCurrentTransparency(); diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index a1aa6b71c6..ce2dfdeeb8 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -336,7 +336,7 @@ protected:  	std::vector<S32> mPreeditPositions;  	LLPreeditor::standouts_t mPreeditStandouts; -	LLHandle<LLView> mContextMenuHandle; +	LLHandle<LLContextMenu> mContextMenuHandle;  private:  	// Instances that by default point to the statics but can be overidden in XML. diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index a6cf86d9b8..6c0d47ef63 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1462,7 +1462,7 @@ BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)  {  	BOOL branch_visible = getBranch()->getVisible();  	BOOL handled = getBranch()->handleAcceleratorKey(key, mask); -	if (handled && !branch_visible && getVisible()) +	if (handled && !branch_visible && isInVisibleChain())  	{  		// flash this menu entry because we triggered an invisible menu item  		LLMenuHolderGL::setActivatedItem(this); @@ -2611,6 +2611,7 @@ LLMenuItemGL* LLMenuGL::getHighlightedItem()  LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled)  { +	if (mItems.empty()) return NULL;  	// highlighting first item on a torn off menu is the  	// same as giving focus to it  	if (!cur_item && getTornOff()) @@ -2711,6 +2712,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa  LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled)  { +	if (mItems.empty()) return NULL; +  	// highlighting first item on a torn off menu is the  	// same as giving focus to it  	if (!cur_item && getTornOff()) @@ -3045,6 +3048,11 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)  	const S32 CURSOR_HEIGHT = 22;		// Approximate "normal" cursor size  	const S32 CURSOR_WIDTH = 12; +	if(menu->getChildList()->empty()) +	{ +		return; +	} +  	// Save click point for detecting cursor moves before mouse-up.  	// Must be in local coords to compare with mouseUp events.  	// If the mouse doesn't move, the menu will stay open ala the Mac. @@ -3125,7 +3133,10 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)  		mAltKeyTrigger = FALSE;  	} -	if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key)) +	if(!result  +		&& (key == KEY_F10 && mask == MASK_CONTROL)  +		&& !gKeyboard->getKeyRepeated(key) +		&& isInVisibleChain())  	{  		if (getHighlightedItem())  		{ @@ -3508,8 +3519,10 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)  			else  			{  				//highlight first enabled one -				pMenu->highlightNextItem(NULL); -				handled = true; +				if(pMenu->highlightNextItem(NULL)) +				{ +					handled = true; +				}  			}  		}  	} @@ -3742,9 +3755,7 @@ public:  	LLContextMenuBranch(const Params&);  	virtual ~LLContextMenuBranch() -	{ -		delete mBranch; -	} +	{}  	// called to rebuild the draw label  	virtual void	buildDrawLabel( void ); @@ -3752,21 +3763,21 @@ public:  	// onCommit() - do the primary funcationality of the menu item.  	virtual void	onCommit( void ); -	LLContextMenu*	getBranch() { return mBranch; } +	LLContextMenu*	getBranch() { return mBranch.get(); }  	void			setHighlight( BOOL highlight );  protected:  	void	showSubMenu(); -	LLContextMenu* mBranch; +	LLHandle<LLContextMenu> mBranch;  };  LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)   :	LLMenuItemGL(p), -	mBranch( p.branch ) +	mBranch( p.branch()->getHandle() )  { -	mBranch->hide(); -	mBranch->setParentMenuItem(this); +	mBranch.get()->hide(); +	mBranch.get()->setParentMenuItem(this);  }  // called to rebuild the draw label @@ -3775,12 +3786,12 @@ void LLContextMenuBranch::buildDrawLabel( void )  	{  		// default enablement is this -- if any of the subitems are  		// enabled, this item is enabled. JC -		U32 sub_count = mBranch->getItemCount(); +		U32 sub_count = mBranch.get()->getItemCount();  		U32 i;  		BOOL any_enabled = FALSE;  		for (i = 0; i < sub_count; i++)  		{ -			LLMenuItemGL* item = mBranch->getItem(i); +			LLMenuItemGL* item = mBranch.get()->getItem(i);  			item->buildDrawLabel();  			if (item->getEnabled() && !item->getDrawTextDisabled() )  			{ @@ -3802,13 +3813,13 @@ void LLContextMenuBranch::buildDrawLabel( void )  void	LLContextMenuBranch::showSubMenu()  { -	LLMenuItemGL* menu_item = mBranch->getParentMenuItem(); +	LLMenuItemGL* menu_item = mBranch.get()->getParentMenuItem();  	if (menu_item != NULL && menu_item->getVisible())  	{  		S32 center_x;  		S32 center_y;  		localPointToScreen(getRect().getWidth(), getRect().getHeight() , ¢er_x, ¢er_y); -		mBranch->show(center_x, center_y); +		mBranch.get()->show(center_x, center_y);  	}  } @@ -3828,7 +3839,7 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )  	}  	else  	{ -		mBranch->hide(); +		mBranch.get()->hide();  	}  } @@ -3859,6 +3870,11 @@ void LLContextMenu::setVisible(BOOL visible)  // Takes cursor position in screen space?  void LLContextMenu::show(S32 x, S32 y)  { +	if (getChildList()->empty()) +	{ +		// nothing to show, so abort +		return; +	}  	// Save click point for detecting cursor moves before mouse-up.  	// Must be in local coords to compare with mouseUp events.  	// If the mouse doesn't move, the menu will stay open ala the Mac. diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 35544402f4..7bde8e83ec 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -678,9 +678,12 @@ public:  			BOOL	appendContextSubMenu(LLContextMenu *menu); +			LLHandle<LLContextMenu> getHandle() { mHandle.bind(this); return mHandle; } +  protected: -	BOOL			mHoveredAnyItem; -	LLMenuItemGL*	mHoverItem; +	BOOL						mHoveredAnyItem; +	LLMenuItemGL*				mHoverItem; +	LLRootHandle<LLContextMenu>	mHandle;  }; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index a3df6a3ced..c347e15792 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -28,6 +28,7 @@  #include "llnotifications.h"  #include "llnotificationtemplate.h" +#include "llnotificationvisibilityrule.h"  #include "llavatarnamecache.h"  #include "llinstantmessage.h" @@ -137,12 +138,6 @@ private:  bool filterIgnoredNotifications(LLNotificationPtr notification)  { -	// filter everything if we are to ignore ALL -	if(LLNotifications::instance().getIgnoreAllNotifications()) -	{ -		return false; -	} -  	LLNotificationFormPtr form = notification->getForm();  	// Check to see if the user wants to ignore this alert  	return !notification->getForm()->getIgnored(); @@ -177,6 +172,28 @@ bool handleIgnoredNotification(const LLSD& payload)  	return false;  } +bool defaultResponse(const LLSD& payload) +{ +	if (payload["sigtype"].asString() == "add") +	{ +		LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); +		if (pNotif)  +		{ +			// supply default response +			pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); +		} +	} +	return false; +} + +bool visibilityRuleMached(const LLSD& payload) +{ +	// This is needed because LLNotifications::isVisibleByRules may have cancelled the notification. +	// Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order. +	return true; +} + +  namespace LLNotificationFilters  {  	// a sample filter @@ -406,10 +423,47 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par  	{  		mUniqueContext.push_back(it->key);  	} +	 +	lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl; +	 +	for(LLInitParam::ParamIterator<LLNotificationTemplate::Tag>::const_iterator it = p.tags.begin(), +			end_it = p.tags.end(); +		it != end_it; +		++it) +	{ +		lldebugs << "    tag \"" << std::string(it->value) << "\"" << llendl; +		mTags.push_back(it->value); +	}  	mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));  } +LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p) +{ +	if (p.show.isChosen()) +	{ +		mType = p.show.type; +		mTag = p.show.tag; +		mName = p.show.name; +		mVisible = true; +	} +	else if (p.hide.isChosen()) +	{ +		mType = p.hide.type; +		mTag = p.hide.tag; +		mName = p.hide.name; +		mVisible = false; +	} +	else if (p.respond.isChosen()) +	{ +		mType = p.respond.type; +		mTag = p.respond.tag; +		mName = p.respond.name; +		mVisible = false; +		mResponse = p.respond.response; +	} +} +  LLNotification::LLNotification(const LLNotification::Params& p) :   	mTimestamp(p.time_stamp),   	mSubstitutions(p.substitutions), @@ -679,6 +733,25 @@ bool LLNotification::hasUniquenessConstraints() const  	return (mTemplatep ? mTemplatep->mUnique : false);  } +bool LLNotification::matchesTag(const std::string& tag) +{ +	bool result = false; +	 +	if(mTemplatep) +	{ +		std::list<std::string>::iterator it; +		for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++) +		{ +			if((*it) == tag) +			{ +				result = true; +				break; +			} +		} +	} +	 +	return result; +}  void LLNotification::setIgnored(bool ignore)  { @@ -1064,12 +1137,12 @@ std::string LLNotificationChannel::summarize()  // LLNotifications implementation  // ---  LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything, -							       LLNotificationComparators::orderByUUID()), -				     mIgnoreAllNotifications(false) +															   LLNotificationComparators::orderByUUID()), +									mIgnoreAllNotifications(false)  {  	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); -	 -	mListener.reset(new LLNotificationsListener(*this)); + +    mListener.reset(new LLNotificationsListener(*this));  } @@ -1184,6 +1257,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN  void LLNotifications::initSingleton()  {  	loadTemplates(); +	loadVisibilityRules();  	createDefaultChannels();  } @@ -1191,15 +1265,19 @@ void LLNotifications::createDefaultChannels()  {  	// now construct the various channels AFTER loading the notifications,  	// because the history channel is going to rewrite the stored notifications file -	LLNotificationChannel::buildChannel("Expiration", "", +	LLNotificationChannel::buildChannel("Enabled", "", +		!boost::bind(&LLNotifications::getIgnoreAllNotifications, this)); +	LLNotificationChannel::buildChannel("Expiration", "Enabled",  		boost::bind(&LLNotifications::expirationFilter, this, _1)); -	LLNotificationChannel::buildChannel("Unexpired", "", +	LLNotificationChannel::buildChannel("Unexpired", "Enabled",  		!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind  	LLNotificationChannel::buildChannel("Unique", "Unexpired",  		boost::bind(&LLNotifications::uniqueFilter, this, _1));  	LLNotificationChannel::buildChannel("Ignore", "Unique",  		filterIgnoredNotifications); -	LLNotificationChannel::buildChannel("Visible", "Ignore", +	LLNotificationChannel::buildChannel("VisibilityRules", "Ignore", +		boost::bind(&LLNotifications::isVisibleByRules, this, _1)); +	LLNotificationChannel::buildChannel("Visible", "VisibilityRules",  		&LLNotificationFilters::includeEverything);  	// create special persistent notification channel @@ -1207,6 +1285,8 @@ void LLNotifications::createDefaultChannels()  	new LLPersistentNotificationChannel();  	// connect action methods to these channels +	LLNotifications::instance().getChannel("Enabled")-> +		connectFailedFilter(&defaultResponse);  	LLNotifications::instance().getChannel("Expiration")->          connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));  	// uniqueHandler slot should be added as first slot of the signal due to @@ -1218,6 +1298,8 @@ void LLNotifications::createDefaultChannels()  //        connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));  	LLNotifications::instance().getChannel("Ignore")->  		connectFailedFilter(&handleIgnoredNotification); +	LLNotifications::instance().getChannel("VisibilityRules")-> +		connectFailedFilter(&visibilityRuleMached);  }  bool LLNotifications::addTemplate(const std::string &name,  @@ -1347,6 +1429,12 @@ bool LLNotifications::loadTemplates()  	LLXUIParser parser;  	parser.readXUI(root, params, full_filename); +	if(!params.validateBlock()) +	{ +		llerrs << "Problem reading UI Notifications file: " << full_filename << llendl; +		return false; +	} +  	mTemplates.clear();  	for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings.begin(), end_it = params.strings.end(); @@ -1396,6 +1484,34 @@ bool LLNotifications::loadTemplates()  	return true;  } +bool LLNotifications::loadVisibilityRules() +{ +	const std::string xml_filename = "notification_visibility.xml"; +	std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename); + +	LLNotificationVisibilityRule::Rules params; +	LLSimpleXUIParser parser; +	parser.readXUI(full_filename, params); + +	if(!params.validateBlock()) +	{ +		llerrs << "Problem reading UI Notification Visibility Rules file: " << full_filename << llendl; +		return false; +	} + +	mVisibilityRules.clear(); + +	for(LLInitParam::ParamIterator<LLNotificationVisibilityRule::Rule>::iterator it = params.rules.begin(),  +			end_it = params.rules.end(); +		it != end_it; +		++it) +	{ +		mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(*it))); +	} + +	return true; +} +  // Add a simple notification (from XUI)  void LLNotifications::addFromCallback(const LLSD& name)  { @@ -1546,6 +1662,94 @@ bool LLNotifications::getIgnoreAllNotifications()  	return mIgnoreAllNotifications;   } +bool LLNotifications::isVisibleByRules(LLNotificationPtr n) +{ +	if(n->isRespondedTo()) +	{ +		// This avoids infinite recursion in the case where the filter calls respond() +		return true; +	} +	 +	VisibilityRuleList::iterator it; +	 +	for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) +	{ +		// An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. + +		lldebugs  +			<< "notification \"" << n->getName() << "\" "  +			<< "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " +			<< "name = \"" << (*it)->mName << "\" " +			<< "tag = \"" << (*it)->mTag << "\" " +			<< "type = \"" << (*it)->mType << "\" " +			<< llendl; + +		if(!(*it)->mType.empty()) +		{ +			if((*it)->mType != n->getType()) +			{ +				// Type doesn't match, so skip this rule. +				continue; +			} +		} +		 +		if(!(*it)->mTag.empty()) +		{ +			// check this notification's tag(s) against it->mTag and continue if no match is found. +			if(!n->matchesTag((*it)->mTag)) +			{ +				// This rule's non-empty tag didn't match one of the notification's tags.  Skip this rule. +				continue; +			} +		} + +		if(!(*it)->mName.empty()) +		{ +			// check this notification's name against the notification's name and continue if no match is found. +			if((*it)->mName != n->getName()) +			{ +				// This rule's non-empty name didn't match the notification.  Skip this rule. +				continue; +			} +		} +		 +		// If we got here, the rule matches.  Don't evaluate subsequent rules. +		if(!(*it)->mVisible) +		{ +			// This notification is being hidden. +			 +			if((*it)->mResponse.empty()) +			{ +				// Response property is empty.  Cancel this notification. +				lldebugs << "cancelling notification " << n->getName() << llendl; + +				n->cancel(); +			} +			else +			{ +				// Response property is not empty.  Return the specified response. +				LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON); +				// TODO: verify that the response template has an item with the correct name +				response[(*it)->mResponse] = true; + +				lldebugs << "responding to notification " << n->getName() << " with response = " << response << llendl; +				 +				n->respond(response); +			} + +			return false; +		} +		 +		// If we got here, exit the loop and return true. +		break; +	} +	 +	lldebugs << "allowing notification " << n->getName() << llendl; + +	return true; +} +			 +  // ---  // END OF LLNotifications implementation  // ========================================================= diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 524cff70e8..f8f4469958 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -270,6 +270,11 @@ struct LLNotificationTemplate;  // with smart pointers  typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr; + +struct LLNotificationVisibilityRule; + +typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr; +  /**   * @class LLNotification   * @brief The object that expresses the details of a notification @@ -506,7 +511,7 @@ public:  	std::string getLabel() const;  	std::string getURL() const;  	S32 getURLOption() const; -	S32 getURLOpenExternally() const; +    S32 getURLOpenExternally() const;  	const LLNotificationFormPtr getForm(); @@ -578,6 +583,8 @@ public:  	bool hasUniquenessConstraints() const; +	bool matchesTag(const std::string& tag); +  	virtual ~LLNotification() {}  }; @@ -859,6 +866,10 @@ public:  	// OK to call more than once because it will reload  	bool loadTemplates();   +	// load visibility rules from file;  +	// OK to call more than once because it will reload +	bool loadVisibilityRules();   +	  	// Add a simple notification (from XUI)  	void addFromCallback(const LLSD& name); @@ -904,6 +915,8 @@ public:  	// test for existence  	bool templateExists(const std::string& name); +	typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList; +	  	void forceResponse(const LLNotification::Params& params, S32 option);  	void createDefaultChannels(); @@ -919,6 +932,8 @@ public:  	void setIgnoreAllNotifications(bool ignore);  	bool getIgnoreAllNotifications(); +	bool isVisibleByRules(LLNotificationPtr pNotification); +	  private:  	// we're a singleton, so we don't have a public constructor  	LLNotifications(); @@ -938,6 +953,8 @@ private:  	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);  	TemplateMap mTemplates; +	VisibilityRuleList mVisibilityRules; +  	std::string mFileName;  	LLNotificationMap mUniqueNotifications; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 6bc0d2aaff..5a6ab40a2e 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -156,6 +156,15 @@ struct LLNotificationTemplate  		{}  	}; +	struct Tag : public LLInitParam::Block<Tag> +	{ +		Mandatory<std::string>	value; + +		Tag() +		:	value("value") +		{} +	}; +  	struct Params : public LLInitParam::Block<Params>  	{  		Mandatory<std::string>			name; @@ -173,6 +182,7 @@ struct LLNotificationTemplate  		Optional<FormRef>				form_ref;  		Optional<ENotificationPriority,   			NotificationPriorityValues> priority; +		Multiple<Tag>		tags;  		Params() @@ -189,7 +199,8 @@ struct LLNotificationTemplate  			expire_option("expireOption", -1),  			url("url"),  			unique("unique"), -			form_ref("") +			form_ref(""), +			tags("tag")  		{}  	}; @@ -276,6 +287,8 @@ struct LLNotificationTemplate  	// this is loaded as a name, but looked up to get the UUID upon template load.  	// If null, it wasn't specified.  	LLUUID mSoundEffect; +	// List of tags that rules can match against. +	std::list<std::string> mTags;  };  #endif //LL_LLNOTIFICATION_TEMPLATE_H diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h new file mode 100644 index 0000000000..78bdec2a8f --- /dev/null +++ b/indra/llui/llnotificationvisibilityrule.h @@ -0,0 +1,104 @@ +/** +* @file llnotificationvisibility.h +* @brief Rules for  +* @author Monroe +* +* $LicenseInfo:firstyear=2010&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_VISIBILITY_RULE_H +#define LL_LLNOTIFICATION_VISIBILITY_RULE_H + +#include "llinitparam.h" +//#include "llnotifications.h" + + + +// This is the class of object read from the XML file (notification_visibility.xml,  +// from the appropriate local language directory). +struct LLNotificationVisibilityRule +{ +	struct Filter : public LLInitParam::Block<Filter> +	{ +		Optional<std::string>	type, +								tag, +								name; + +		Filter() +		:	type("type"), +			tag("tag"), +			name("name") +		{} +	}; + +	struct Respond : public LLInitParam::Block<Respond, Filter> +	{ +		Mandatory<std::string> response; + +		Respond() +		:	response("response") +		{} +	}; + +	struct Rule : public LLInitParam::Choice<Rule> +	{ +		Alternative<Filter>		show; +		Alternative<Filter>		hide; +		Alternative<Respond>	respond; + +		Rule() +		:	show("show"), +			hide("hide"), +			respond("respond") +		{} +	}; + +	struct Rules : public LLInitParam::Block<Rules> +	{ +		Multiple<Rule>	rules; + +		Rules() +		:	rules("") +		{} +	}; + +	LLNotificationVisibilityRule(const Rule& p); +	 +    // If true, this rule makes matching notifications visible.  Otherwise, it makes them invisible. +    bool mVisible; + +    // Which response to give when making a notification invisible.  An empty string means the notification should be cancelled instead of responded to. +	std::string mResponse; + +    // String to match against the notification's "type".  An empty string matches all notifications. +    std::string mType; +	 +    // String to match against the notification's tag(s).  An empty string matches all notifications. +	std::string mTag; + +    // String to match against the notification's name.  An empty string matches all notifications. +	std::string mName; +	 +}; + +#endif //LL_LLNOTIFICATION_VISIBILITY_RULE_H + diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index ff377ba3a1..b2383106a8 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -436,7 +436,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p)      //and LLView::initFromParams will use them to set visible and enabled    	setVisible(p.visible);  	setEnabled(p.enabled); - +	setFocusRoot(p.focus_root);  	setSoundFlags(p.sound_flags);  	 // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp index aaa328754d..ead22686bc 100644 --- a/indra/llui/llprogressbar.cpp +++ b/indra/llui/llprogressbar.cpp @@ -50,7 +50,7 @@ LLProgressBar::Params::Params()  LLProgressBar::LLProgressBar(const LLProgressBar::Params& p)  -:	LLView(p), +:	LLUICtrl(p),  	mImageBar(p.image_bar),  	mImageFill(p.image_fill),  	mColorBackground(p.color_bg()), @@ -80,7 +80,7 @@ void LLProgressBar::draw()  	mImageFill->draw(progress_rect, bar_color);  } -void LLProgressBar::setPercent(const F32 percent) +void LLProgressBar::setValue(const LLSD& value)  { -	mPercentDone = llclamp(percent, 0.f, 100.f); +	mPercentDone = llclamp((F32)value.asReal(), 0.f, 100.f);  } diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h index 13297f7493..3f308e7496 100644 --- a/indra/llui/llprogressbar.h +++ b/indra/llui/llprogressbar.h @@ -27,14 +27,14 @@  #ifndef LL_LLPROGRESSBAR_H  #define LL_LLPROGRESSBAR_H -#include "llview.h" +#include "lluictrl.h"  #include "llframetimer.h"  class LLProgressBar -	: public LLView +	: public LLUICtrl  {  public: -	struct Params : public LLInitParam::Block<Params, LLView::Params> +	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>  	{  		Optional<LLUIImage*>	image_bar,  								image_fill; @@ -47,7 +47,7 @@ public:  	LLProgressBar(const Params&);  	virtual ~LLProgressBar(); -	void setPercent(const F32 percent); +	void setValue(const LLSD& value);  	/*virtual*/ void draw(); diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index cc348fdc63..6e9586369f 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -69,7 +69,7 @@ protected:  static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");  LLRadioGroup::Params::Params() -:	has_border("draw_border"), +:	allow_deselect("allow_deselect"),  	items("item")   {  	addSynonym(items, "radio_item"); @@ -85,18 +85,8 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)  :	LLUICtrl(p),  	mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),  	mSelectedIndex(-1), -	mHasBorder(p.has_border) -{	 -	if (mHasBorder) -	{ -		LLViewBorder::Params params; -		params.name("radio group border"); -		params.rect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0)); -		params.bevel_style(LLViewBorder::BEVEL_NONE); -		LLViewBorder * vb = LLUICtrlFactory::create<LLViewBorder> (params); -		addChild (vb); -	} -} +	mAllowDeselect(p.allow_deselect) +{}  void LLRadioGroup::initFromParams(const Params& p)  { @@ -184,7 +174,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)  BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)  { -	if (index < 0 || (S32)mRadioButtons.size() <= index ) +	if ((S32)mRadioButtons.size() <= index )  	{  		return FALSE;  	} @@ -202,13 +192,16 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)  	mSelectedIndex = index; -	LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex]; -	radio_item->setTabStop(true); -	radio_item->setValue( TRUE ); - -	if (hasFocus()) +	if (mSelectedIndex >= 0)  	{ -		mRadioButtons[mSelectedIndex]->focusFirstItem(FALSE, FALSE); +		LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex]; +		radio_item->setTabStop(true); +		radio_item->setValue( TRUE ); + +		if (hasFocus()) +		{ +			radio_item->focusFirstItem(FALSE, FALSE); +		}  	}  	if (!from_event) @@ -307,8 +300,15 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)  		LLRadioCtrl* radio = *iter;  		if (radio == clicked_radio)  		{ -			// llinfos << "clicked button " << index << llendl; -			setSelectedIndex(index); +			if (index == mSelectedIndex && mAllowDeselect) +			{ +				// don't select anything +				setSelectedIndex(-1); +			} +			else +			{ +				setSelectedIndex(index); +			}  			// BUG: Calls click callback even if button didn't actually change  			onCommit(); diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h index 0588900600..8bd5698538 100644 --- a/indra/llui/llradiogroup.h +++ b/indra/llui/llradiogroup.h @@ -49,7 +49,7 @@ public:  	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>  	{ -		Optional<bool>						has_border; +		Optional<bool>						allow_deselect;  		Multiple<ItemParams, AtLeast<1> >	items;  		Params();  	}; @@ -73,7 +73,6 @@ public:  	void setIndexEnabled(S32 index, BOOL enabled);  	// return the index value of the selected item  	S32 getSelectedIndex() const { return mSelectedIndex; } -	  	// set the index value programatically  	BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE); @@ -103,12 +102,13 @@ public:  	/*virtual*/ BOOL	operateOnAll(EOperation op);  private: -	const LLFontGL* mFont; -	S32 mSelectedIndex; +	const LLFontGL*		mFont; +	S32					mSelectedIndex; +  	typedef std::vector<class LLRadioCtrl*> button_list_t; -	button_list_t mRadioButtons; +	button_list_t		mRadioButtons; -	BOOL mHasBorder; +	bool				mAllowDeselect;	// user can click on an already selected option to deselect it  };  #endif diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 8854f0a02e..b7848ec37c 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -322,6 +322,7 @@ LLScrollListCtrl::~LLScrollListCtrl()  	delete mSortCallback;  	std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); +	std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());  } @@ -2371,10 +2372,10 @@ void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )  void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending)  { -	std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.find(name); +	column_map_t::iterator itor = mColumns.find(name);  	if (itor != mColumns.end())  	{ -		sortByColumnIndex((*itor).second.mIndex, ascending); +		sortByColumnIndex((*itor).second->mIndex, ascending);  	}  } @@ -2420,11 +2421,11 @@ void LLScrollListCtrl::dirtyColumns()  	// just in case someone indexes into it immediately  	mColumnsIndexed.resize(mColumns.size()); -	std::map<std::string, LLScrollListColumn>::iterator column_itor; +	column_map_t::iterator column_itor;  	for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)  	{ -		LLScrollListColumn *column = &column_itor->second; -		mColumnsIndexed[column_itor->second.mIndex] = column; +		LLScrollListColumn *column = column_itor->second; +		mColumnsIndexed[column_itor->second->mIndex] = column;  	}  } @@ -2582,8 +2583,8 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params  	if (mColumns.find(name) == mColumns.end())  	{  		// Add column -		mColumns[name] = LLScrollListColumn(column_params, this); -		LLScrollListColumn* new_column = &mColumns[name]; +		mColumns[name] = new LLScrollListColumn(column_params, this); +		LLScrollListColumn* new_column = mColumns[name];  		new_column->mIndex = mColumns.size()-1;  		// Add button @@ -2605,14 +2606,14 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params  			S32 top = mItemListRect.mTop;  			S32 left = mItemListRect.mLeft; -			for (std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.begin();  +			for (column_map_t::iterator itor = mColumns.begin();   				itor != mColumns.end();   				++itor)  			{ -				if (itor->second.mIndex < new_column->mIndex && -					itor->second.getWidth() > 0) +				if (itor->second->mIndex < new_column->mIndex && +					itor->second->getWidth() > 0)  				{ -					left += itor->second.getWidth() + mColumnPadding; +					left += itor->second->getWidth() + mColumnPadding;  				}  			} @@ -2668,8 +2669,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)  	if (column->mSortingColumn != column->mName  		&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())  	{ -		LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn]; -		column_index = info_redir.mIndex; +		LLScrollListColumn* info_redir = parent->mColumns[column->mSortingColumn]; +		column_index = info_redir->mIndex;  	}  	// if this column is the primary sort key, reverse the direction @@ -2702,16 +2703,17 @@ BOOL LLScrollListCtrl::hasSortOrder() const  void LLScrollListCtrl::clearColumns()  { -	std::map<std::string, LLScrollListColumn>::iterator itor; +	column_map_t::iterator itor;  	for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)  	{ -		LLScrollColumnHeader *header = itor->second.mHeader; +		LLScrollColumnHeader *header = itor->second->mHeader;  		if (header)  		{  			removeChild(header);  			delete header;  		}  	} +	std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer());  	mColumns.clear();  	mSortColumns.clear();  	mTotalStaticColumnWidth = 0; @@ -2745,7 +2747,7 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)  	column_map_t::iterator column_itor = mColumns.find(name);  	if (column_itor != mColumns.end())   	{ -		return &column_itor->second; +		return column_itor->second;  	}  	return NULL;  } @@ -2806,7 +2808,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS  				new_column.width.pixel_width = cell_p.width;  			}  			addColumn(new_column); -			columnp = &mColumns[column]; +			columnp = mColumns[column];  			new_item->setNumColumns(mColumns.size());  		} @@ -2843,7 +2845,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS  		LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value));  		if (cell)  		{ -			LLScrollListColumn* columnp = &(mColumns.begin()->second); +			LLScrollListColumn* columnp = mColumns.begin()->second;  			new_item->setColumn(0, cell);  			if (columnp->mHeader  @@ -2858,10 +2860,10 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS  	// add dummy cells for missing columns  	for (column_map_t::iterator column_it = mColumns.begin(); column_it != mColumns.end(); ++column_it)  	{ -		S32 column_idx = column_it->second.mIndex; +		S32 column_idx = column_it->second->mIndex;  		if (new_item->getColumn(column_idx) == NULL)  		{ -			LLScrollListColumn* column_ptr = &column_it->second; +			LLScrollListColumn* column_ptr = column_it->second;  			LLScrollListCell::Params cell_p;  			cell_p.width = column_ptr->getWidth(); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 8a2f893ba2..09ab89960d 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -491,7 +491,7 @@ private:  	mutable bool	mSorted; -	typedef std::map<std::string, LLScrollListColumn> column_map_t; +	typedef std::map<std::string, LLScrollListColumn*> column_map_t;  	column_map_t mColumns;  	BOOL			mDirty; diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index f97f80ab6c..9ad13054cb 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -45,6 +45,7 @@ LLParamSDParser::LLParamSDParser()  	if (sReadFuncs.empty())  	{ +		registerParserFuncs<LLInitParam::NoParamValue>(readNoValue, &LLParamSDParser::writeNoValue);  		registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>);  		registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param);  		registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); @@ -71,6 +72,18 @@ bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const voi  	return true;  } +bool LLParamSDParser::writeNoValue(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) +{ +	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); +	if (!sdparser.mWriteRootSD) return false; + +	LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); +	if (!sd_to_write) return false; + +	return true; +} + +  void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)  {  	mCurReadSD = NULL; @@ -87,6 +100,8 @@ void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)  	block.serializeBlock(*this);  } +const LLSD NO_VALUE_MARKER; +  void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block)  {  	if (sd.isMap()) @@ -110,6 +125,11 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block  			readSDValues(*it, block);  		}  	} +	else if (sd.isUndefined()) +	{ +		mCurReadSD = &NO_VALUE_MARKER; +		block.submitValue(mNameStack, *this); +	}  	else  	{  		mCurReadSD = &sd; @@ -206,6 +226,13 @@ LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)  	return sd_to_write;  } +bool LLParamSDParser::readNoValue(Parser& parser, void* val_ptr) +{ +	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); +	return self.mCurReadSD == &NO_VALUE_MARKER; +} + +  bool LLParamSDParser::readS32(Parser& parser, void* val_ptr)  {  	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h index 97e8b58e49..69dab2b411 100644 --- a/indra/llui/llsdparam.h +++ b/indra/llui/llsdparam.h @@ -63,7 +63,9 @@ private:  	LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack);  	static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); +	static bool writeNoValue(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack); +	static bool readNoValue(Parser& parser, void* val_ptr);  	static bool readS32(Parser& parser, void* val_ptr);  	static bool readU32(Parser& parser, void* val_ptr);  	static bool readF32(Parser& parser, void* val_ptr); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 1e2fe09cd9..c300fe55d9 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1596,23 +1596,25 @@ void LLUI::initClass(const settings_map_t& settings,  	sWindow = NULL; // set later in startup  	LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow"); +	LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); +  	// Callbacks for associating controls with floater visibilty: -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2)); -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2)); -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2)); -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2)); +	reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2)); +	reg.add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2)); +	reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2)); +	reg.add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));  	// Button initialization callback for toggle buttons -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); +	reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));  	// Button initialization callback for toggle buttons on dockale floaters -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2)); +	reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2));  	// Display the help topic for the current context -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2)); +	reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2));  	// Currently unused, but kept for reference: -	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); +	reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));  	// Used by menus along with Floater.Toggle to display visibility as a checkmark  	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2)); diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 0641f6d175..9455d09cc0 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -215,6 +215,12 @@ bool LLUIColorTable::loadFromSettings()  		result |= loadFromFilename(current_filename, mLoadedColors);  	} +	current_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SKIN, "colors.xml"); +	if(current_filename != default_filename) +	{ +		result |= loadFromFilename(current_filename, mLoadedColors); +	} +  	std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");  	loadFromFilename(user_filename, mUserSetColors); diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 4faa0e070e..cb40c85582 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -61,7 +61,6 @@ public:  	LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}  	LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);  	LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } -  	~LLUIString() { delete mArgs; }  	void assign(const std::string& instring); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index f25be55665..e51f28e2e9 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -27,6 +27,7 @@  #include "linden_common.h"  #include "llurlentry.h" +#include "lluictrl.h"  #include "lluri.h"  #include "llurlmatch.h"  #include "llurlregistry.h" @@ -167,6 +168,15 @@ void LLUrlEntryBase::callObservers(const std::string &id,  	}  } +/// is this a match for a URL that should not be hyperlinked? +bool LLUrlEntryBase::isLinkDisabled() const +{ +	// this allows us to have a global setting to turn off text hyperlink highlighting/action +	bool globally_disabled = LLUI::sSettingGroups["config"]->getBOOL("DisableTextHyperlinkActions"); + +	return globally_disabled; +} +  static std::string getStringAfterToken(const std::string str, const std::string token)  {  	size_t pos = str.find(token); diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 1a16056041..43a667c390 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -94,6 +94,8 @@ public:  	virtual LLUUID	getID(const std::string &string) const { return LLUUID::null; } +	bool isLinkDisabled() const; +  protected:  	std::string getIDStringFromUrl(const std::string &url) const;  	std::string escapeUrl(const std::string &url) const; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 3fa86bf0ca..267640a226 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -102,6 +102,7 @@ LLView::Params::Params()  	left_pad("left_pad"),  	left_delta("left_delta", S32_MAX),  	from_xui("from_xui", false), +	focus_root("focus_root", false),  	needs_translate("translate"),  	xmlns("xmlns"),  	xmlns_xsi("xmlns:xsi"), @@ -117,7 +118,7 @@ LLView::LLView(const LLView::Params& p)  	mParentView(NULL),  	mReshapeFlags(FOLLOWS_NONE),  	mFromXUI(p.from_xui), -	mIsFocusRoot(FALSE), +	mIsFocusRoot(p.focus_root),  	mLastVisible(FALSE),  	mNextInsertionOrdinal(0),  	mHoverCursor(getCursorFromString(p.hover_cursor)), @@ -163,8 +164,6 @@ LLView::~LLView()  	if (mDefaultWidgets)  	{ -		std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(), -					  DeletePairedPointer());  		delete mDefaultWidgets;  		mDefaultWidgets = NULL;  	} @@ -1682,18 +1681,7 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const  //-----------------------------------------------------------------------------  LLView* LLView::getChildView(const std::string& name, BOOL recurse) const  { -	LLView* child = findChildView(name, recurse); -	if (!child) -	{ -		child = getDefaultWidget<LLView>(name); -		if (!child) -		{ -			LLView::Params view_params; -			view_params.name = name; -			child = LLUICtrlFactory::create<LLView>(view_params); -		} -	} -	return child; +	return getChild<LLView>(name, recurse);  }  static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets"); @@ -2804,11 +2792,14 @@ LLView::root_to_view_iterator_t LLView::endRootToView()  // only create maps on demand, as they incur heap allocation/deallocation cost  // when a view is constructed/deconstructed -LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const +LLView& LLView::getDefaultWidgetContainer() const  {  	if (!mDefaultWidgets)  	{ -		mDefaultWidgets = new default_widget_map_t(); +		LLView::Params p; +		p.name = "default widget container"; +		p.visible = false; // ensures default widgets can't steal focus, etc. +		mDefaultWidgets = new LLView(p);  	}  	return *mDefaultWidgets;  } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 33d345beff..a5d8e31640 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -116,7 +116,8 @@ public:  									visible,  									mouse_opaque,  									use_bounding_rect, -									from_xui; +									from_xui, +									focus_root;  		Optional<S32>				tab_group,  									default_tab_group; @@ -466,12 +467,8 @@ public:  	template <class T> T* getDefaultWidget(const std::string& name) const  	{ -		default_widget_map_t::const_iterator found_it = getDefaultWidgetMap().find(name); -		if (found_it == getDefaultWidgetMap().end()) -		{ -			return NULL; -		} -		return dynamic_cast<T*>(found_it->second); +		LLView* widgetp = getDefaultWidgetContainer().findChildView(name); +		return dynamic_cast<T*>(widgetp);  	}  	////////////////////////////////////////////// @@ -585,9 +582,9 @@ private:  	typedef std::map<std::string, LLView*> default_widget_map_t;  	// allocate this map no demand, as it is rarely needed -	mutable default_widget_map_t* mDefaultWidgets; +	mutable LLView* mDefaultWidgets; -	default_widget_map_t& getDefaultWidgetMap() const; +	LLView& getDefaultWidgetContainer() const;  public:  	// Depth in view hierarchy during rendering @@ -654,7 +651,7 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co  				return NULL;  			} -			getDefaultWidgetMap()[name] = result; +			getDefaultWidgetContainer().addChild(result);  		}  	}  	return result; diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 5c6623da61..59c0826ad7 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -27,6 +27,7 @@  #include "linden_common.h"  #include "../llurlentry.h" +#include "../lluictrl.h"  #include "llurlentry_stub.cpp"  #include "lltut.h"  #include "../lluicolortable.h" @@ -34,6 +35,14 @@  #include <boost/regex.hpp> +typedef std::map<std::string, LLControlGroup*> settings_map_t; +settings_map_t LLUI::sSettingGroups; + +BOOL LLControlGroup::getBOOL(const std::string& name) +{ +	return false; +} +  LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const  {  	return LLUIColor(); | 
