summaryrefslogtreecommitdiff
path: root/indra/newview/llchiclet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llchiclet.cpp')
-rw-r--r--indra/newview/llchiclet.cpp325
1 files changed, 289 insertions, 36 deletions
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 90f246ddaf..30967677e8 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -32,6 +32,7 @@
#include "llviewerprecompiledheaders.h" // must be first include
#include "llchiclet.h"
+
#include "llagent.h"
#include "llavataractions.h"
#include "llbottomtray.h"
@@ -42,6 +43,8 @@
#include "llfloaterreg.h"
#include "lllocalcliprect.h"
#include "llmenugl.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
#include "lloutputmonitorctrl.h"
#include "llscriptfloater.h"
#include "lltextbox.h"
@@ -52,11 +55,13 @@
#include "lltransientfloatermgr.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
+static LLDefaultChildRegistry::Register<LLIMWellChiclet> t2_0("chiclet_im_well");
static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification");
static LLDefaultChildRegistry::Register<LLIMP2PChiclet> t3("chiclet_im_p2p");
static LLDefaultChildRegistry::Register<LLIMGroupChiclet> t4("chiclet_im_group");
static LLDefaultChildRegistry::Register<LLAdHocChiclet> t5("chiclet_im_adhoc");
static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");
+static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer");
static const LLRect CHICLET_RECT(0, 25, 25, 0);
static const LLRect CHICLET_ICON_RECT(0, 22, 22, 0);
@@ -66,7 +71,6 @@ static const S32 OVERLAY_ICON_SHIFT = 2; // used for shifting of an overlay icon
// static
const S32 LLChicletPanel::s_scroll_ratio = 10;
-S32 LLNotificationChiclet::mUreadSystemNotifications = 0;
boost::signals2::signal<LLChiclet* (const LLUUID&),
LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > >
@@ -75,70 +79,173 @@ boost::signals2::signal<LLChiclet* (const LLUUID&),
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-LLNotificationChiclet::Params::Params()
+/**
+ * Updates the Well's 'Lit' state to flash it when "new messages" are come.
+ *
+ * It gets callback which will be called 2*N times with passed period. See EXT-3147
+ */
+class LLSysWellChiclet::FlashToLitTimer : public LLEventTimer
+{
+public:
+ typedef boost::function<void()> callback_t;
+ FlashToLitTimer(S32 count, F32 period, callback_t cb)
+ : LLEventTimer(period)
+ , mCallback(cb)
+ , mFlashCount(2 * count)
+ , mCurrentFlashCount(0)
+ {
+ mEventTimer.stop();
+ }
+
+ BOOL tick()
+ {
+ mCallback();
+
+ if (++mCurrentFlashCount == mFlashCount) mEventTimer.stop();
+ return FALSE;
+ }
+
+ void flash()
+ {
+ mCurrentFlashCount = 0;
+ mEventTimer.start();
+ }
+
+private:
+ callback_t mCallback;
+ S32 mFlashCount;
+ S32 mCurrentFlashCount;
+};
+
+LLSysWellChiclet::Params::Params()
: button("button")
, unread_notifications("unread_notifications")
+, max_displayed_count("max_displayed_count", 9)
+, flash_to_lit_count("flash_to_lit_count", 3)
+, flash_period("flash_period", 0.5F)
{
button.name("button");
button.tab_stop(FALSE);
button.label(LLStringUtil::null);
-
}
-LLNotificationChiclet::LLNotificationChiclet(const Params& p)
+LLSysWellChiclet::LLSysWellChiclet(const Params& p)
: LLChiclet(p)
, mButton(NULL)
, mCounter(0)
+, mMaxDisplayedCount(p.max_displayed_count)
+, mFlashToLitTimer(NULL)
{
LLButton::Params button_params = p.button;
mButton = LLUICtrlFactory::create<LLButton>(button_params);
addChild(mButton);
- // connect counter handlers to the signals
- connectCounterUpdatersToSignal("notify");
- connectCounterUpdatersToSignal("groupnotify");
- connectCounterUpdatersToSignal("offer");
+ mFlashToLitTimer = new FlashToLitTimer(p.flash_to_lit_count, p.flash_period, boost::bind(&LLSysWellChiclet::changeLitState, this));
}
-LLNotificationChiclet::~LLNotificationChiclet()
+LLSysWellChiclet::~LLSysWellChiclet()
{
-
+ delete mFlashToLitTimer;
}
-void LLNotificationChiclet::connectCounterUpdatersToSignal(std::string notification_type)
-{
- LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
- LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
- if(n_handler)
- {
- n_handler->setNewNotificationCallback(boost::bind(&LLNotificationChiclet::incUreadSystemNotifications, this));
- n_handler->setDelNotification(boost::bind(&LLNotificationChiclet::decUreadSystemNotifications, this));
- }
-}
-
-void LLNotificationChiclet::setCounter(S32 counter)
+void LLSysWellChiclet::setCounter(S32 counter)
{
std::string s_count;
if(counter != 0)
{
- s_count = llformat("%d", counter);
+ static std::string more_messages_exist("+");
+ std::string more_messages(counter > mMaxDisplayedCount ? more_messages_exist : "");
+ s_count = llformat("%d%s"
+ , llmin(counter, mMaxDisplayedCount)
+ , more_messages.c_str()
+ );
}
mButton->setLabel(s_count);
+ /*
+ Emulate 4 states of button by background images, see detains in EXT-3147
+ xml attribute Description
+ image_unselected "Unlit" - there are no new messages
+ image_selected "Unlit" + "Selected" - there are no new messages and the Well is open
+ image_pressed "Lit" - there are new messages
+ image_pressed_selected "Lit" + "Selected" - there are new messages and the Well is open
+ */
+ mButton->setForcePressedState(counter > 0);
+
+ if (mCounter == 0 && counter > 0)
+ {
+ mFlashToLitTimer->flash();
+ }
mCounter = counter;
}
-boost::signals2::connection LLNotificationChiclet::setClickCallback(
+boost::signals2::connection LLSysWellChiclet::setClickCallback(
const commit_callback_t& cb)
{
return mButton->setClickedCallback(cb);
}
-void LLNotificationChiclet::setToggleState(BOOL toggled) {
+void LLSysWellChiclet::setToggleState(BOOL toggled) {
mButton->setToggleState(toggled);
}
+void LLSysWellChiclet::changeLitState()
+{
+ static bool set_lit = false;
+
+ mButton->setForcePressedState(set_lit);
+
+ set_lit ^= true;
+}
+
+/************************************************************************/
+/* LLIMWellChiclet implementation */
+/************************************************************************/
+LLIMWellChiclet::LLIMWellChiclet(const Params& p)
+: LLSysWellChiclet(p)
+{
+ LLIMModel::instance().addNewMsgCallback(boost::bind(&LLIMWellChiclet::messageCountChanged, this, _1));
+ LLIMModel::instance().addNoUnreadMsgsCallback(boost::bind(&LLIMWellChiclet::messageCountChanged, this, _1));
+
+ LLIMMgr::getInstance()->addSessionObserver(this);
+}
+
+LLIMWellChiclet::~LLIMWellChiclet()
+{
+ LLIMMgr::getInstance()->removeSessionObserver(this);
+}
+
+void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)
+{
+ S32 total_unread = LLIMMgr::instance().getNumberOfUnreadParticipantMessages();
+ setCounter(total_unread);
+}
+
+/************************************************************************/
+/* LLNotificationChiclet implementation */
+/************************************************************************/
+LLNotificationChiclet::LLNotificationChiclet(const Params& p)
+: LLSysWellChiclet(p)
+, mUreadSystemNotifications(0)
+{
+ // connect counter handlers to the signals
+ connectCounterUpdatersToSignal("notify");
+ connectCounterUpdatersToSignal("groupnotify");
+ connectCounterUpdatersToSignal("offer");
+}
+
+void LLNotificationChiclet::connectCounterUpdatersToSignal(const std::string& notification_type)
+{
+ LLNotificationsUI::LLNotificationManager* manager = LLNotificationsUI::LLNotificationManager::getInstance();
+ LLNotificationsUI::LLEventHandler* n_handler = manager->getHandlerForNotification(notification_type);
+ if(n_handler)
+ {
+ n_handler->setNewNotificationCallback(boost::bind(&LLNotificationChiclet::incUreadSystemNotifications, this));
+ n_handler->setDelNotification(boost::bind(&LLNotificationChiclet::decUreadSystemNotifications, this));
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -392,6 +499,10 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
sendChildToFront(mNewMessagesIcon);
setShowSpeaker(p.show_speaker);
+
+ //since mShowSpeaker initialized with false
+ //setShowSpeaker(false) will not hide mSpeakerCtrl
+ mSpeakerCtrl->setVisible(getShowSpeaker());
}
void LLIMP2PChiclet::setCounter(S32 counter)
@@ -592,8 +703,49 @@ void LLAdHocChiclet::setCounter(S32 counter)
setShowNewMessagesIcon(counter);
}
+void LLAdHocChiclet::createPopupMenu()
+{
+ if(mPopupMenu)
+ {
+ llwarns << "Menu already exists" << llendl;
+ return;
+ }
+ if(getSessionId().isNull())
+ {
+ return;
+ }
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("IMChicletMenu.Action", boost::bind(&LLAdHocChiclet::onMenuItemClicked, this, _2));
+
+ mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
+ ("menu_imchiclet_adhoc.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
+void LLAdHocChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string level = user_data.asString();
+ LLUUID group_id = getSessionId();
+
+ if("end" == level)
+ {
+ LLGroupActions::endIM(group_id);
+ }
+}
+
BOOL LLAdHocChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
+ if(!mPopupMenu)
+ {
+ createPopupMenu();
+ }
+
+ if (mPopupMenu)
+ {
+ mPopupMenu->arrangeAndClear();
+ LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ }
+
return TRUE;
}
@@ -836,16 +988,7 @@ LLChicletPanel::~LLChicletPanel()
void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
LLUUID session_id = data["session_id"].asUUID();
- LLUUID from_id = data["from_id"].asUUID();
- const std::string from = data["from"].asString();
- S32 unread = data["num_unread"].asInteger();
-
- // if new message came
- if(unread != 0)
- {
- //we do not show balloon (indicator of new messages) for system messages and our own messages
- if (from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) return;
- }
+ S32 unread = data["participant_unread"].asInteger();
LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
if (im_floater && im_floater->getVisible())
@@ -868,12 +1011,34 @@ void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
}
}
+void object_chiclet_callback(const LLSD& data)
+{
+ LLUUID object_id = data["object_id"];
+ bool new_message = data["new_message"];
+
+ std::list<LLChiclet*> chiclets = LLIMChiclet::sFindChicletsSignal(object_id);
+ std::list<LLChiclet *>::iterator iter;
+ for (iter = chiclets.begin(); iter != chiclets.end(); iter++)
+ {
+ LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*iter);
+ if (chiclet != NULL)
+ {
+ if(data.has("unread"))
+ {
+ chiclet->setCounter(data["unread"]);
+ }
+ chiclet->setShowNewMessagesIcon(new_message);
+ }
+ }
+}
BOOL LLChicletPanel::postBuild()
{
LLPanel::postBuild();
LLIMModel::instance().addNewMsgCallback(boost::bind(im_chiclet_callback, this, _1));
LLIMModel::instance().addNoUnreadMsgsCallback(boost::bind(im_chiclet_callback, this, _1));
+ LLScriptFloaterManager::getInstance()->addNewObjectCallback(boost::bind(object_chiclet_callback, _1));
+ LLScriptFloaterManager::getInstance()->addToggleObjectFloaterCallback(boost::bind(object_chiclet_callback, _1));
LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLChicletPanel::findChiclet<LLChiclet>, this, _1));
LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLChicletPanel::onCurrentVoiceChannelChanged, this, _1));
@@ -1359,7 +1524,7 @@ void LLChicletNotificationCounterCtrl::setCounter(S32 counter)
LLRect LLChicletNotificationCounterCtrl::getRequiredRect()
{
LLRect rc;
- S32 text_width = getContentsRect().getWidth();
+ S32 text_width = getTextPixelWidth();
rc.mRight = rc.mLeft + llmax(text_width, mInitialWidth);
@@ -1412,6 +1577,28 @@ void LLChicletGroupIconCtrl::setValue(const LLSD& value )
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+LLChicletInvOfferIconCtrl::LLChicletInvOfferIconCtrl(const Params& p)
+: LLChicletAvatarIconCtrl(p)
+ , mDefaultIcon(p.default_icon)
+{
+}
+
+void LLChicletInvOfferIconCtrl::setValue(const LLSD& value )
+{
+ if(value.asUUID().isNull())
+ {
+ LLIconCtrl::setValue(mDefaultIcon);
+ }
+ else
+ {
+ LLChicletAvatarIconCtrl::setValue(value);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p)
: LLOutputMonitorCtrl(p)
{
@@ -1452,6 +1639,11 @@ void LLScriptChiclet::setSessionId(const LLUUID& session_id)
}
}
+void LLScriptChiclet::setCounter(S32 counter)
+{
+ setShowNewMessagesIcon( counter > 0 );
+}
+
void LLScriptChiclet::onMouseDown()
{
LLScriptFloaterManager::getInstance()->toggleScriptFloater(getSessionId());
@@ -1463,4 +1655,65 @@ BOOL LLScriptChiclet::handleMouseDown(S32 x, S32 y, MASK mask)
return LLChiclet::handleMouseDown(x, y, mask);
}
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+static const std::string INVENTORY_USER_OFFER ("UserGiveItem");
+
+LLInvOfferChiclet::Params::Params()
+{
+ // *TODO Vadim: Get rid of hardcoded values.
+ rect(CHICLET_RECT);
+ icon.rect(CHICLET_ICON_RECT);
+}
+
+LLInvOfferChiclet::LLInvOfferChiclet(const Params&p)
+ : LLIMChiclet(p)
+ , mChicletIconCtrl(NULL)
+{
+ LLChicletInvOfferIconCtrl::Params icon_params = p.icon;
+ mChicletIconCtrl = LLUICtrlFactory::create<LLChicletInvOfferIconCtrl>(icon_params);
+ // Let "new message" icon be on top, else it will be hidden behind chiclet icon.
+ addChildInBack(mChicletIconCtrl);
+}
+
+void LLInvOfferChiclet::setSessionId(const LLUUID& session_id)
+{
+ setShowNewMessagesIcon( getSessionId() != session_id );
+
+ LLIMChiclet::setSessionId(session_id);
+ LLUUID notification_id = LLScriptFloaterManager::getInstance()->findNotificationId(session_id);
+ LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id);
+ if(notification)
+ {
+ setToolTip(notification->getSubstitutions()["TITLE"].asString());
+ }
+
+ if ( notification && notification->getName() == INVENTORY_USER_OFFER )
+ {
+ mChicletIconCtrl->setValue(notification->getPayload()["from_id"]);
+ }
+ else
+ {
+ mChicletIconCtrl->setValue(LLUUID::null);
+ }
+}
+
+void LLInvOfferChiclet::setCounter(S32 counter)
+{
+ setShowNewMessagesIcon( counter > 0 );
+}
+
+void LLInvOfferChiclet::onMouseDown()
+{
+ LLScriptFloaterManager::instance().toggleScriptFloater(getSessionId());
+}
+
+BOOL LLInvOfferChiclet::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ onMouseDown();
+ return LLChiclet::handleMouseDown(x, y, mask);
+}
+
// EOF