From 13a6077b780117be0fa3a054426d139ca1d35df9 Mon Sep 17 00:00:00 2001
From: Dmitry Zaporozhan <dzaporozhan@productengine.com>
Date: Fri, 20 Nov 2009 19:17:38 +0200
Subject: [PATCH] Implemented normal task EXT-2081 - Object IM chiclets art
 needs to be hooked up to LLDialog chiclets. Implemented
 LLDialog(LLScriptFloater) and Script Chiclets.

--HG--
branch : product-engine
---
 indra/newview/CMakeLists.txt                  |   2 +
 indra/newview/llchiclet.cpp                   |  56 +++
 indra/newview/llchiclet.h                     |  34 ++
 indra/newview/llimview.cpp                    |   2 +-
 indra/newview/llnotificationscripthandler.cpp |  51 ++-
 indra/newview/llscreenchannel.cpp             |   4 +-
 indra/newview/llscriptfloater.cpp             | 335 ++++++++++++++++++
 indra/newview/llscriptfloater.h               | 114 ++++++
 indra/newview/llviewerfloaterreg.cpp          |   2 +
 indra/newview/llviewermessage.cpp             |  10 +
 .../skins/default/xui/en/floater_script.xml   |  19 +
 .../skins/default/xui/en/notifications.xml    |  23 +-
 12 files changed, 634 insertions(+), 18 deletions(-)
 create mode 100644 indra/newview/llscriptfloater.cpp
 create mode 100644 indra/newview/llscriptfloater.h
 create mode 100644 indra/newview/skins/default/xui/en/floater_script.xml

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index e7458529bee..8537c92ff74 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -364,6 +364,7 @@ set(viewer_SOURCE_FILES
     llremoteparcelrequest.cpp
     llsavedsettingsglue.cpp
     llscreenchannel.cpp
+    llscriptfloater.cpp
     llscrollingpanelparam.cpp
     llsearchcombobox.cpp
     llsearchhistory.cpp
@@ -860,6 +861,7 @@ set(viewer_HEADER_FILES
     llrootview.h
     llsavedsettingsglue.h
     llscreenchannel.h
+    llscriptfloater.h
     llscrollingpanelparam.h
     llsearchcombobox.h
     llsearchhistory.h
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index caf6917d90e..15c4c5f95d0 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -43,6 +43,7 @@
 #include "lllocalcliprect.h"
 #include "llmenugl.h"
 #include "lloutputmonitorctrl.h"
+#include "llscriptfloater.h"
 #include "lltextbox.h"
 #include "llvoiceclient.h"
 #include "llvoicecontrolpanel.h"
@@ -1392,3 +1393,58 @@ LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p)
  : LLOutputMonitorCtrl(p)
 {
 }
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLScriptChiclet::Params::Params()
+ : avatar_icon("avatar_icon")
+{
+	// *TODO Vadim: Get rid of hardcoded values.
+	rect(CHICLET_RECT);
+	name("dialog_chiclet");
+
+	avatar_icon.name("avatar_icon");
+	avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+
+	avatar_icon.rect(CHICLET_ICON_RECT);
+	avatar_icon.mouse_opaque(false);
+}
+
+LLScriptChiclet::LLScriptChiclet(const Params&p)
+ : LLIMChiclet(p)
+ , mChicletIconCtrl(NULL)
+{
+	mImage = LLUI::getUIImage("Generic_Object_Small");
+}
+
+void LLScriptChiclet::setSessionId(const LLUUID& session_id)
+{
+	setShowNewMessagesIcon( getSessionId() != session_id );
+
+	LLIMChiclet::setSessionId(session_id);
+	LLNotificationPtr notification = LLNotifications::getInstance()->find(
+		LLScriptFloaterManager::getInstance()->getNotificationId(session_id));
+	if(notification)
+	{
+		setToolTip(notification->getSubstitutions()["TITLE"].asString());
+	}
+}
+
+void LLScriptChiclet::draw()
+{
+	mImage->draw(getLocalRect());
+	LLIMChiclet::draw();
+}
+
+void LLScriptChiclet::onMouseDown()
+{
+	LLScriptFloaterManager::getInstance()->toggleScriptFloater(getSessionId());
+}
+
+BOOL LLScriptChiclet::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	onMouseDown();
+	return LLChiclet::handleMouseDown(x, y, mask);
+}
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index bb5dc1e5500..a46f817c13b 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -533,6 +533,40 @@ class LLAdHocChiclet : public LLIMChiclet
 	LLMenuGL* mPopupMenu;
 };
 
