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.cpp304
1 files changed, 256 insertions, 48 deletions
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 30967677e8..21a0381495 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -53,6 +53,7 @@
#include "llgroupmgr.h"
#include "llnotificationmanager.h"
#include "lltransientfloatermgr.h"
+#include "llsyswellwindow.h"
static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel");
static LLDefaultChildRegistry::Register<LLIMWellChiclet> t2_0("chiclet_im_well");
@@ -65,11 +66,13 @@ 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);
-static const LLRect VOICE_INDICATOR_RECT(25, 25, 45, 0);
+static const LLRect VOICE_INDICATOR_RECT(50, 25, 70, 0);
+static const LLRect COUNTER_RECT(25, 25, 50, 0);
static const S32 OVERLAY_ICON_SHIFT = 2; // used for shifting of an overlay icon for new massages in a chiclet
// static
const S32 LLChicletPanel::s_scroll_ratio = 10;
+const S32 LLChicletNotificationCounterCtrl::MAX_DISPLAYED_COUNT = 99;
boost::signals2::signal<LLChiclet* (const LLUUID&),
@@ -88,6 +91,14 @@ class LLSysWellChiclet::FlashToLitTimer : public LLEventTimer
{
public:
typedef boost::function<void()> callback_t;
+
+ /**
+ * Constructor.
+ *
+ * @param count - how many times callback should be called (twice to not change original state)
+ * @param period - how frequently callback should be called
+ * @param cb - callback to be called each tick
+ */
FlashToLitTimer(S32 count, F32 period, callback_t cb)
: LLEventTimer(period)
, mCallback(cb)
@@ -111,8 +122,17 @@ public:
mEventTimer.start();
}
+ void stopFlashing()
+ {
+ mEventTimer.stop();
+ }
+
private:
callback_t mCallback;
+
+ /**
+ * How many times Well will blink.
+ */
S32 mFlashCount;
S32 mCurrentFlashCount;
};
@@ -134,7 +154,9 @@ LLSysWellChiclet::LLSysWellChiclet(const Params& p)
, mButton(NULL)
, mCounter(0)
, mMaxDisplayedCount(p.max_displayed_count)
+, mIsNewMessagesState(false)
, mFlashToLitTimer(NULL)
+, mContextMenu(NULL)
{
LLButton::Params button_params = p.button;
mButton = LLUICtrlFactory::create<LLButton>(button_params);
@@ -150,6 +172,7 @@ LLSysWellChiclet::~LLSysWellChiclet()
void LLSysWellChiclet::setCounter(S32 counter)
{
+ // note same code in LLChicletNotificationCounterCtrl::setCounter(S32 counter)
std::string s_count;
if(counter != 0)
{
@@ -163,20 +186,20 @@ void LLSysWellChiclet::setCounter(S32 counter)
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);
+ setNewMessagesState(counter > 0);
- if (mCounter == 0 && counter > 0)
+ // we have to flash to 'Lit' state each time new unread message is comming.
+ if (counter > mCounter)
{
mFlashToLitTimer->flash();
}
+ else if (counter == 0)
+ {
+ // if notification is resolved while well is flashing it can leave in the 'Lit' state
+ // when flashing finishes itself. Let break flashing here.
+ mFlashToLitTimer->stopFlashing();
+ }
+
mCounter = counter;
}
@@ -192,11 +215,37 @@ void LLSysWellChiclet::setToggleState(BOOL toggled) {
void LLSysWellChiclet::changeLitState()
{
- static bool set_lit = false;
+ setNewMessagesState(!mIsNewMessagesState);
+}
- mButton->setForcePressedState(set_lit);
+void LLSysWellChiclet::setNewMessagesState(bool new_messages)
+{
+ /*
+ 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(new_messages);
+
+ mIsNewMessagesState = new_messages;
+}
- set_lit ^= true;
+// virtual
+BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ if(!mContextMenu)
+ {
+ createMenu();
+ }
+ if (mContextMenu)
+ {
+ mContextMenu->show(x, y);
+ LLMenuGL::showPopup(this, mContextMenu, x, y);
+ }
+ return TRUE;
}
/************************************************************************/
@@ -209,6 +258,8 @@ LLIMWellChiclet::LLIMWellChiclet(const Params& p)
LLIMModel::instance().addNoUnreadMsgsCallback(boost::bind(&LLIMWellChiclet::messageCountChanged, this, _1));
LLIMMgr::getInstance()->addSessionObserver(this);
+
+ LLIMWellWindow::getInstance()->setSysWellChiclet(this);
}
LLIMWellChiclet::~LLIMWellChiclet()
@@ -216,10 +267,50 @@ LLIMWellChiclet::~LLIMWellChiclet()
LLIMMgr::getInstance()->removeSessionObserver(this);
}
+void LLIMWellChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string action = user_data.asString();
+ if("close all" == action)
+ {
+ LLIMWellWindow::getInstance()->closeAll();
+ }
+}
+
+bool LLIMWellChiclet::enableMenuItem(const LLSD& user_data)
+{
+ std::string item = user_data.asString();
+ if (item == "can close all")
+ {
+ return !LLIMWellWindow::getInstance()->isWindowEmpty();
+ }
+ return true;
+}
+
+void LLIMWellChiclet::createMenu()
+{
+ if(mContextMenu)
+ {
+ llwarns << "Menu already exists" << llendl;
+ return;
+ }
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("IMWellChicletMenu.Action",
+ boost::bind(&LLIMWellChiclet::onMenuItemClicked, this, _2));
+
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ enable_registrar.add("IMWellChicletMenu.EnableItem",
+ boost::bind(&LLIMWellChiclet::enableMenuItem, this, _2));
+
+ mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
+ ("menu_im_well_button.xml",
+ LLMenuGL::sMenuContainer,
+ LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)
{
- S32 total_unread = LLIMMgr::instance().getNumberOfUnreadParticipantMessages();
- setCounter(total_unread);
+ setCounter(LLBottomTray::getInstance()->getTotalUnreadIMCount());
}
/************************************************************************/
@@ -233,6 +324,10 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)
connectCounterUpdatersToSignal("notify");
connectCounterUpdatersToSignal("groupnotify");
connectCounterUpdatersToSignal("offer");
+
+ // ensure that notification well window exists, to synchronously
+ // handle toast add/delete events.
+ LLNotificationWellWindow::getInstance()->setSysWellChiclet(this);
}
void LLNotificationChiclet::connectCounterUpdatersToSignal(const std::string& notification_type)
@@ -246,6 +341,47 @@ void LLNotificationChiclet::connectCounterUpdatersToSignal(const std::string& no
}
}
+void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
+{
+ std::string action = user_data.asString();
+ if("close all" == action)
+ {
+ LLNotificationWellWindow::getInstance()->closeAll();
+ }
+}
+
+bool LLNotificationChiclet::enableMenuItem(const LLSD& user_data)
+{
+ std::string item = user_data.asString();
+ if (item == "can close all")
+ {
+ return mUreadSystemNotifications != 0;
+ }
+ return true;
+}
+
+void LLNotificationChiclet::createMenu()
+{
+ if(mContextMenu)
+ {
+ llwarns << "Menu already exists" << llendl;
+ return;
+ }
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ registrar.add("NotificationWellChicletMenu.Action",
+ boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2));
+
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ enable_registrar.add("NotificationWellChicletMenu.EnableItem",
+ boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2));
+
+ mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
+ ("menu_notification_well_button.xml",
+ LLMenuGL::sMenuContainer,
+ LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -330,7 +466,7 @@ LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)
// shift an icon a little bit to the right and up corner of a chiclet
overlay_icon_rect.translate(OVERLAY_ICON_SHIFT, OVERLAY_ICON_SHIFT);
- setShowCounter(false);
+ enableCounterControl(false);
}
void LLIMChiclet::setShowSpeaker(bool show)
@@ -343,30 +479,87 @@ void LLIMChiclet::setShowSpeaker(bool show)
onChicletSizeChanged();
}
}
+
+void LLIMChiclet::enableCounterControl(bool enable)
+{
+ mCounterEnabled = enable;
+ if(!enable)
+ {
+ LLChiclet::setShowCounter(false);
+ }
+}
+
+void LLIMChiclet::setShowCounter(bool show)
+{
+ if(!mCounterEnabled)
+ {
+ return;
+ }
+
+ bool needs_resize = getShowCounter() != show;
+ if(needs_resize)
+ {
+ LLChiclet::setShowCounter(show);
+ toggleCounterControl();
+ onChicletSizeChanged();
+ }
+}
+
void LLIMChiclet::initSpeakerControl()
{
// virtual
}
-void LLIMChiclet::toggleSpeakerControl()
+void LLIMChiclet::setRequiredWidth()
{
- LLRect speaker_rect = mSpeakerCtrl->getRect();
- S32 required_width = getRect().getWidth();
+ bool show_speaker = getShowSpeaker();
+ bool show_counter = getShowCounter();
+ S32 required_width = CHICLET_RECT.getWidth();
- if(getShowSpeaker())
+ if (show_counter)
{
- required_width = required_width + speaker_rect.getWidth();
- initSpeakerControl();
+ required_width += COUNTER_RECT.getWidth();
}
- else
+ if (show_speaker)
{
- required_width = required_width - speaker_rect.getWidth();
- }
-
+ required_width += VOICE_INDICATOR_RECT.getWidth();
+ }
+
reshape(required_width, getRect().getHeight());
+}
+
+void LLIMChiclet::toggleSpeakerControl()
+{
+ if(getShowSpeaker())
+ {
+ if(getShowCounter())
+ {
+ mSpeakerCtrl->setRect(VOICE_INDICATOR_RECT);
+ }
+ else
+ {
+ mSpeakerCtrl->setRect(COUNTER_RECT);
+ }
+ initSpeakerControl();
+ }
+
+ setRequiredWidth();
mSpeakerCtrl->setVisible(getShowSpeaker());
}
+void LLIMChiclet::setCounter(S32 counter)
+{
+ mCounterCtrl->setCounter(counter);
+ setShowCounter(counter);
+ setShowNewMessagesIcon(counter);
+}
+
+void LLIMChiclet::toggleCounterControl()
+{
+ setRequiredWidth();
+ mCounterCtrl->setVisible(getShowCounter());
+}
+
void LLIMChiclet::setShowNewMessagesIcon(bool show)
{
if(mNewMessagesIcon)
@@ -467,6 +660,7 @@ LLIMP2PChiclet::Params::Params()
unread_notifications.v_pad(5);
unread_notifications.text_color(LLColor4::white);
unread_notifications.mouse_opaque(false);
+ unread_notifications.rect(COUNTER_RECT);
unread_notifications.visible(false);
speaker.name("speaker");
@@ -505,12 +699,6 @@ LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
mSpeakerCtrl->setVisible(getShowSpeaker());
}
-void LLIMP2PChiclet::setCounter(S32 counter)
-{
- mCounterCtrl->setCounter(counter);
- setShowNewMessagesIcon(counter);
-}
-
void LLIMP2PChiclet::initSpeakerControl()
{
mSpeakerCtrl->setSpeakerId(getOtherParticipantId());
@@ -623,6 +811,7 @@ LLAdHocChiclet::Params::Params()
unread_notifications.v_pad(5);
unread_notifications.text_color(LLColor4::white);
unread_notifications.mouse_opaque(false);
+ unread_notifications.rect(COUNTER_RECT);
unread_notifications.visible(false);
@@ -697,12 +886,6 @@ void LLAdHocChiclet::switchToCurrentSpeaker()
mSpeakerCtrl->setSpeakerId(speaker_id);
}
-void LLAdHocChiclet::setCounter(S32 counter)
-{
- mCounterCtrl->setCounter(counter);
- setShowNewMessagesIcon(counter);
-}
-
void LLAdHocChiclet::createPopupMenu()
{
if(mPopupMenu)
@@ -774,6 +957,7 @@ LLIMGroupChiclet::Params::Params()
unread_notifications.font_halign(LLFontGL::HCENTER);
unread_notifications.v_pad(5);
unread_notifications.text_color(LLColor4::white);
+ unread_notifications.rect(COUNTER_RECT);
unread_notifications.visible(false);
speaker.name("speaker");
@@ -814,12 +998,6 @@ LLIMGroupChiclet::~LLIMGroupChiclet()
LLGroupMgr::getInstance()->removeObserver(this);
}
-void LLIMGroupChiclet::setCounter(S32 counter)
-{
- mCounterCtrl->setCounter(counter);
- setShowNewMessagesIcon(counter);
-}
-
void LLIMGroupChiclet::draw()
{
switchToCurrentSpeaker();
@@ -1493,14 +1671,34 @@ bool LLChicletPanel::isAnyIMFloaterDoked()
return res;
}
+S32 LLChicletPanel::getTotalUnreadIMCount()
+{
+ S32 count = 0;
+ chiclet_list_t::const_iterator it = mChicletList.begin();
+ for( ; mChicletList.end() != it; ++it)
+ {
+ LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it);
+ if(chiclet)
+ {
+ count += chiclet->getCounter();
+ }
+ }
+ return count;
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+LLChicletNotificationCounterCtrl::Params::Params()
+: max_displayed_count("max_displayed_count", MAX_DISPLAYED_COUNT)
+{
+}
LLChicletNotificationCounterCtrl::LLChicletNotificationCounterCtrl(const Params& p)
: LLTextBox(p)
, mCounter(0)
, mInitialWidth(0)
+ , mMaxDisplayedCount(p.max_displayed_count)
{
mInitialWidth = getRect().getWidth();
}
@@ -1509,11 +1707,21 @@ void LLChicletNotificationCounterCtrl::setCounter(S32 counter)
{
mCounter = counter;
- std::stringstream stream;
- stream << getCounter();
+ // note same code in LLSysWellChiclet::setCounter(S32 counter)
+ std::string s_count;
+ if(counter != 0)
+ {
+ 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()
+ );
+ }
+
if(mCounter != 0)
{
- setText(stream.str());
+ setText(s_count);
}
else
{