From 40a74eb5b77493e66587a01b6655d405c75e3a59 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 12 Dec 2011 12:32:22 -0800
Subject: [PATCH] EXP-1711 FIX LLWindowShade doesn't stack multiple
 notifications

---
 indra/llui/lllayoutstack.h                 |   3 +-
 indra/llui/llpanel.h                       |   2 +
 indra/llui/llwindowshade.cpp               | 207 +++++++++++++--------
 indra/llui/llwindowshade.h                 |  10 +-
 indra/newview/llmediactrl.cpp              |  46 ++---
 indra/newview/llpanelprimmediacontrols.cpp |   3 +-
 6 files changed, 163 insertions(+), 108 deletions(-)

diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index ede6149a800..3b308a359d1 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -191,13 +191,12 @@ friend class LLUICtrlFactory;
 		return min_dim;
 	}
 
+	F32 getCollapseFactor();
 	void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; }
 
 protected:
 	LLLayoutPanel(const Params& p);
 	
-	F32 getCollapseFactor();
-
 	bool	mExpandedMinDimSpecified;
 	S32		mExpandedMinDim;
 	
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index cd339382263..f6202010202 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -135,6 +135,8 @@ class LLPanel : public LLUICtrl, public LLBadgeHolder
 	const LLColor4&	getBackgroundColor() const { return mBgOpaqueColor; }
 	void			setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; }
 	const LLColor4& getTransparentColor() const { return mBgAlphaColor; }
+	void			setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; }
+	void			setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; }
 	LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; }
 	LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; }
 	LLColor4		getBackgroundImageOverlay() { return mBgOpaqueImageOverlay; }
diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp
index cf762022155..0b4cfe68a65 100644
--- a/indra/llui/llwindowshade.cpp
+++ b/indra/llui/llwindowshade.cpp
@@ -37,6 +37,8 @@
 const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
 const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
 
+static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade");
+
 LLWindowShade::Params::Params()
 :	bg_image("bg_image"),
 	modal("modal", false),
@@ -48,7 +50,6 @@ LLWindowShade::Params::Params()
 
 LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
 :	LLUICtrl(params),
-	mNotification(params.notification),
 	mModal(params.modal),
 	mFormHeight(0),
 	mTextColor(params.text_color)
@@ -72,7 +73,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 	addChild(stackp);
 
 	LLLayoutPanel::Params panel_p;
-	panel_p.rect = LLRect(0, 30, 800, 0);
+	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0);
 	panel_p.name = "notification_area";
 	panel_p.visible = false;
 	panel_p.user_resize = false;
@@ -107,11 +108,11 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 
 	LLIconCtrl::Params icon_p;
 	icon_p.name = "notification_icon";
-	icon_p.rect = LLRect(5, 23, 21, 8);
+	icon_p.rect = LLRect(5, 25, 21, 10);
 	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
 
 	LLTextBox::Params text_p;
-	text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0);
+	text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3);
 	text_p.follows.flags = FOLLOWS_ALL;
 	text_p.text_color = mTextColor;
 	text_p.font = LLFontGL::getFontSansSerifSmall();
@@ -125,41 +126,132 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 	panel_p.auto_resize = false;
 	panel_p.user_resize = false;
 	panel_p.name="form_elements";
-	panel_p.rect = LLRect(0, 30, 130, 0);
+	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0);
 	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
 	stackp->addChild(form_elements_panel);
 