+class LLScriptChiclet : public LLIMChiclet
+{
+public:
+
+	struct Params : public LLInitParam::Block<Params, LLIMChiclet::Params>
+	{
+		Optional<LLChicletAvatarIconCtrl::Params> avatar_icon;
+
+		Params();
+	};
+
+	void setSessionId(const LLUUID& session_id);
+
+	void setCounter(S32 counter){}
+
+	S32 getCounter() { return 0; }
+
+	void onMouseDown();
+
+	BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+
+	void draw();
+
+protected:
+
+	LLScriptChiclet(const Params&);
+	friend class LLUICtrlFactory;
+
+private:
+
+	LLPointer<LLUIImage> mImage;
+	LLChicletAvatarIconCtrl* mChicletIconCtrl;
+};
+
 /**
  * Implements Group chat chiclet.
  */
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index dd78bb631fd..b509fe4043a 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -49,7 +49,7 @@
 #include "llbottomtray.h"
 #include "llcallingcard.h"
 #include "llchat.h"
-#include "llchiclet.h"
+#include "llchiclet.h"
 #include "llresmgr.h"
 #include "llfloaterchat.h"
 #include "llfloaterchatterbox.h"
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 70b86e8b976..84a81913757 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -38,6 +38,7 @@
 #include "llviewercontrol.h"
 #include "llviewerwindow.h"
 #include "llnotificationmanager.h"
+#include "llscriptfloater.h"
 
 using namespace LLNotificationsUI;
 
@@ -90,25 +91,37 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
 	
 	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
 	{
-		LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);
-
-		LLToast::Params p;
-		p.notif_id = notification->getID();
-		p.notification = notification;
-		p.panel = notify_box;	
-		p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1);
-
-		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
-		if(channel)
-			channel->addToast(p);
-
-		// send a signal to the counter manager
-		mNewNotificationSignal();
-
+		if("ScriptDialog" == notification->getName() || "ScriptDialogGroup" == notification->getName())
+		{
+			LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID());
+		}
+		else
+		{
+			LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);
+
+			LLToast::Params p;
+			p.notif_id = notification->getID();
+			p.notification = notification;
+			p.panel = notify_box;	
+			p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1);
+
+			LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
+			if(channel)
+			{
+				channel->addToast(p);
+			}
+
+			// send a signal to the counter manager
+			mNewNotificationSignal();
+		}
 	}
 	else if (notify["sigtype"].asString() == "delete")
 	{
 		mChannel->killToastByNotificationID(notification->getID());
+		if("ScriptDialog" == notification->getName())
+		{
+			LLScriptFloaterManager::getInstance()->removeNotification(notification->getID());
+		}
 	}
 	return true;
 }
@@ -123,6 +136,14 @@ void LLScriptHandler::onDeleteToast(LLToast* toast)
 	// send a signal to a listener to let him perform some action
 	// in this case listener is a SysWellWindow and it will remove a corresponding item from its list
 	mNotificationIDSignal(toast->getNotificationID());
+
+	LLNotificationPtr notification = LLNotifications::getInstance()->find(toast->getNotificationID());
+	
+	if( notification && ("ScriptDialog" == notification->getName() 
+		|| "ScriptDialogGroup" == notification->getName()) )
+	{
+		LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
+	}
 }
 
 //--------------------------------------------------------------------------
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 81eb133b07f..f033251831c 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -46,6 +46,7 @@
 #include "lldockablefloater.h"
 #include "llsyswellwindow.h"
 #include "llimfloater.h"
+#include "llscriptfloater.h"
 
 #include <algorithm>
 
@@ -698,7 +699,8 @@ void LLScreenChannel::updateShowToastsState()
 	}
 
 	// for IM floaters showed in a docked state - prohibit showing of ani toast
