PageRenderTime 3314ms CodeModel.GetById 878ms app.highlight 1503ms RepoModel.GetById 182ms app.codeStats 113ms

/indra/newview/llscreenchannel.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 972 lines | 707 code | 154 blank | 111 comment | 157 complexity | d4836e02390ed45f8c864c1d703d667a MD5 | raw file
  1/** 
  2 * @file llscreenchannel.cpp
  3 * @brief Class implements a channel on a screen in which appropriate toasts may appear.
  4 *
  5 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27
 28#include "llviewerprecompiledheaders.h" // must be first include
 29
 30#include "lliconctrl.h"
 31#include "lltextbox.h"
 32#include "llscreenchannel.h"
 33
 34#include "lltoastpanel.h"
 35#include "llviewercontrol.h"
 36#include "llviewerwindow.h"
 37#include "llfloaterreg.h"
 38#include "lltrans.h"
 39
 40#include "lldockablefloater.h"
 41#include "llsyswellwindow.h"
 42#include "llimfloater.h"
 43#include "llscriptfloater.h"
 44#include "llrootview.h"
 45
 46#include <algorithm>
 47
 48using namespace LLNotificationsUI;
 49
 50bool LLScreenChannel::mWasStartUpToastShown = false;
 51
 52LLFastTimer::DeclareTimer FTM_GET_CHANNEL_RECT("Calculate Notification Channel Region");
 53LLRect LLScreenChannelBase::getChannelRect()
 54{
 55	LLFastTimer _(FTM_GET_CHANNEL_RECT);
 56
 57	if (mFloaterSnapRegion == NULL)
 58	{
 59		mFloaterSnapRegion = gViewerWindow->getRootView()->getChildView("floater_snap_region");
 60	}
 61	
 62	if (mChicletRegion == NULL)
 63	{
 64		mChicletRegion = gViewerWindow->getRootView()->getChildView("chiclet_container");
 65	}
 66	
 67	LLRect channel_rect;
 68	LLRect chiclet_rect;
 69
 70	mFloaterSnapRegion->localRectToScreen(mFloaterSnapRegion->getLocalRect(), &channel_rect);
 71	mChicletRegion->localRectToScreen(mChicletRegion->getLocalRect(), &chiclet_rect);
 72
 73	channel_rect.mTop = chiclet_rect.mBottom;
 74	return channel_rect;
 75}
 76
 77
 78//--------------------------------------------------------------------------
 79//////////////////////
 80// LLScreenChannelBase
 81//////////////////////
 82
 83LLScreenChannelBase::LLScreenChannelBase(const Params& p) 
 84:	LLUICtrl(p),
 85	mToastAlignment(p.toast_align),
 86	mCanStoreToasts(true),
 87	mHiddenToastsNum(0),
 88	mHoveredToast(NULL),
 89	mControlHovering(false),
 90	mShowToasts(true),
 91	mID(p.id),
 92	mDisplayToastsAlways(p.display_toasts_always),
 93	mChannelAlignment(p.channel_align),
 94	mFloaterSnapRegion(NULL),
 95	mChicletRegion(NULL)
 96{
 97	mID = p.id;
 98
 99	setMouseOpaque( false );
100	setVisible(FALSE);
101}
102
103BOOL LLScreenChannelBase::postBuild()
104{
105	if (mFloaterSnapRegion == NULL)
106	{
107		mFloaterSnapRegion = gViewerWindow->getRootView()->getChildView("floater_snap_region");
108	}
109	
110	if (mChicletRegion == NULL)
111	{
112		mChicletRegion = gViewerWindow->getRootView()->getChildView("chiclet_container");
113	}
114	
115	return TRUE;
116}
117
118void LLScreenChannelBase::reshape(S32 width, S32 height, BOOL called_from_parent)
119{
120	redrawToasts();
121}
122
123bool  LLScreenChannelBase::isHovering()
124{
125	if (!mHoveredToast)
126	{
127		return false;
128	}
129
130	return mHoveredToast->isHovered();
131}
132
133void LLScreenChannelBase::updatePositionAndSize(LLRect rect)
134{
135	LLRect this_rect = getRect();
136
137	this_rect.mTop = rect.mTop;
138	switch(mChannelAlignment)
139	{
140	case CA_LEFT :
141		break;
142	case CA_CENTRE :
143		this_rect.setCenterAndSize( (rect.getWidth()) / 2, rect.getHeight() / 2, this_rect.getWidth(), this_rect.getHeight());
144		break;
145	case CA_RIGHT :
146		this_rect.setLeftTopAndSize(rect.mRight - this_rect.getWidth(),
147			this_rect.mTop,
148			this_rect.getWidth(),
149			this_rect.getHeight());
150	}
151	setRect(this_rect);
152	redrawToasts();
153	
154}
155
156void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)
157{
158	// top and bottom set by updateRect()
159	setRect(LLRect(channel_left, 0, channel_right, 0));
160	updateRect();
161	setVisible(TRUE);
162}
163
164void	LLScreenChannelBase::updateRect()
165{
166	S32 channel_top = getChannelRect().mTop;
167	S32 channel_bottom = getChannelRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
168	S32 channel_left = getRect().mLeft;
169	S32 channel_right = getRect().mRight;
170	setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom));
171}
172
173//--------------------------------------------------------------------------
174//////////////////////
175// LLScreenChannel
176//////////////////////
177//--------------------------------------------------------------------------
178LLScreenChannel::LLScreenChannel(const Params& p)
179:	LLScreenChannelBase(p),
180	mStartUpToastPanel(NULL)
181{
182}
183
184//--------------------------------------------------------------------------
185void LLScreenChannel::init(S32 channel_left, S32 channel_right)
186{
187	LLScreenChannelBase::init(channel_left, channel_right);
188	LLRect channel_rect = getChannelRect();
189	updatePositionAndSize(channel_rect);
190}
191
192//--------------------------------------------------------------------------
193LLScreenChannel::~LLScreenChannel() 
194{
195	
196}
197
198std::list<LLToast*> LLScreenChannel::findToasts(const Matcher& matcher)
199{
200	std::list<LLToast*> res;
201
202	// collect stored toasts
203	for (std::vector<ToastElem>::iterator it = mStoredToastList.begin(); it
204			!= mStoredToastList.end(); it++)
205	{
206		if (matcher.matches(it->toast->getNotification()))
207		{
208			res.push_back(it->toast);
209		}
210	}
211
212	// collect displayed toasts
213	for (std::vector<ToastElem>::iterator it = mToastList.begin(); it
214			!= mToastList.end(); it++)
215	{
216		if (matcher.matches(it->toast->getNotification()))
217		{
218			res.push_back(it->toast);
219		}
220	}
221
222	return res;
223}
224
225//--------------------------------------------------------------------------
226void LLScreenChannel::updatePositionAndSize(LLRect new_world_rect)
227{
228	LLRect this_rect = getRect();
229
230	switch(mChannelAlignment)
231	{
232	case CA_LEFT :
233		this_rect.mTop = (S32) (new_world_rect.getHeight() * getHeightRatio());
234		break;
235	case CA_CENTRE :
236		LLScreenChannelBase::updatePositionAndSize(new_world_rect);
237		return;
238	case CA_RIGHT :
239		this_rect.mTop = (S32) (new_world_rect.getHeight() * getHeightRatio());
240		this_rect.setLeftTopAndSize(new_world_rect.mRight - this_rect.getWidth(),
241			this_rect.mTop,
242			this_rect.getWidth(),
243			this_rect.getHeight());
244	}
245	setRect(this_rect);
246	redrawToasts();
247}
248
249//--------------------------------------------------------------------------
250void LLScreenChannel::addToast(const LLToast::Params& p)
251{
252	bool store_toast = false, show_toast = false;
253
254	mDisplayToastsAlways ? show_toast = true : show_toast = mWasStartUpToastShown && (mShowToasts || p.force_show);
255	store_toast = !show_toast && p.can_be_stored && mCanStoreToasts;
256
257	if(!show_toast && !store_toast)
258	{
259		mRejectToastSignal(p.notif_id);
260		return;
261	}
262
263	ToastElem new_toast_elem(p);
264
265	new_toast_elem.toast->setOnFadeCallback(boost::bind(&LLScreenChannel::onToastFade, this, _1));
266	new_toast_elem.toast->setOnToastDestroyedCallback(boost::bind(&LLScreenChannel::onToastDestroyed, this, _1));
267	if(mControlHovering)
268	{
269		new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2));
270		new_toast_elem.toast->setMouseEnterCallback(boost::bind(&LLScreenChannel::stopToastTimer, this, new_toast_elem.toast));
271		new_toast_elem.toast->setMouseLeaveCallback(boost::bind(&LLScreenChannel::startToastTimer, this, new_toast_elem.toast));
272	}
273	
274	if(show_toast)
275	{
276		mToastList.push_back(new_toast_elem);
277		if(p.can_be_stored)
278		{
279			// store toasts immediately - EXT-3762
280			storeToast(new_toast_elem);
281		}
282		updateShowToastsState();
283		redrawToasts();
284	}	
285	else // store_toast
286	{
287		mHiddenToastsNum++;
288		storeToast(new_toast_elem);
289	}
290}
291
292//--------------------------------------------------------------------------
293void LLScreenChannel::onToastDestroyed(LLToast* toast)
294{	
295	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast));
296		
297	if(it != mToastList.end())
298	{
299		mToastList.erase(it);
300	}
301
302	it = find(mStoredToastList.begin(), mStoredToastList.end(), static_cast<LLPanel*>(toast));
303
304	if(it != mStoredToastList.end())
305	{
306		mStoredToastList.erase(it);
307	}
308
309	// if destroyed toast is hovered - reset hovered
310	if (mHoveredToast == toast)
311	{
312		mHoveredToast = NULL;
313	}
314}
315
316
317//--------------------------------------------------------------------------
318void LLScreenChannel::onToastFade(LLToast* toast)
319{	
320	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast));
321		
322	if(it != mToastList.end())
323	{
324		bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored();
325		if(delete_toast)
326		{
327			mToastList.erase(it);
328			deleteToast(toast);
329		}
330		else
331		{
332			storeToast((*it));
333			mToastList.erase(it);
334		}	
335
336		redrawToasts();
337	}
338}
339
340//--------------------------------------------------------------------------
341void LLScreenChannel::deleteToast(LLToast* toast)
342{
343	if (toast->isDead())
344	{
345		return;
346	}
347
348	// send signal to observers about destroying of a toast
349	toast->mOnDeleteToastSignal(toast);
350	
351	// update channel's Hovering state
352	// turning hovering off manually because onMouseLeave won't happen if a toast was closed using a keyboard
353	if(mHoveredToast == toast)
354	{
355		mHoveredToast  = NULL;
356	}
357
358	// close the toast
359	toast->closeFloater();
360}
361
362//--------------------------------------------------------------------------
363
364void LLScreenChannel::storeToast(ToastElem& toast_elem)
365{
366	// do not store clones
367	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), toast_elem.id);
368	if( it != mStoredToastList.end() )
369		return;
370
371	mStoredToastList.push_back(toast_elem);
372	mOnStoreToast(toast_elem.toast->getPanel(), toast_elem.id);
373}
374
375//--------------------------------------------------------------------------
376void LLScreenChannel::loadStoredToastsToChannel()
377{
378	std::vector<ToastElem>::iterator it;
379
380	if(mStoredToastList.size() == 0)
381		return;
382
383	for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)
384	{
385		(*it).toast->setIsHidden(false);
386		(*it).toast->startTimer();
387		mToastList.push_back((*it));
388	}
389
390	mStoredToastList.clear();
391	redrawToasts();
392}
393
394//--------------------------------------------------------------------------
395void LLScreenChannel::loadStoredToastByNotificationIDToChannel(LLUUID id)
396{
397	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
398
399	if( it == mStoredToastList.end() )
400		return;
401
402	LLToast* toast = (*it).toast;
403
404	if(toast->getVisible())
405	{
406		// toast is already in channel
407		return;
408	}
409
410	toast->setIsHidden(false);
411	toast->startTimer();
412	mToastList.push_back((*it));
413
414	redrawToasts();
415}
416
417//--------------------------------------------------------------------------
418void LLScreenChannel::removeStoredToastByNotificationID(LLUUID id)
419{
420	// *TODO: may be remove this function
421	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
422
423	if( it == mStoredToastList.end() )
424		return;
425
426	LLToast* toast = (*it).toast;
427	mStoredToastList.erase(it);
428	mRejectToastSignal(toast->getNotificationID());
429}
430
431//--------------------------------------------------------------------------
432void LLScreenChannel::killToastByNotificationID(LLUUID id)
433{
434	// searching among toasts on a screen
435	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id);
436	
437	if( it != mToastList.end())
438	{
439		LLToast* toast = (*it).toast;
440		// if it is a notification toast and notification is UnResponded - then respond on it
441		// else - simply destroy a toast
442		//
443		// NOTE:	if a notification is unresponded this function will be called twice for the same toast.
444		//			At first, the notification will be discarded, at second (it will be caused by discarding),
445		//			the toast will be destroyed.
446		if(toast->isNotificationValid())
447		{
448			mRejectToastSignal(toast->getNotificationID());
449		}
450		else
451		{
452			mToastList.erase(it);
453			deleteToast(toast);
454			redrawToasts();
455		}
456		return;
457	}
458
459	// searching among stored toasts
460	it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
461
462	if( it != mStoredToastList.end() )
463	{
464		LLToast* toast = (*it).toast;
465		mStoredToastList.erase(it);
466		// send signal to a listener to let him perform some action on toast rejecting
467		mRejectToastSignal(toast->getNotificationID());
468		deleteToast(toast);
469	}
470}
471
472void LLScreenChannel::killMatchedToasts(const Matcher& matcher)
473{
474	std::list<LLToast*> to_delete = findToasts(matcher);
475	for (std::list<LLToast*>::iterator it = to_delete.begin(); it
476			!= to_delete.end(); it++)
477	{
478		killToastByNotificationID((*it)-> getNotificationID());
479	}
480}
481
482//--------------------------------------------------------------------------
483void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
484{
485	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id);
486	
487	if( it != mToastList.end() && panel)
488	{
489		LLToast* toast = (*it).toast;
490		LLPanel* old_panel = toast->getPanel();
491		toast->removeChild(old_panel);
492		delete old_panel;
493		toast->insertPanel(panel);
494		toast->startTimer();
495		redrawToasts();
496	}
497}
498
499//--------------------------------------------------------------------------
500void LLScreenChannel::redrawToasts()
501{
502	if (!getParent())
503	{
504		// connect to floater snap region just to get resize events, we don't care about being a proper widget 
505		mFloaterSnapRegion->addChild(this);
506		setFollows(FOLLOWS_ALL);
507	}
508
509	if(mToastList.size() == 0)
510		return;
511
512	switch(mToastAlignment)
513	{
514	case NA_TOP : 
515		showToastsTop();
516		break;
517
518	case NA_CENTRE :
519		showToastsCentre();
520		break;
521
522	case NA_BOTTOM :
523		showToastsBottom();					
524	}
525}
526
527//--------------------------------------------------------------------------
528void LLScreenChannel::showToastsBottom()
529{
530	LLRect	toast_rect;	
531	S32		bottom = getRect().mBottom - gFloaterView->getRect().mBottom;
532	S32		toast_margin = 0;
533	std::vector<ToastElem>::reverse_iterator it;
534
535	updateRect();
536
537	LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get());
538
539	for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
540	{
541		if(it != mToastList.rbegin())
542		{
543			LLToast* toast = (*(it-1)).toast;
544			bottom = toast->getRect().mTop - toast->getTopPad();
545			toast_margin = gSavedSettings.getS32("ToastGap");
546		}
547
548		toast_rect = (*it).toast->getRect();
549		toast_rect.setOriginAndSize(getRect().mRight - toast_rect.getWidth(),
550				bottom + toast_margin, toast_rect.getWidth(),
551				toast_rect.getHeight());
552		(*it).toast->setRect(toast_rect);
553
554		if(floater && floater->overlapsScreenChannel())
555		{
556			if(it == mToastList.rbegin())
557			{
558				// move first toast above docked floater
559				S32 shift = floater->getRect().getHeight();
560				if(floater->getDockControl())
561				{
562					shift += floater->getDockControl()->getTongueHeight();
563				}
564				(*it).toast->translate(0, shift);
565			}
566
567			LLRect channel_rect = getChannelRect();
568			// don't show toasts if there is not enough space
569			if(toast_rect.mTop > channel_rect.mTop)
570			{
571				break;
572			}
573		}
574
575		bool stop_showing_toasts = (*it).toast->getRect().mTop > getRect().mTop;
576
577		if(!stop_showing_toasts)
578		{
579			if( it != mToastList.rend()-1)
580			{
581				S32 toast_top = (*it).toast->getRect().mTop + gSavedSettings.getS32("ToastGap");
582				stop_showing_toasts = toast_top > getRect().mTop;
583			}
584		} 
585
586		// at least one toast should be visible
587		if(it == mToastList.rbegin())
588		{
589			stop_showing_toasts = false;
590		}
591
592		if(stop_showing_toasts)
593			break;
594
595		if( !(*it).toast->getVisible() )
596		{
597			// HACK
598			// EXT-2653: it is necessary to prevent overlapping for secondary showed toasts
599			(*it).toast->setVisible(TRUE);
600		}		
601		if(!(*it).toast->hasFocus())
602		{
603			// Fixing Z-order of toasts (EXT-4862)
604			// Next toast will be positioned under this one.
605			gFloaterView->sendChildToBack((*it).toast);
606		}
607	}
608
609	// Dismiss toasts we don't have space for (STORM-391).
610	if(it != mToastList.rend())
611	{
612		mHiddenToastsNum = 0;
613		for(; it != mToastList.rend(); it++)
614		{
615			(*it).toast->hide();
616		}
617	}
618}
619
620//--------------------------------------------------------------------------
621void LLScreenChannel::showToastsCentre()
622{
623	LLRect	toast_rect;	
624	S32		bottom = (getRect().mTop - getRect().mBottom)/2 + mToastList[0].toast->getRect().getHeight()/2;
625	std::vector<ToastElem>::reverse_iterator it;
626
627	for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
628	{
629		toast_rect = (*it).toast->getRect();
630		toast_rect.setLeftTopAndSize(getRect().mLeft - toast_rect.getWidth() / 2, bottom + toast_rect.getHeight() / 2 + gSavedSettings.getS32("ToastGap"), toast_rect.getWidth() ,toast_rect.getHeight());
631		(*it).toast->setRect(toast_rect);
632
633		(*it).toast->setVisible(TRUE);	
634	}
635}
636
637//--------------------------------------------------------------------------
638void LLScreenChannel::showToastsTop()
639{
640	LLRect channel_rect = getChannelRect();
641
642	LLRect	toast_rect;	
643	S32		top = channel_rect.mTop;
644	S32		toast_margin = 0;
645	std::vector<ToastElem>::reverse_iterator it;
646
647	updateRect();
648
649	LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get());
650
651	for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
652	{
653		if(it != mToastList.rbegin())
654		{
655			LLToast* toast = (*(it-1)).toast;
656			top = toast->getRect().mBottom - toast->getTopPad();
657			toast_margin = gSavedSettings.getS32("ToastGap");
658		}
659
660		toast_rect = (*it).toast->getRect();
661		toast_rect.setLeftTopAndSize(channel_rect.mRight - toast_rect.getWidth(),
662			top, toast_rect.getWidth(),
663			toast_rect.getHeight());
664		(*it).toast->setRect(toast_rect);
665
666		if(floater && floater->overlapsScreenChannel())
667		{
668			if(it == mToastList.rbegin())
669			{
670				// move first toast above docked floater
671				S32 shift = -floater->getRect().getHeight();
672				if(floater->getDockControl())
673				{
674					shift -= floater->getDockControl()->getTongueHeight();
675				}
676				(*it).toast->translate(0, shift);
677			}
678
679			LLRect channel_rect = getChannelRect();
680			// don't show toasts if there is not enough space
681			if(toast_rect.mBottom < channel_rect.mBottom)
682			{
683				break;
684			}
685		}
686
687		bool stop_showing_toasts = (*it).toast->getRect().mBottom < channel_rect.mBottom;
688
689		if(!stop_showing_toasts)
690		{
691			if( it != mToastList.rend()-1)
692			{
693				S32 toast_bottom = (*it).toast->getRect().mBottom - gSavedSettings.getS32("ToastGap");
694				stop_showing_toasts = toast_bottom < channel_rect.mBottom;
695			}
696		} 
697
698		// at least one toast should be visible
699		if(it == mToastList.rbegin())
700		{
701			stop_showing_toasts = false;
702		}
703
704		if(stop_showing_toasts)
705			break;
706
707		if( !(*it).toast->getVisible() )
708		{
709			// HACK
710			// EXT-2653: it is necessary to prevent overlapping for secondary showed toasts
711			(*it).toast->setVisible(TRUE);
712		}		
713		if(!(*it).toast->hasFocus())
714		{
715			// Fixing Z-order of toasts (EXT-4862)
716			// Next toast will be positioned under this one.
717			gFloaterView->sendChildToBack((*it).toast);
718		}
719	}
720
721	// Dismiss toasts we don't have space for (STORM-391).
722	if(it != mToastList.rend())
723	{
724		mHiddenToastsNum = 0;
725		for(; it != mToastList.rend(); it++)
726		{
727			(*it).toast->hide();
728		}
729	}
730}
731
732//--------------------------------------------------------------------------
733void LLScreenChannel::createStartUpToast(S32 notif_num, F32 timer)
734{
735	LLScreenChannelBase::updateRect();
736
737	LLRect toast_rect;
738	LLToast::Params p;
739	p.lifetime_secs = timer;
740	p.enable_hide_btn = false;
741	mStartUpToastPanel = new LLToast(p);
742
743	if(!mStartUpToastPanel)
744		return;
745
746	mStartUpToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onStartUpToastHide, this));
747
748	LLPanel* wrapper_panel = mStartUpToastPanel->getChild<LLPanel>("wrapper_panel");
749	LLTextBox* text_box = mStartUpToastPanel->getChild<LLTextBox>("toast_text");
750
751	std::string	text = LLTrans::getString("StartUpNotifications");
752
753	toast_rect = mStartUpToastPanel->getRect();
754	mStartUpToastPanel->reshape(getRect().getWidth(), toast_rect.getHeight(), true);
755
756	text_box->setValue(text);
757	text_box->setVisible(TRUE);
758
759	text_box->reshapeToFitText();
760	text_box->setOrigin(text_box->getRect().mLeft, (wrapper_panel->getRect().getHeight() - text_box->getRect().getHeight())/2);
761
762	toast_rect.setLeftTopAndSize(0, getRect().getHeight() - gSavedSettings.getS32("ToastGap"), getRect().getWidth(), toast_rect.getHeight());
763	mStartUpToastPanel->setRect(toast_rect);
764
765	addChild(mStartUpToastPanel);
766	
767	mStartUpToastPanel->setVisible(TRUE);
768}
769
770// static --------------------------------------------------------------------------
771F32 LLScreenChannel::getHeightRatio()
772{
773	F32 ratio = gSavedSettings.getF32("NotificationChannelHeightRatio");
774	if(0.0f > ratio)
775	{
776		ratio = 0.0f;
777	}
778	else if(1.0f < ratio)
779	{
780		ratio = 1.0f;
781	}
782	return ratio;
783}
784
785//--------------------------------------------------------------------------
786void LLScreenChannel::updateStartUpString(S32 num)
787{
788	// *TODO: update string if notifications are arriving while the StartUp toast is on a screen
789}
790
791//--------------------------------------------------------------------------
792void LLScreenChannel::onStartUpToastHide()
793{
794	onCommit();
795}
796
797//--------------------------------------------------------------------------
798void LLScreenChannel::closeStartUpToast()
799{
800	if(mStartUpToastPanel != NULL)
801	{
802		mStartUpToastPanel->setVisible(FALSE);
803		mStartUpToastPanel = NULL;
804	}
805}
806
807void LLNotificationsUI::LLScreenChannel::stopToastTimer(LLToast* toast)
808{
809	if (!toast || toast != mHoveredToast) return;
810
811	// Pause fade timer of the hovered toast.
812	toast->stopTimer();
813}
814
815void LLNotificationsUI::LLScreenChannel::startToastTimer(LLToast* toast)
816{
817	if (!toast || toast == mHoveredToast)
818	{
819		return;
820	}
821
822	// Reset its fade timer.
823	toast->startTimer();
824}
825
826//--------------------------------------------------------------------------
827void LLScreenChannel::hideToastsFromScreen()
828{
829	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
830		(*it).toast->setVisible(FALSE);
831}
832
833//--------------------------------------------------------------------------
834void LLScreenChannel::hideToast(const LLUUID& notification_id)
835{
836	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), notification_id);
837	if(mToastList.end() != it)
838	{
839		ToastElem te = *it;
840		te.toast->hide();
841	}
842}
843
844void LLScreenChannel::closeHiddenToasts(const Matcher& matcher)
845{
846	// since we can't guarantee that close toast operation doesn't change mToastList
847	// we collect matched toasts that should be closed into separate list
848	std::list<ToastElem> toasts;
849	for (std::vector<ToastElem>::iterator it = mToastList.begin(); it
850			!= mToastList.end(); it++)
851	{
852		LLToast * toast = it->toast;
853		// add to list valid toast that match to provided matcher criteria
854		if (toast != NULL && !toast->isDead() && toast->getNotification() != NULL
855				&& !toast->getVisible() && matcher.matches(toast->getNotification()))
856		{
857			toasts.push_back(*it);
858		}
859	}
860
861	// close collected toasts
862	for (std::list<ToastElem>::iterator it = toasts.begin(); it
863			!= toasts.end(); it++)
864	{
865		it->toast->closeFloater();
866	}
867}
868
869//--------------------------------------------------------------------------
870void LLScreenChannel::removeToastsFromChannel()
871{
872	hideToastsFromScreen();
873	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
874	{
875		deleteToast((*it).toast);
876	}
877	mToastList.clear();
878}
879
880//--------------------------------------------------------------------------
881void LLScreenChannel::removeAndStoreAllStorableToasts()
882{
883	if(mToastList.size() == 0)
884		return;
885
886	hideToastsFromScreen();
887	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end();)
888	{
889		if((*it).toast->getCanBeStored())
890		{
891			storeToast(*(it));
892			it = mToastList.erase(it);
893		}
894		else
895		{
896			++it;
897		}
898	}
899	redrawToasts();
900}
901
902//--------------------------------------------------------------------------
903void LLScreenChannel::removeToastsBySessionID(LLUUID id)
904{
905	if(mToastList.size() == 0)
906		return;
907
908	hideToastsFromScreen();
909	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end();)
910	{
911		if((*it).toast->getSessionID() == id)
912		{
913			deleteToast((*it).toast);
914			it = mToastList.erase(it);
915		}
916		else
917		{
918			++it;
919		}
920	}
921	redrawToasts();
922}
923
924//--------------------------------------------------------------------------
925void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)
926{
927	// because of LLViewerWindow::updateUI() that NOT ALWAYS calls onMouseEnter BEFORE onMouseLeave
928	// we must check hovering directly to prevent incorrect setting for hovering in a channel
929	if (mouse_enter)
930	{
931		if (toast->isHovered())
932		{
933			mHoveredToast = toast;
934		}
935	}
936	else if (mHoveredToast != NULL)
937	{
938		if (!mHoveredToast->isHovered())
939		{
940			mHoveredToast = NULL;
941		}
942	}
943
944	redrawToasts();
945}
946
947//--------------------------------------------------------------------------
948void LLScreenChannel::updateShowToastsState()
949{
950	LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get());
951
952	if(!floater)
953	{
954		setShowToasts(true);
955		return;
956	}
957
958	updateRect();
959}
960
961//--------------------------------------------------------------------------
962
963LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id)
964{
965	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(),
966			mStoredToastList.end(), id);
967
968	if (it == mStoredToastList.end())
969		return NULL;
970
971	return it->toast;
972}