summaryrefslogtreecommitdiff
path: root/indra/newview/llscreenchannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llscreenchannel.cpp')
-rw-r--r--indra/newview/llscreenchannel.cpp554
1 files changed, 554 insertions, 0 deletions
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
new file mode 100644
index 0000000000..1fbe359295
--- /dev/null
+++ b/indra/newview/llscreenchannel.cpp
@@ -0,0 +1,554 @@
+/**
+ * @file llscreenchannel.cpp
+ * @brief Class implements a channel on a screen in which appropriate toasts may appear.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-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" // must be first include
+
+#include "lliconctrl.h"
+#include "lltextbox.h"
+#include "llscreenchannel.h"
+
+#include "lltoastpanel.h"
+#include "llviewercontrol.h"
+#include "llfloaterreg.h"
+#include "lltrans.h"
+
+#include <algorithm>
+
+using namespace LLNotificationsUI;
+
+bool LLScreenChannel::mWasStartUpToastShown = false;
+
+//--------------------------------------------------------------------------
+LLScreenChannel::LLScreenChannel(LLUUID& id): mOverflowToastPanel(NULL), mStartUpToastPanel(NULL),
+ mToastAlignment(NA_BOTTOM), mCanStoreToasts(true),
+ mHiddenToastsNum(0), mOverflowToastHidden(false),
+ mIsHovering(false), mControlHovering(false),
+ mShowToasts(false)
+{
+ mID = id;
+
+ setFollows(FOLLOWS_RIGHT | FOLLOWS_BOTTOM | FOLLOWS_TOP);
+
+ mOverflowFormatString = LLTrans::getString("OverflowInfoChannelString");
+
+ setMouseOpaque( false );
+}
+
+void LLScreenChannel::init(S32 channel_left, S32 channel_right)
+{
+ S32 channel_top = getRootView()->getRect().getHeight() - gSavedSettings.getS32("NavBarMargin");
+ S32 channel_bottom = getRootView()->getRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
+ setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom));
+
+}
+
+//--------------------------------------------------------------------------
+LLScreenChannel::~LLScreenChannel()
+{
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLUICtrl::reshape(width, height, called_from_parent);
+ if(mToastAlignment != NA_CENTRE)
+ showToasts();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::addToast(LLToast::Params p)
+{
+ bool store_toast = false, show_toast = false;
+
+ show_toast = mShowToasts || p.force_show;
+ store_toast = !show_toast && p.can_be_stored && mCanStoreToasts;
+
+ if(!show_toast && !store_toast)
+ {
+ mOnRejectToast(p);
+ return;
+ }
+
+ ToastElem new_toast_elem(p);
+
+ mOverflowToastHidden = false;
+
+ new_toast_elem.toast->setOnFadeCallback(boost::bind(&LLScreenChannel::onToastFade, this, new_toast_elem.toast));
+ if(mControlHovering)
+ {
+ new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2));
+ }
+
+ if(show_toast)
+ {
+ mToastList.push_back(new_toast_elem);
+ showToasts();
+ }
+ else // store_toast
+ {
+ mHiddenToastsNum++;
+ storeToast(new_toast_elem);
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::onToastFade(LLToast* toast)
+{
+ std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast));
+
+ bool destroy_toast = !mCanStoreToasts || !toast->getCanBeStored();
+ if(destroy_toast)
+ {
+ mToastList.erase(it);
+ toast->mOnToastDestroy(toast);
+ }
+ else
+ {
+ storeToast((*it));
+ mToastList.erase(it);
+ }
+
+ showToasts();
+}
+
+//--------------------------------------------------------------------------
+
+void LLScreenChannel::storeToast(ToastElem& toast_elem)
+{
+ // do not store clones
+ std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), toast_elem.id);
+ if( it != mStoredToastList.end() )
+ return;
+
+ toast_elem.toast->stopTimer();
+ mStoredToastList.push_back(toast_elem);
+ mOnStoreToast(toast_elem.toast->getPanel(), toast_elem.id);
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::loadStoredToastsToChannel()
+{
+ std::vector<ToastElem>::iterator it;
+
+ if(mStoredToastList.size() == 0)
+ return;
+
+ mOverflowToastHidden = false;
+
+ for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)
+ {
+ (*it).toast->resetTimer();
+ mToastList.push_back((*it));
+ }
+
+ mStoredToastList.clear();
+ showToasts();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::loadStoredToastByIDToChannel(LLUUID id)
+{
+ std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
+
+ if( it == mStoredToastList.end() )
+ return;
+
+ mOverflowToastHidden = false;
+
+ LLToast* toast = (*it).toast;
+ toast->resetTimer();
+ mToastList.push_back((*it));
+ mStoredToastList.erase(it);
+
+ showToasts();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::removeStoredToastByID(LLUUID id)
+{
+ // *TODO: may be remove this function
+ std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
+
+ if( it == mStoredToastList.end() )
+ return;
+
+ LLToast* toast = (*it).toast;
+ mStoredToastList.erase(it);
+ toast->discardNotification();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::killToastByNotificationID(LLUUID id)
+{
+ // searching among toasts on a screen
+ std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id);
+
+ if( it != mToastList.end())
+ {
+ LLToast* toast = (*it).toast;
+ // if it is a notification toast and notification is UnResponded - then respond on it
+ // else - simply destroy a toast
+ //
+ // NOTE: if a notification is unresponded this function will be called twice for the same toast.
+ // At first, the notification will be discarded, at second (it will be caused by discarding),
+ // the toast will be destroyed.
+ if(toast->getIsNotificationUnResponded())
+ {
+ toast->discardNotification();
+ }
+ else
+ {
+ mToastList.erase(it);
+ toast->mOnToastDestroy(toast);
+ showToasts();
+ }
+ return;
+ }
+
+ // searching among stored toasts
+ it = find(mStoredToastList.begin(), mStoredToastList.end(), id);
+
+ if( it != mStoredToastList.end() )
+ {
+ LLToast* toast = (*it).toast;
+ mStoredToastList.erase(it);
+ toast->discardNotification();
+ toast->mOnToastDestroy(toast);
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
+{
+ std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id);
+
+ if( it != mToastList.end() && panel)
+ {
+ LLToast* toast = (*it).toast;
+ LLPanel* old_panel = toast->getPanel();
+ toast->removeChild(old_panel);
+ delete old_panel;
+ toast->insertPanel(panel);
+ toast->resetTimer();
+ showToasts();
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::showToasts()
+{
+ if(mToastList.size() == 0 || mIsHovering)
+ return;
+
+ hideToastsFromScreen();
+
+ switch(mToastAlignment)
+ {
+ case NA_TOP :
+ showToastsTop();
+ break;
+
+ case NA_CENTRE :
+ showToastsCentre();
+ break;
+
+ case NA_BOTTOM :
+ showToastsBottom();
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::showToastsBottom()
+{
+ LLRect toast_rect;
+ S32 bottom = getRect().mBottom;
+ std::vector<ToastElem>::reverse_iterator it;
+
+ for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
+ {
+ if(it != mToastList.rbegin())
+ {
+ bottom = (*(it-1)).toast->getRect().mTop;
+ }
+
+ toast_rect = (*it).toast->getRect();
+ toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight());
+ (*it).toast->setRect(toast_rect);
+
+ bool stop_showing_toasts = (*it).toast->getRect().mTop > getRect().getHeight();
+
+ if(!stop_showing_toasts)
+ {
+ if( it != mToastList.rend()-1)
+ {
+ stop_showing_toasts = ((*it).toast->getRect().mTop + gSavedSettings.getS32("OverflowToastHeight") + gSavedSettings.getS32("ToastMargin")) > getRect().getHeight();
+ }
+ }
+
+ if(stop_showing_toasts)
+ break;
+
+ (*it).toast->setVisible(TRUE);
+ }
+
+ if(it != mToastList.rend() && !mOverflowToastHidden)
+ {
+ mHiddenToastsNum = 0;
+ for(; it != mToastList.rend(); it++)
+ {
+ mHiddenToastsNum++;
+ }
+ createOverflowToast(bottom, gSavedSettings.getS32("NotificationToastTime"));
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::showToastsCentre()
+{
+ LLRect toast_rect;
+ S32 bottom = (getRect().mTop - getRect().mBottom)/2 + mToastList[0].toast->getRect().getHeight()/2;
+ std::vector<ToastElem>::reverse_iterator it;
+
+ for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
+ {
+ toast_rect = (*it).toast->getRect();
+ toast_rect.setLeftTopAndSize(getRect().mLeft - toast_rect.getWidth() / 2, bottom + toast_rect.getHeight() / 2 + gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight());
+ (*it).toast->setRect(toast_rect);
+
+ (*it).toast->setVisible(TRUE);
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::showToastsTop()
+{
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::createOverflowToast(S32 bottom, F32 timer)
+{
+ LLRect toast_rect;
+ LLToast::Params p;
+ p.timer_period = timer;
+ mOverflowToastPanel = new LLToast(p);
+
+ if(!mOverflowToastPanel)
+ return;
+
+ mOverflowToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onOverflowToastHide, this));
+
+ LLTextBox* text_box = mOverflowToastPanel->getChild<LLTextBox>("toast_text");
+ LLIconCtrl* icon = mOverflowToastPanel->getChild<LLIconCtrl>("icon");
+ std::string text = llformat(mOverflowFormatString.c_str(),mHiddenToastsNum);
+ if(mHiddenToastsNum == 1)
+ {
+ text += ".";
+ }
+ else
+ {
+ text += "s.";
+ }
+
+ toast_rect = mOverflowToastPanel->getRect();
+ mOverflowToastPanel->reshape(getRect().getWidth(), toast_rect.getHeight(), true);
+ toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), getRect().getWidth(), toast_rect.getHeight());
+ mOverflowToastPanel->setRect(toast_rect);
+
+ text_box->setValue(text);
+ text_box->setVisible(TRUE);
+ icon->setVisible(TRUE);
+
+ mOverflowToastPanel->setVisible(TRUE);
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::onOverflowToastHide()
+{
+ mOverflowToastHidden = true;
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::closeOverflowToastPanel()
+{
+ if(mOverflowToastPanel != NULL)
+ {
+ mOverflowToastPanel->closeFloater();
+ mOverflowToastPanel = NULL;
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::createStartUpToast(S32 notif_num, S32 bottom, F32 timer)
+{
+ LLRect toast_rect;
+ LLToast::Params p;
+ p.timer_period = timer;
+ mStartUpToastPanel = new LLToast(p);
+
+ if(!mStartUpToastPanel)
+ return;
+
+ mStartUpToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onStartUpToastHide, this));
+
+ LLTextBox* text_box = mStartUpToastPanel->getChild<LLTextBox>("toast_text");
+ LLIconCtrl* icon = mStartUpToastPanel->getChild<LLIconCtrl>("icon");
+
+ std::string mStartUpFormatString;
+
+ if(notif_num == 1)
+ {
+ mStartUpFormatString = LLTrans::getString("StartUpNotification");
+ }
+ else
+ {
+ mStartUpFormatString = LLTrans::getString("StartUpNotifications");
+ }
+
+
+ std::string text = llformat(mStartUpFormatString.c_str(), notif_num);
+
+ toast_rect = mStartUpToastPanel->getRect();
+ mStartUpToastPanel->reshape(getRect().getWidth(), toast_rect.getHeight(), true);
+ toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), getRect().getWidth(), toast_rect.getHeight());
+ mStartUpToastPanel->setRect(toast_rect);
+
+ text_box->setValue(text);
+ text_box->setVisible(TRUE);
+ icon->setVisible(TRUE);
+
+ mStartUpToastPanel->setVisible(TRUE);
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::updateStartUpString(S32 num)
+{
+ // *TODO: update string if notifications are arriving while the StartUp toast is on a screen
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::onStartUpToastHide()
+{
+ onCommit();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::closeStartUpToast()
+{
+ if(mStartUpToastPanel != NULL)
+ {
+ mStartUpToastPanel->closeFloater();
+ mStartUpToastPanel = NULL;
+ }
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::hideToastsFromScreen()
+{
+ closeOverflowToastPanel();
+ for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
+ (*it).toast->setVisible(FALSE);
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::removeToastsFromChannel()
+{
+ hideToastsFromScreen();
+ for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
+ {
+ // *TODO: ivestigate mOnToastDestroy callback - change name or/and place
+ (*it).toast->mOnToastDestroy((*it).toast);
+ }
+ mToastList.clear();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::removeAndStoreAllVisibleToasts()
+{
+ if(mToastList.size() == 0)
+ return;
+
+ hideToastsFromScreen();
+ for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
+ {
+ if((*it).toast->getCanBeStored())
+ {
+ mStoredToastList.push_back(*it);
+ mOnStoreToast((*it).toast->getPanel(), (*it).id);
+ (*it).toast->stopTimer();
+ }
+ (*it).toast->setVisible(FALSE);
+ }
+
+ mToastList.clear();
+}
+
+//--------------------------------------------------------------------------
+void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)
+{
+ // because of LLViewerWindow::updateUI() that ALWAYS calls onMouseEnter BEFORE onMouseLeave
+ // we must check this to prevent incorrect setting for hovering in a channel
+ std::map<LLToast*, bool>::iterator it_first, it_second;
+ S32 stack_size = mToastEventStack.size();
+ mIsHovering = mouse_enter;
+
+ switch(stack_size)
+ {
+ case 0:
+ mToastEventStack.insert(std::pair<LLToast*, bool>(toast, mouse_enter));
+ break;
+ case 1:
+ it_first = mToastEventStack.begin();
+ if((*it_first).second && !mouse_enter && ((*it_first).first != toast) )
+ {
+ mToastEventStack.clear();
+ mIsHovering = true;
+ }
+ else
+ {
+ mToastEventStack.clear();
+ mToastEventStack.insert(std::pair<LLToast*, bool>(toast, mouse_enter));
+ }
+ break;
+ default:
+ LL_ERRS ("LLScreenChannel::onToastHover: stack size error " ) << stack_size << llendl;
+ }
+
+ if(!mIsHovering)
+ showToasts();
+}
+
+//--------------------------------------------------------------------------
+
+
+
+