-	if(dynamic_cast<LLIMFloater*>(floater))
+	if(dynamic_cast<LLIMFloater*>(floater)
+		|| dynamic_cast<LLScriptFloater*>(floater) )
 	{
 		setShowToasts(!(floater->getVisible() && floater->isDocked()));
 		if (!getShowToasts())
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
new file mode 100644
index 00000000000..6fdde1df991
--- /dev/null
+++ b/indra/newview/llscriptfloater.cpp
@@ -0,0 +1,335 @@
+/** 
+ * @file llscriptfloater.cpp
+ * @brief LLScriptFloater class definition
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llscriptfloater.h"
+
+#include "llbottomtray.h"
+#include "llchannelmanager.h"
+#include "llchiclet.h"
+#include "llfloaterreg.h"
+#include "llscreenchannel.h"
+#include "lltoastnotifypanel.h"
+#include "llviewerwindow.h"
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLUUID notification_id_to_object_id(const LLUUID& notification_id)
+{
+	LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id);
+	if(notification)
+	{
+		return notification->getPayload()["object_id"].asUUID();
+	}
+	return LLUUID::null;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLScriptFloater::LLScriptFloater(const LLSD& key)
+: LLTransientDockableFloater(NULL, true, key)
+, mObjectId(key.asUUID())
+{
+}
+
+bool LLScriptFloater::toggle(const LLUUID& object_id)
+{
+	LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", object_id);
+
+	// show existing floater
+	if(floater)
+	{
+		if(floater->getVisible())
+		{
+			floater->setVisible(false);
+			return false;
+		}
+		else
+		{
+			floater->setVisible(TRUE);
+			floater->setFocus(TRUE);
+			return true;
+		}
+	}
+	else
+	{
+		show(object_id);
+		return true;
+	}
+}
+
+LLScriptFloater* LLScriptFloater::show(const LLUUID& object_id)
+{
+	LLScriptFloater* floater = LLFloaterReg::showTypedInstance<LLScriptFloater>("script_floater", object_id);
+	floater->createForm(object_id);
+
+	if (floater->getDockControl() == NULL)
+	{
+		LLChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(object_id);
+		if (chiclet == NULL)
+		{
+			llerror("Dock chiclet for LLScriptFloater doesn't exist", 0);
+		}
+		else
+		{
+			LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
+		}
+
+		floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(),
+			LLDockControl::TOP,  boost::bind(&LLScriptFloater::getAllowedRect, floater, _1)));
+	}
+
+	return floater;
+}
+
+void LLScriptFloater::getAllowedRect(LLRect& rect)
+{
+	rect = gViewerWindow->getWorldViewRectRaw();
+}
+
+void LLScriptFloater::createForm(const LLUUID& object_id)
+{
+	static const std::string PANEL_NAME = "_notification_panel_";
+
+	LLPanel* old_panel = findChild<LLPanel>(PANEL_NAME);
+	if(old_panel)
+	{
+		removeChild(old_panel);
+	}
+
+	LLNotificationPtr notification = LLNotifications::getInstance()->find(
+		LLScriptFloaterManager::getInstance()->getNotificationId(object_id));
+	if(NULL == notification)
+	{
+		return;
+	}
+	LLToastNotifyPanel* panel = new LLToastNotifyPanel(notification);
+	panel->setName(PANEL_NAME);
+	addChild(panel);
+
+	LLRect panel_rect;
+
+	panel_rect = panel->getRect();
+	panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight());
+	reshape(panel_rect.getWidth(), panel_rect.getHeight());
+	panel->setRect(panel_rect);
+
+	LLRect toast_rect = getRect();
+	toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, panel_rect.getWidth(), panel_rect.getHeight() + getHeaderHeight());
+	reshape(toast_rect.getWidth(), toast_rect.getHeight());
+	setRect(toast_rect);
+}
+
+void LLScriptFloater::onClose(bool app_quitting)
+{
+	LLScriptFloaterManager::getInstance()->closeScriptFloater(getObjectId());
+	setObjectId(LLUUID::null);
+}
+
+void LLScriptFloater::setDocked(bool docked, bool pop_on_undock /* = true */)
+{
+	LLTransientDockableFloater::setDocked(docked, pop_on_undock);
+
+	updateToasts();
+}
+
+void LLScriptFloater::setVisible(BOOL visible)
+{
+	LLTransientDockableFloater::setVisible(visible);
+
+	updateToasts();
+}
+
+void LLScriptFloater::updateToasts()
+{
+	using namespace LLNotificationsUI;
+
+	// find channel
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID(
+		LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+	// update notification channel state
+	if(channel)
+	{
+		channel->updateShowToastsState();
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
+{
+	// get scripted Object's ID
+	LLUUID object_id = notification_id_to_object_id(notification_id);
+	if(object_id.isNull())
+	{
+		llerrs << "Invalid notification, no object id" << llendl;
+		return;
+	}
+
+	// If an Object spawns more-than-one floater, only the newest one is shown. 
+	// The other is automatically closed.
+	script_notification_map_t::iterator it = mNotifications.find(object_id);
+	if(it != mNotifications.end())
+	{
+		removeNotification(notification_id);
+	}
+
+	LLNotificationData nd = {notification_id};
+	mNotifications.insert(std::make_pair(object_id, nd));
+
+	LLBottomTray::getInstance()->getChicletPanel()->createChiclet<LLScriptChiclet>(object_id);
+}
+
+void LLScriptFloaterManager::onRemoveNotification(const LLUUID& notification_id)
+{
+	LLUUID object_id = notification_id_to_object_id(notification_id);
+	if(object_id.isNull())
+	{
+		llerrs << "Invalid notification, no object id" << llendl;
+		return;
+	}
+
+	using namespace LLNotificationsUI;
+
+	// remove related toast
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID(
+		LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+	if(channel)
+	{
+		channel->killToastByNotificationID(getToastNotificationId(object_id));
+	}
+
+	mNotifications.erase(object_id);
+
+	// remove related chiclet
+	LLBottomTray::getInstance()->getChicletPanel()->removeChiclet(object_id);
+
+	// close floater
+	LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", object_id);
+	if(floater)
+	{
+		floater->closeFloater();
+	}
+}
+
+void LLScriptFloaterManager::toggleScriptFloater(const LLUUID& object_id)
+{
+	// hide "new message" icon from chiclet
+	LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(object_id);
+	if(chiclet)
+	{
+		chiclet->setShowNewMessagesIcon(false);
+	}
+
+	// kill toast
+	using namespace LLNotificationsUI;
+	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID(
+		LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+	if(channel)
+	{
+		channel->killToastByNotificationID(getToastNotificationId(object_id));
+	}
+
+	// toggle floater
+	LLScriptFloater::toggle(object_id);
+}
+
+void LLScriptFloaterManager::closeScriptFloater(const LLUUID& object_id)
+{
+	LLNotificationPtr notification = LLNotifications::getInstance()->find(
+		getNotificationId(object_id));
+	if(notification)
+	{
+		removeNotification(notification->getID());
+	}
+}
+
+void LLScriptFloaterManager::setToastNotificationId(const LLUUID& object_id, const LLUUID& notification_id)
+{
+	script_notification_map_t::iterator it = mNotifications.find(object_id);
+	if(mNotifications.end() != it)
+	{
+		it->second.toast_notification_id = notification_id;
+	}
+}
+
+const LLUUID& LLScriptFloaterManager::getNotificationId(const LLUUID& object_id)
+{
+	script_notification_map_t::const_iterator it = mNotifications.find(object_id);
+	if(mNotifications.end() != it)
+	{
+		return it->second.notification_id;
+	}
+	return LLUUID::null;
+}
+
+const LLUUID& LLScriptFloaterManager::getToastNotificationId(const LLUUID& object_id)
+{
+	script_notification_map_t::const_iterator it = mNotifications.find(object_id);
+	if(mNotifications.end() != it)
+	{
+		return it->second.toast_notification_id;
+	}
+	return LLUUID::null;
+}
+
+//static
+void LLScriptFloaterManager::onToastButtonClick(const LLSD&notification, const LLSD&response)
+{
+	S32 option = LLNotification::getSelectedOption(notification, response);
+	LLUUID object_id = notification["payload"]["object_id"].asUUID();
+
+	switch(option)
+	{
+	case 0: // "Open"
+		LLScriptFloaterManager::getInstance()->toggleScriptFloater(object_id);
+		break;
+	case 1: // "Ignore"
+		LLScriptFloaterManager::getInstance()->closeScriptFloater(object_id);
+		break;
+	case 2: // "Mute"
+		LLMuteList::getInstance()->add(LLMute(object_id, notification["substitutions"]["TITLE"], LLMute::OBJECT));
+		LLScriptFloaterManager::getInstance()->closeScriptFloater(object_id);
+		break;
+	default:
+		llwarns << "Unexpected value" << llendl;
+		break;
+	}
+}
+
+// EOF
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
new file mode 100644
index 00000000000..fc1d9a01866
--- /dev/null
+++ b/indra/newview/llscriptfloater.h
@@ -0,0 +1,114 @@
+/** 
+ * @file llscriptfloater.h
+ * @brief LLScriptFloater class definition
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_SCRIPTFLOATER_H
+#define LL_SCRIPTFLOATER_H
+
+#include "lltransientdockablefloater.h"
+
+/**
+ * This class manages Object script floaters.
+ */
+class LLScriptFloaterManager : public LLSingleton<LLScriptFloaterManager>
+{
+public:
+
+	void onAddNotification(const LLUUID& notification_id);
+
+	void onRemoveNotification(const LLUUID& notification_id);
+
+	void toggleScriptFloater(const LLUUID& object_id);
+
+	void closeScriptFloater(const LLUUID& object_id);
+
+	const LLUUID& getNotificationId(const LLUUID& object_id);
+
+	const LLUUID& getToastNotificationId(const LLUUID& object_id);
+
+	void setToastNotificationId(const LLUUID& object_id, const LLUUID& notification_id);
+
+	static void onToastButtonClick(const LLSD&notification, const LLSD&response);
+
+private:
+
+	struct LLNotificationData
+	{
+		LLUUID notification_id;
+		LLUUID toast_notification_id;
+	};
+
+	typedef std::map<LLUUID, LLNotificationData> script_notification_map_t;
+
+	script_notification_map_t mNotifications;
+};
+
+/**
+ * Floater for displaying script forms
+ */
+class LLScriptFloater : public LLTransientDockableFloater
+{
+public:
+
+	/**
+	 * key - UUID of scripted Object
+	 */
+	LLScriptFloater(const LLSD& key);
+
+	virtual ~LLScriptFloater(){};
+
+	static bool toggle(const LLUUID& object_id);
+
+	static LLScriptFloater* show(const LLUUID& object_id);
+
+	const LLUUID& getObjectId() { return mObjectId; }
+
+	/*virtual*/ void onClose(bool app_quitting);
+
+	/*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
+
+	/*virtual*/ void setVisible(BOOL visible);
+
+protected:
+
+	void createForm(const LLUUID& object_id);
+
+	/*virtual*/ void getAllowedRect(LLRect& rect);
+
+	static void updateToasts();
+
+	void setObjectId(const LLUUID& id) { mObjectId = id; }
+
+private:
+	LLUUID mObjectId;
+};
+
+#endif //LL_SCRIPTFLOATER_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 7772f613f0a..812107dd72b 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -124,6 +124,7 @@
 #include "llpreviewsound.h"
 #include "llpreviewtexture.h"
 #include "llsyswellwindow.h"
+#include "llscriptfloater.h"
 // *NOTE: Please add files in alphabetical order to keep merges easy.
 
 
@@ -171,6 +172,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);
 
 	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
+	LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>);
 	LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);
 	LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>);
 	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 8db6d5917a8..ac1f366f9cd 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -101,6 +101,7 @@
 #include "llpanelgrouplandmoney.h"
 #include "llpanelplaces.h"
 #include "llrecentpeople.h"
+#include "llscriptfloater.h"
 #include "llselectmgr.h"
 #include "llsidetray.h"
 #include "llstartup.h"
@@ -5380,6 +5381,15 @@ void process_script_dialog(LLMessageSystem* msg, void**)
 		notification = LLNotifications::instance().add(
 			LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD()));
 	}