-	if (params.can_close)
+	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
+	panel_p.auto_resize = false;
+	panel_p.user_resize = false;
+	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0);
+	panel_p.name = "close_panel";
+	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
+	stackp->addChild(close_panel);
+
+	LLButton::Params button_p;
+	button_p.name = "close_notification";
+	button_p.rect = LLRect(5, 23, 21, 7);
+	button_p.image_color.control="DkGray_66";
+	button_p.image_unselected.name="Icon_Close_Foreground";
+	button_p.image_selected.name="Icon_Close_Press";
+	button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
+
+	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
+	
+	close_panel->setVisible(params.can_close);
+}
+
+void LLWindowShade::draw()
+{
+	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
+
+	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
+
+	notification_area->reshape(notification_area->getRect().getWidth(), 
+		llclamp(message_rect.getHeight() + 15, 
+				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
+				MAX_NOTIFICATION_AREA_HEIGHT));
+
+	LLUICtrl::draw();
+
+	while(!mNotifications.empty() && !mNotifications.back()->isActive())
+	{
+		mNotifications.pop_back();
+		// go ahead and hide 
+		hide();
+	}
+
+	if (mNotifications.empty())
+	{
+		hide();
+	}
+	else if (notification_area->getCollapseFactor() < 0.01f)
+	{
+		displayLatestNotification();
+	}
+
+	if (!notification_area->getVisible() && (notification_area->getCollapseFactor() < 0.001f))
+	{
+		getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
+		setMouseOpaque(false);
+	}
+}
+
+void LLWindowShade::hide()
+{
+	getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
+}
+
+void LLWindowShade::onCloseNotification()
+{
+	if (!mNotifications.empty())
+		LLNotifications::instance().cancel(mNotifications.back());
+}
+
+void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
+{
+	LLNotificationPtr notify = getCurrentNotification();
+	if (!notify) return;
+
+	bool check = ctrl->getValue().asBoolean();
+	if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
 	{
-		panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
-		panel_p.auto_resize = false;
-		panel_p.user_resize = false;
-		panel_p.rect = LLRect(0, 30, 25, 0);
-		LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
-		stackp->addChild(close_panel);
-
-		LLButton::Params button_p;
-		button_p.name = "close_notification";
-		button_p.rect = LLRect(5, 23, 21, 7);
-		button_p.image_color.control="DkGray_66";
-		button_p.image_unselected.name="Icon_Close_Foreground";
-		button_p.image_selected.name="Icon_Close_Press";
-		button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
-
-		close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
+		// question was "show again" so invert value to get "ignore"
+		check = !check;
 	}
+	notify->setIgnored(check);
+}
+
+void LLWindowShade::onClickNotificationButton(const std::string& name)
+{
+	LLNotificationPtr notify = getCurrentNotification();
+	if (!notify) return;
 
-	LLSD payload = mNotification->getPayload();
+	mNotificationResponse[name] = true;
 
-	LLNotificationFormPtr formp = mNotification->getForm();
+	notify->respond(mNotificationResponse);
+}
+
+void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
+{
+	mNotificationResponse[name] = ctrl->getValue().asString();
+}
+
+void LLWindowShade::show(LLNotificationPtr notification)
+{
+	mNotifications.push_back(notification);
+
+	displayLatestNotification();
+}
+
+void LLWindowShade::displayLatestNotification()
+{
+	if (mNotifications.empty()) return;
+
+	LLNotificationPtr notification = mNotifications.back();
+
+	LLSD payload = notification->getPayload();
+
+	LLNotificationFormPtr formp = notification->getForm();
 	LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
-	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon());
-	notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage());
-	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage());
+	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon());
+	notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage());
+	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage());
 
 	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); 
 	LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
 	form_elements.deleteAllChildren();
+	form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT);
 
 	const S32 FORM_PADDING_HORIZONTAL = 10;
 	const S32 FORM_PADDING_VERTICAL = 3;
@@ -229,7 +321,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 			label_p.v_pad = 5;
 			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
 			textbox->reshapeToFitText();
-			textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL); 
+			textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL); 
 			form_elements.addChild(textbox);
 			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
 
@@ -249,7 +341,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 		}
 	}
 
-	mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT;
+	mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL);
 	form_elements.reshape(form_width, mFormHeight);
 	form_elements.setMinDim(form_width);
 
@@ -261,68 +353,33 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 	{
 		(*it)->translate(0, delta_y);
 	}
-}
 
-void LLWindowShade::show()
-{
 	getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
 	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
 
 	setMouseOpaque(mModal);
 }
 
-void LLWindowShade::draw()
+void LLWindowShade::setBackgroundImage(LLUIImage* image)
 {
-	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
-
-	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
-
-	notification_area->reshape(notification_area->getRect().getWidth(), 
-		llclamp(message_rect.getHeight() + 10, 
-				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
-				MAX_NOTIFICATION_AREA_HEIGHT));
-
-	LLUICtrl::draw();
-	if (mNotification && !mNotification->isActive())
-	{
-		hide();
-	}
+	getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image);
 }
 
-void LLWindowShade::hide()
+void LLWindowShade::setTextColor(LLColor4 color)
 {
-	getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
-	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
-
-	setMouseOpaque(false);
+	getChild<LLTextBox>("notification_text")->setColor(color);
 }
 
-void LLWindowShade::onCloseNotification()
+void LLWindowShade::setCanClose(bool can_close)
 {
-	LLNotifications::instance().cancel(mNotification);
+	getChildView("close_panel")->setVisible(can_close);
 }
 
-void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
+LLNotificationPtr LLWindowShade::getCurrentNotification()
 {
-	bool check = ctrl->getValue().asBoolean();
-	if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+	if (mNotifications.empty())
 	{
-		// question was "show again" so invert value to get "ignore"
-		check = !check;
+		return LLNotificationPtr();
 	}
-	mNotification->setIgnored(check);
-}
-
-void LLWindowShade::onClickNotificationButton(const std::string& name)
-{
-	if (!mNotification) return;
-
-	mNotificationResponse[name] = true;
-
-	mNotification->respond(mNotificationResponse);
-}
-
-void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
-{
-	mNotificationResponse[name] = ctrl->getValue().asString();
-}
+	return mNotifications.back();
+}
\ No newline at end of file
diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h
index 09ffc2cd54b..1dcab4e32ff 100644
--- a/indra/llui/llwindowshade.h
+++ b/indra/llui/llwindowshade.h
@@ -36,7 +36,6 @@ class LLWindowShade : public LLUICtrl
 public:
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
-		Mandatory<LLNotificationPtr>	notification;
 		Optional<LLUIImage*>			bg_image;
 		Optional<LLUIColor>				text_color;
 		Optional<bool>					modal,
@@ -45,11 +44,16 @@ class LLWindowShade : public LLUICtrl
 		Params();
 	};
 
-	void show();
+	void show(LLNotificationPtr);
 	/*virtual*/ void draw();
 	void hide();
+	void setBackgroundImage(LLUIImage* image);
+	void setTextColor(LLColor4 color);
+	void setCanClose(bool can_close);
 
 private:
+	void displayLatestNotification();
+	LLNotificationPtr getCurrentNotification();
 	friend class LLUICtrlFactory;
 
 	LLWindowShade(const Params& p);
@@ -60,7 +64,7 @@ class LLWindowShade : public LLUICtrl
 	void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name);
 	void onClickIgnore(LLUICtrl* ctrl);
 
-	LLNotificationPtr	mNotification;
+	std::vector<LLNotificationPtr>	mNotifications;
 	LLSD				mNotificationResponse;
 	bool				mModal;
 	S32					mFormHeight;
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 74fa5d350a3..7650fe92296 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -133,10 +133,15 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 		navigateHome();
 	}
 		
-	// FIXME: How do we create a bevel now?
-//	LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 );
-//	mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN );
-//	addChild( mBorder );
+	LLWindowShade::Params params;
+	params.name = "notification_shade";
+	params.rect = getLocalRect();
+	params.follows.flags = FOLLOWS_ALL;
+	params.modal = true;
+
+	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
+
+	addChild(mWindowShade);
 }
 
 LLMediaCtrl::~LLMediaCtrl()
@@ -1092,39 +1097,28 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)
 
 void LLMediaCtrl::showNotification(LLNotificationPtr notify)
 {
-	delete mWindowShade;
+	LLWindowShade* shade = getChild<LLWindowShade>("notification_shade");
 
-	LLWindowShade::Params params;
-	params.name = "notification_shade";
-	params.rect = getLocalRect();
-	params.follows.flags = FOLLOWS_ALL;
-	params.notification = notify;
-	params.modal = true;
-	//HACK: don't hardcode this
 	if (notify->getIcon() == "Popup_Caution")
 	{
-		params.bg_image.name = "Yellow_Gradient";
-		params.text_color = LLColor4::black;
+		shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient"));
+		shade->setTextColor(LLColor4::black);
+		shade->setCanClose(true);
 	}
-	else
-	//HACK: another one since XUI doesn't support what we need right now
-	if (notify->getName() == "AuthRequest")
+	else if (notify->getName() == "AuthRequest")
 	{
-		params.bg_image.name = "Yellow_Gradient";
-		params.text_color = LLColor4::black;
-		params.can_close = false;
+		shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient"));
+		shade->setTextColor(LLColor4::black);
+		shade->setCanClose(false);
 	}
 	else
 	{
 		//HACK: make this a property of the notification itself, "cancellable"
-		params.can_close = false;
-		params.text_color.control = "LabelTextColor";
+		shade->setCanClose(false);
+		shade->setTextColor(LLUIColorTable::instance().getColor("LabelTextColor"));
 	}
 
-	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
-
-	addChild(mWindowShade);
-	mWindowShade->show();
+	mWindowShade->show(notify);
 }
 
 void LLMediaCtrl::hideNotification()
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 933b40ec791..39c0628cbe0 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -1351,7 +1351,6 @@ void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify)
 	LLWindowShade::Params params;
 	params.rect = mMediaRegion->getLocalRect();
 	params.follows.flags = FOLLOWS_ALL;
-	params.notification = notify;
 
 	//HACK: don't hardcode this
 	if (notify->getIcon() == "Popup_Caution")
@@ -1369,7 +1368,7 @@ void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify)
 	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
 
 	mMediaRegion->addChild(mWindowShade);
-	mWindowShade->show();
+	mWindowShade->show(notify);
 }
 
 void LLPanelPrimMediaControls::hideNotification()
-- 
GitLab