+
+	LLNotification::Params p("ScriptToast");
+	p.substitutions(args).payload(payload).functor.function(boost::bind(
+		LLScriptFloaterManager::onToastButtonClick, _1, _2));
+
+	notification = LLNotifications::instance().add(p);
+
+	LLScriptFloaterManager::getInstance()->setToastNotificationId(
+		object_id, notification->getID());
 }
 
 //---------------------------------------------------------------------------
diff --git a/indra/newview/skins/default/xui/en/floater_script.xml b/indra/newview/skins/default/xui/en/floater_script.xml
new file mode 100644
index 00000000000..f44ba6d873e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_script.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ background_visible="true"
+ follows="left|top|right|bottom"
+ height="369"
+ layout="topleft"
+ left="0"
+ name="script_floater"
+ help_topic="script_floater"
+ top="0"
+ can_dock="true"
+ can_minimize="true"
+ visible="true" 
+ width="520"
+ can_resize="true"
+ min_width="350"
+ min_height="369">
+</floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 4897a4c8abc..af71ae09d20 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -5298,6 +5298,27 @@ Grant this request?
     </form>
   </notification>
 
+  <notification
+   icon="notify.tga"
+   name="ScriptToast"
+   type="notify">
+    [FIRST] [LAST]&apos;s &apos;[TITLE]&apos; is requesting user input.
+    <form name="form">
+      <button
+       index="0"
+       name="Open"
+       text="Open Dialog"/>
+      <button
+       index="1"
+       name="Ignore"
+       text="Ignore"/>
+      <button
+       index="2"
+       name="Mute"
+       text="Mute"/>
+    </form>
+  </notification>
+
   <notification
    icon="notify.tga"
    name="FirstBalanceIncrease"
@@ -5748,7 +5769,7 @@ Are you sure you want to delete your teleport history?
    name="BottomTrayButtonCanNotBeShown"
    type="alert">
 Selected button can not be shown right now.
-The button will be shown when there is enough space for it.
+The button will be shown when there is enough space for it.
   </notification>
 
 
-- 
GitLab