diff options
Diffstat (limited to 'indra')
48 files changed, 5326 insertions, 133 deletions
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 5a609a2e40..b1d33f48e9 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -333,12 +333,13 @@ protected: open_signal_t mOpenSignal; close_signal_t mCloseSignal; LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg - -private: - LLRect mExpandedRect; + LLDragHandle* mDragHandle; LLResizeBar* mResizeBar[4]; LLResizeHandle* mResizeHandle[4]; + +private: + LLRect mExpandedRect; LLUIString mTitle; LLUIString mShortTitle; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ac3163a1bd..5dec4a8688 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -64,7 +64,7 @@ include_directories( set(viewer_SOURCE_FILES llaccordionctrltab.cpp - llaccordionpanel.cpp + llaccordionctrl.cpp llagent.cpp llagentaccess.cpp llagentdata.cpp @@ -88,7 +88,9 @@ set(viewer_SOURCE_FILES llcallingcard.cpp llcapabilitylistener.cpp llcaphttpsender.cpp - llchathistoryscroll.cpp + llchannelmanager.cpp + llchatitemscontainerctrl.cpp + llchatmsgbox.cpp llchiclet.cpp llclassifiedinfo.cpp llclassifiedstatsresponder.cpp @@ -104,7 +106,6 @@ set(viewer_SOURCE_FILES lldebugview.cpp lldelayedgestureerror.cpp lldirpicker.cpp - lldraggerbar.cpp lldrawable.cpp lldrawpoolalpha.cpp lldrawpoolavatar.cpp @@ -266,8 +267,13 @@ set(viewer_SOURCE_FILES llnameeditor.cpp llnamelistctrl.cpp llnavigationbar.cpp - llnearbychathistory.cpp + llnearbychat.cpp + llnearbychathandler.cpp llnetmap.cpp + llnotificationalerthandler.cpp + llnotificationgrouphandler.cpp + llnotificationinfohandler.cpp + llnotificationmanager.cpp llnotify.cpp lloutputmonitorctrl.cpp lloverlaybar.cpp @@ -329,6 +335,7 @@ set(viewer_SOURCE_FILES llregionposition.cpp llremoteparcelrequest.cpp llsavedsettingsglue.cpp + llscreenchannel.cpp llselectmgr.cpp llsidetray.cpp llsky.cpp @@ -349,6 +356,11 @@ set(viewer_SOURCE_FILES lltexturectrl.cpp lltexturefetch.cpp lltextureview.cpp + lltoast.cpp + lltoastalertpanel.cpp + lltoastgroupnotifypanel.cpp + lltoastnotifypanel.cpp + lltoastpanel.cpp lltoggleablemenu.cpp lltoolbar.cpp lltoolbrush.cpp @@ -484,7 +496,7 @@ set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake llaccordionctrltab.h - llaccordionpanel.h + llaccordionctrl.h llagent.h llagentaccess.h llagentdata.h @@ -510,7 +522,9 @@ set(viewer_HEADER_FILES llcapabilitylistener.h llcapabilityprovider.h llcaphttpsender.h - llchathistoryscroll.h + llchannelmanager.h + llchatitemscontainerctrl.h + llchatmsgbox.h llchiclet.h llclassifiedinfo.h llclassifiedstatsresponder.h @@ -526,7 +540,6 @@ set(viewer_HEADER_FILES lldebugview.h lldelayedgestureerror.h lldirpicker.h - lldraggerbar.h lldrawable.h lldrawpool.h lldrawpoolalpha.h @@ -690,8 +703,11 @@ set(viewer_HEADER_FILES llnameeditor.h llnamelistctrl.h llnavigationbar.h - llnearbychathistory.h + llnearbychat.h + llnearbychathandler.h llnetmap.h + llnotificationhandler.h + llnotificationmanager.h llnotify.h lloutputmonitorctrl.h lloverlaybar.h @@ -754,6 +770,7 @@ set(viewer_HEADER_FILES llremoteparcelrequest.h llresourcedata.h llrootview.h + llscreenchannel.h llsavedsettingsglue.h llselectmgr.h llsidetray.h @@ -776,6 +793,11 @@ set(viewer_HEADER_FILES lltexturectrl.h lltexturefetch.h lltextureview.h + lltoast.h + lltoastalertpanel.h + lltoastgroupnotifypanel.h + lltoastnotifypanel.h + lltoastpanel.h lltoggleablemenu.h lltool.h lltoolbar.h diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index e37b660951..d84dd09812 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -47,7 +47,7 @@ #include "llselectmgr.h" #include "llvoavatarself.h" -S32 LLBottomTray::mLastSpecialChatChannel = 0; +S32 LLBottomTray::sLastSpecialChatChannel = 0; // legacy calllback glue void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); @@ -412,16 +412,6 @@ void LLBottomTray::refreshStandUp() moveChildToBackOfTabGroup(mStandUpBtn); } } -void LLBottomTray::updateRightPosition(const S32 new_right_position) -{ - LLRect rc = getRect(); - if (new_right_position != rc.mRight) - { - rc.mRight = new_right_position; - reshape(rc.getWidth(), rc.getHeight(), FALSE); - setRect(rc); - } -} //FIXME: temporary, for stand up proto void LLBottomTray::onCommitStandUp(LLUICtrl* ctrl) @@ -624,7 +614,7 @@ LLWString LLBottomTray::stripChannelNumber(const LLWString &mesg, S32* channel) && mesg[1] == '/') { // This is a "repeat channel send" - *channel = mLastSpecialChatChannel; + *channel = sLastSpecialChatChannel; return mesg.substr(2, mesg.length() - 2); } else if (mesg[0] == '/' @@ -654,8 +644,8 @@ LLWString LLBottomTray::stripChannelNumber(const LLWString &mesg, S32* channel) pos++; } - mLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10); - *channel = mLastSpecialChatChannel; + sLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10); + *channel = sLastSpecialChatChannel; return mesg.substr(pos, mesg.length() - pos); } else diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 1d4e271f80..330afeb647 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -89,7 +89,6 @@ public: /*virtual*/void draw(); void refreshStandUp(); - void updateRightPosition(const S32 new_right_position); void onCommitGesture(LLUICtrl* ctrl); void onCommitStandUp(LLUICtrl* ctrl); @@ -118,7 +117,7 @@ protected: void setChicletPanelVisible(bool visible); // Which non-zero channel did we last chat on? - static S32 mLastSpecialChatChannel; + static S32 sLastSpecialChatChannel; LLLineEditor* mChatBox; LLChicletPanel* mChicletPanel; diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp new file mode 100644 index 0000000000..723bf2a248 --- /dev/null +++ b/indra/newview/llchannelmanager.cpp @@ -0,0 +1,133 @@ +/** + * @file llchannelmanager.cpp + * @brief This class rules screen notification channels. + * + * $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 "llchannelmanager.h" + +#include <algorithm> + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLChannelManager::LLChannelManager() +{ +} + +//-------------------------------------------------------------------------- +LLChannelManager::~LLChannelManager() +{ + //All channels are being deleted by Parent View +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::createChannel(LLChannelManager::Params& p) +{ + LLScreenChannel* new_channel = NULL; + + if(!p.chiclet) + { + new_channel = getChannelByID(p.id); + } + else + { + new_channel = getChannelByChiclet(p.chiclet); + } + + if(new_channel) + return new_channel; + + new_channel = new LLScreenChannel(); + new_channel->init(p.channel_right_bound - p.channel_width, getRootView()); + new_channel->setToastAlignment(p.align); + + ChannelElem new_elem; + new_elem.id = p.id; + new_elem.chiclet = p.chiclet; + new_elem.channel = new_channel; + + mChannelList.push_back(new_elem); //TODO: remove chiclet from ScreenChannel? + + return new_channel; +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::getChannelByID(const LLUUID id) +{ + std::vector<ChannelElem>::iterator it = find(mChannelList.begin(), mChannelList.end(), id); + if(it != mChannelList.end()) + { + return (*it).channel; + } + + return NULL; +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::getChannelByChiclet(const LLChiclet* chiclet) +{ + std::vector<ChannelElem>::iterator it = find(mChannelList.begin(), mChannelList.end(), chiclet); + if(it != mChannelList.end()) + { + return (*it).channel; + } + + return NULL; +} + +//-------------------------------------------------------------------------- +void LLChannelManager::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + for(std::vector<ChannelElem>::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) + { + if((*it).channel->getToastAlignment() == NA_CENTRE) + { + LLRect channel_rect = (*it).channel->getRect(); + S32 screen_width = getRootView()->getRect().getWidth(); + channel_rect.setLeftTopAndSize(screen_width/2, channel_rect.mTop, channel_rect.getWidth(), channel_rect.getHeight()); + (*it).channel->setRect(channel_rect); + (*it).channel->showToasts(); + } + } +} + +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- + + + + + + + diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h new file mode 100644 index 0000000000..564535ff24 --- /dev/null +++ b/indra/newview/llchannelmanager.h @@ -0,0 +1,116 @@ +/** + * @file llchannelmanager.h + * @brief This class rules screen notification channels. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLCHANNELMANAGER_H +#define LL_LLCHANNELMANAGER_H + + +#include "llchiclet.h" +#include "llscreenchannel.h" + +#include "lluuid.h" + +#include <map> +#include <boost/shared_ptr.hpp> + +namespace LLNotificationsUI +{ + +/** + * Manager for screen channels. + * Responsible for instantiating and retrieving screen channels. + */ +class LLChannelManager : public LLUICtrl, public LLSingleton<LLChannelManager> +{ +public: + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLUUID> id; + Optional<LLChiclet*> chiclet; + Optional<S32> channel_right_bound; + Optional<S32> channel_width; + Optional<EToastAlignment> align; + + Params(): id("id", LLUUID("")), + chiclet("chiclet", NULL), + channel_right_bound("channel_right_bound", 0), + channel_width("channel_width", 0), + align("align", NA_BOTTOM) + {} + }; + + struct ChannelElem + { + LLUUID id; + LLChiclet* chiclet; + LLScreenChannel* channel; + + ChannelElem() : id(LLUUID("")), chiclet(NULL), channel(NULL) { } + + ChannelElem(const ChannelElem &elem) + { + id = elem.id; + chiclet = elem.chiclet; + channel = elem.channel; + } + + bool operator == (const LLUUID &id_op) const + { + return (id == id_op); + } + + bool operator == (const LLChiclet* chiclet_op) const + { + return (chiclet == chiclet_op); + } + + }; + + LLChannelManager(); + virtual ~LLChannelManager(); + + //TODO: make protected? in order to be shure that channels are created only by notification handlers + LLScreenChannel* createChannel(LLChannelManager::Params& p); + + LLScreenChannel* getChannelByID(const LLUUID id); + LLScreenChannel* getChannelByChiclet(const LLChiclet* chiclet); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +private: + + std::vector<ChannelElem> mChannelList; +}; + +} +#endif + diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp new file mode 100644 index 0000000000..27ebccfe25 --- /dev/null +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -0,0 +1,525 @@ +/** + * @file llchatitemscontainer.cpp + * @brief chat history scrolling panel implementation + * + * $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 "llchatitemscontainerctrl.h" +#include "lltextbox.h" + +#include "llchatmsgbox.h" +#include "llavatariconctrl.h" +#include "llfloaterreg.h" +#include "lltrans.h" + +#include "llviewercontrol.h" + +static const S32 BORDER_MARGIN = 2; +static const S32 PARENT_BORDER_MARGIN = 0; + +static const S32 HORIZONTAL_MULTIPLE = 8; +static const S32 VERTICAL_MULTIPLE = 16; +static const F32 MIN_AUTO_SCROLL_RATE = 120.f; +static const F32 MAX_AUTO_SCROLL_RATE = 500.f; +static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; + +#define MAX_CHAT_HISTORY 100 + + +static LLDefaultChildRegistry::Register<LLChatItemsContainerCtrl> t2("chat_items_container"); + + + +//******************************************************************************************************************* +//LLChatItemCtrl +//******************************************************************************************************************* + +LLChatItemCtrl* LLChatItemCtrl::createInstance() +{ + LLChatItemCtrl* item = new LLChatItemCtrl(); + LLUICtrlFactory::getInstance()->buildPanel(item, "panel_chat_item.xml"); + return item; +} + +void LLChatItemCtrl::draw() +{ + LLPanel::draw(); +} + +void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +{ + LLPanel::reshape(width, height,called_from_parent); + + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text",false,false); + if(caption && msg_text) + { + LLRect caption_rect = caption->getRect(); + caption_rect.setLeftTopAndSize( 2, height, width - 4, caption_rect.getHeight()); + caption->reshape( width - 4, caption_rect.getHeight(), 1); + caption->setRect(caption_rect); + + + LLRect msg_text_rect = msg_text->getRect(); + msg_text_rect.setLeftTopAndSize( 10, height - caption_rect.getHeight() , width - 20, height - caption_rect.getHeight()); + msg_text->reshape( width - 20, height - caption_rect.getHeight(), 1); + msg_text->setRect(msg_text_rect); + } + +} + +BOOL LLChatItemCtrl::postBuild() +{ + return LLPanel::postBuild(); +} + + +std::string LLChatItemCtrl::appendTime() +{ + time_t utc_time; + utc_time = time_corrected(); + std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" + +LLTrans::getString("TimeMin")+"] "; + + LLSD substitution; + + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + + return timeStr; +} + + + +void LLChatItemCtrl::addText (const std::string& message) +{ + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text",false,false); + if(msg_text) + msg_text->addText(message); + mMessages.push_back(message); +} + +void LLChatItemCtrl::setMessage (const LLChat& msg) +{ + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + if(!caption) + return; + caption->getChild<LLTextBox>("sender_name",false,false)->setText(msg.mFromName); + std::string tt = appendTime(); + + caption->getChild<LLTextBox>("msg_time",false,false)->setText(tt); + + caption->getChild<LLAvatarIconCtrl>("avatar_icon",false,false)->setValue(msg.mFromID); + + mOriginalMessage = msg; + + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text",false,false); + if(msg_text) + msg_text->setText(msg.mText); + + LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); + if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + msg_inspector->setVisible(false); + + mMessages.clear(); + +} + + +void LLChatItemCtrl::setWidth(S32 width) +{ + LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text",false,false); + if(!text_box) + return;///actually assert fits better + + text_box->reshape(width - 20,100/*its not magic number, we just need any number*/); + + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text",false,false); + if(msg_text && mOriginalMessage.mText.length()) + msg_text->setText(mOriginalMessage.mText); + + for(size_t i=0;i<mMessages.size();++i) + msg_text->addText(mMessages[i]); + + S32 new_height = text_box->getTextPixelHeight(); + LLRect panel_rect = getRect(); + panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, width , 35 + new_height); + + reshape( width, panel_rect.getHeight(), 1); + + setRect(panel_rect); +} + +void LLChatItemCtrl::onMouseLeave (S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + if(!caption) + return; + LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); + if(msg_inspector) + msg_inspector->setVisible(false); + +} +void LLChatItemCtrl::onMouseEnter (S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + if(!caption) + return; + LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); + if(msg_inspector) + msg_inspector->setVisible(true); +} + +BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + if(mOriginalMessage.mSourceType == CHAT_SOURCE_AGENT && caption) + { + LLUICtrl* msg_inspector = caption->getChild<LLUICtrl>("msg_inspector"); + if(msg_inspector) + { + S32 local_x = x - msg_inspector->getRect().mLeft - caption->getRect().mLeft; + S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom; + if(msg_inspector->pointInView(local_x, local_y)) + { + LLFloaterReg::showInstance("mini_inspector", mOriginalMessage.mFromID); + } + } + } + return LLPanel::handleMouseDown(x,y,mask); +} + +void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) +{ + LLPanel* caption = getChild<LLPanel>("msg_caption",false,false); + if(!caption) + return; + + LLUICtrl* icon = caption->getChild<LLUICtrl>("avatar_icon",false,false); + LLUICtrl* name = caption->getChild<LLUICtrl>("sender_name",false,false); + + if(icon == 0 || name == 0) + return; + + icon->setVisible(e == CHATITEMHEADER_SHOW_ONLY_ICON || e==CHATITEMHEADER_SHOW_BOTH); + name->setVisible(e == CHATITEMHEADER_SHOW_ONLY_NAME || e==CHATITEMHEADER_SHOW_BOTH); + +} + +bool LLChatItemCtrl::canAddText () +{ + LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text",false,false); + if(!msg_text ) + return false; + return msg_text->getTextLinesNum()<10; +} + + +//******************************************************************************************************************* +//LLChatItemsContainerCtrl +//******************************************************************************************************************* + +LLChatItemsContainerCtrl::LLChatItemsContainerCtrl(const Params& params):LLPanel(params) +{ + mEShowItemHeader = CHATITEMHEADER_SHOW_BOTH; +} + + +void LLChatItemsContainerCtrl::addMessage(const LLChat& msg) +{ + /* + if(msg.mChatType == CHAT_TYPE_DEBUG_MSG) + return; + */ + if(mItems.size() >= MAX_CHAT_HISTORY) + { + LLChatItemCtrl* item = mItems[0]; + removeChild(item); + delete item; + } + + + if(mItems.size() > 0 && msg.mFromID == mItems[mItems.size()-1]->getMessage().mFromID && mItems[mItems.size()-1]->canAddText()) + { + mItems[mItems.size()-1]->addText(msg.mText); + mItems[mItems.size()-1]->setWidth(getRect().getWidth() - 16); + } + else + { + LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); + mItems.push_back(item); + addChild(item,0); + item->setWidth(getRect().getWidth() - 16); + item->setMessage(msg); + item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + + item->setVisible(true); + } + + arrange(getRect().getWidth(),getRect().getHeight()); + updateLayout(getRect().getWidth(),getRect().getHeight()); + scrollToBottom(); +} + +void LLChatItemsContainerCtrl::scrollToBottom () +{ + if(mScrollbar->getVisible()) + { + mScrollbar->setDocPos(mScrollbar->getDocPosMax()); + onScrollPosChangeCallback(0,0); + } +} + +void LLChatItemsContainerCtrl::draw() +{ + LLLocalClipRect clip(getRect()); + LLPanel::draw(); +} + +void LLChatItemsContainerCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +{ + S32 delta_width = width - getRect().getWidth(); + S32 delta_height = height - getRect().getHeight(); + + if (delta_width || delta_height || sForceReshape) + { + arrange(width, height); + } + + updateBoundingRect(); +} + +void LLChatItemsContainerCtrl::arrange (S32 width, S32 height) +{ + S32 delta_width = width - getRect().getWidth(); + if(delta_width)//width changed...too bad. now we need to reformat all items + reformatHistoryScrollItems(width); + + calcRecuiredHeight(); + + show_hide_scrollbar(width,height); + + updateLayout(width,height); +} + +void LLChatItemsContainerCtrl::reformatHistoryScrollItems(S32 width) +{ + for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) + { + (*it)->setWidth(width); + } +} + +S32 LLChatItemsContainerCtrl::calcRecuiredHeight () +{ + S32 rec_height = 0; + + std::vector<LLChatItemCtrl*>::iterator it; + for(it=mItems.begin(); it!=mItems.end(); ++it) + { + rec_height += (*it)->getRect().getHeight(); + } + + mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); + + return mInnerRect.getHeight(); +} + + +void LLChatItemsContainerCtrl::updateLayout (S32 width, S32 height) +{ + S32 panel_top = height - BORDER_MARGIN ; + S32 panel_width = width; + if(mScrollbar->getVisible()) + { + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + panel_top+=mScrollbar->getDocPos(); + panel_width-=scrollbar_size; + } + + + //set sizes for first pannels and dragbars + for(size_t i=0;i<mItems.size();++i) + { + LLRect panel_rect = mItems[i]->getRect(); + panelSetLeftTopAndSize(mItems[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); + panel_top-=panel_rect.getHeight(); + } +} + +void LLChatItemsContainerCtrl::show_hide_scrollbar (S32 width, S32 height) +{ + calcRecuiredHeight(); + if(getRecuiredHeight() > height ) + showScrollbar(width, height); + else + hideScrollbar(width, height); +} + +void LLChatItemsContainerCtrl::showScrollbar (S32 width, S32 height) +{ + bool was_visible = mScrollbar->getVisible(); + + mScrollbar->setVisible(true); + + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + panelSetLeftTopAndSize(mScrollbar,width-scrollbar_size + ,height-PARENT_BORDER_MARGIN,scrollbar_size,height-2*PARENT_BORDER_MARGIN); + + mScrollbar->setPageSize(height); + mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); + + if(was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); + mScrollbar->setDocPos(scroll_pos); + updateLayout(width,height); + return; + } +} + +void LLChatItemsContainerCtrl::hideScrollbar (S32 width, S32 height) +{ + if(mScrollbar->getVisible() == false) + return; + mScrollbar->setVisible(false); + + mScrollbar->setDocPos(0); + + if(mItems.size()>0) + { + S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel + S32 diff = panel_top - mItems[0]->getRect().mTop; + shiftPanels(diff); + } +} + +//--------------------------------------------------------------------------------- +void LLChatItemsContainerCtrl::panelSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) +{ + if(!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize( left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); +} + +void LLChatItemsContainerCtrl::panelShiftVertical(LLView* panel,S32 delta) +{ + if(!panel) + return; + panel->translate(0,delta); +} + +void LLChatItemsContainerCtrl::shiftPanels(S32 delta) +{ + //Arrange panels + for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) + { + panelShiftVertical((*it),delta); + } + +} + +//--------------------------------------------------------------------------------- + +void LLChatItemsContainerCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) +{ + updateLayout(getRect().getWidth(),getRect().getHeight()); +} + +BOOL LLChatItemsContainerCtrl::postBuild() +{ + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + + LLScrollbar::Params sbparams; + sbparams.name("scrollable vertical"); + sbparams.rect(scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(mInnerRect.getHeight()); + sbparams.doc_pos(0); + sbparams.page_size(mInnerRect.getHeight()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.change_callback(boost::bind(&LLChatItemsContainerCtrl::onScrollPosChangeCallback, this, _1, _2)); + + mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); + LLView::addChild( mScrollbar ); + mScrollbar->setVisible( true ); + mScrollbar->setFollowsRight(); + mScrollbar->setFollowsTop(); + mScrollbar->setFollowsBottom(); + + reformatHistoryScrollItems(getRect().getWidth()); + arrange(getRect().getWidth(),getRect().getHeight()); + + return LLPanel::postBuild(); +} +BOOL LLChatItemsContainerCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +{ + return LLPanel::handleMouseDown(x,y,mask); +} +BOOL LLChatItemsContainerCtrl::handleKeyHere (KEY key, MASK mask) +{ + if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) + return TRUE; + return LLPanel::handleKeyHere(key,mask); +} +BOOL LLChatItemsContainerCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) +{ + if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + return TRUE; + return false; +} + +void LLChatItemsContainerCtrl::setHeaderVisibility(EShowItemHeader e) +{ + if(e == mEShowItemHeader) + return; + mEShowItemHeader = e; + for(std::vector<LLChatItemCtrl*>::iterator it = mItems.begin(); it != mItems.end();++it) + { + (*it)->setHeaderVisibility(e); + } +} + + diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h new file mode 100644 index 0000000000..f5791078aa --- /dev/null +++ b/indra/newview/llchatitemscontainerctrl.h @@ -0,0 +1,152 @@ +/** + * @file llchatitemscontainer.h + * @brief chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-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_LLCHATITEMSCONTAINER_H_ +#define LL_LLCHATITEMSCONTAINER_H_ + +#include "llpanel.h" +#include "llscrollbar.h" +#include "string" +#include "llchat.h" + +typedef enum e_show_item_header +{ + CHATITEMHEADER_SHOW_ONLY_NAME = 0, + CHATITEMHEADER_SHOW_ONLY_ICON = 1, + CHATITEMHEADER_SHOW_BOTH +} EShowItemHeader; + +class LLChatItemCtrl: public LLPanel +{ +protected: + LLChatItemCtrl(){}; +public: + + + ~LLChatItemCtrl(){} + + static LLChatItemCtrl* createInstance(); + + void draw(); + + const LLChat& getMessage() const { return mOriginalMessage;} + + void addText (const std::string& message); + void setMessage (const LLChat& msg); + void setWidth (S32 width); + + bool canAddText (); + + void onMouseLeave (S32 x, S32 y, MASK mask); + void onMouseEnter (S32 x, S32 y, MASK mask); + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + + virtual BOOL postBuild(); + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + void setHeaderVisibility(EShowItemHeader e); +private: + + std::string appendTime (); + +private: + LLChat mOriginalMessage; + + std::vector<std::string> mMessages; +}; + +class LLChatItemsContainerCtrl: public LLPanel +{ +public: + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + Params(){}; + }; + + LLChatItemsContainerCtrl(const Params& params); + + + ~LLChatItemsContainerCtrl(){} + + void addMessage (const LLChat& msg); + + void draw(); + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + void onScrollPosChangeCallback(S32, LLScrollbar*); + + virtual BOOL postBuild(); + + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + BOOL handleKeyHere (KEY key, MASK mask); + BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + void scrollToBottom (); + + void setHeaderVisibility(EShowItemHeader e); + EShowItemHeader getHeaderVisibility() const { return mEShowItemHeader;}; + + +private: + void reformatHistoryScrollItems(S32 width); + void arrange (S32 width, S32 height); + + S32 calcRecuiredHeight (); + S32 getRecuiredHeight () const { return mInnerRect.getHeight(); } + + void updateLayout (S32 width, S32 height); + + void show_hide_scrollbar (S32 width, S32 height); + + void showScrollbar (S32 width, S32 height); + void hideScrollbar (S32 width, S32 height); + + void panelSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); + void panelShiftVertical (LLView* panel,S32 delta); + void shiftPanels (S32 delta); + +private: + std::vector<LLChatItemCtrl*> mItems; + + EShowItemHeader mEShowItemHeader; + + LLRect mInnerRect; + LLScrollbar* mScrollbar; + +}; + +#endif + + diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp new file mode 100644 index 0000000000..8fb4b78cb8 --- /dev/null +++ b/indra/newview/llchatmsgbox.cpp @@ -0,0 +1,390 @@ +/** + * @file llchatmsgbox.cpp + * @brief chat history text box, able to show array of strings with separator + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-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 "llchatmsgbox.h" +#include "llwindow.h" +#include "llfocusmgr.h" + +static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat"); + +LLChatMsgBox::Params::Params() +: text_color("text_color"), + highlight_on_hover("hover", false), + border_visible("border_visible", false), + border_drop_shadow_visible("border_drop_shadow_visible", false), + bg_visible("bg_visible", false), + use_ellipses("use_ellipses"), + word_wrap("word_wrap", false), + hover_color("hover_color"), + disabled_color("disabled_color"), + background_color("background_color"), + border_color("border_color"), + v_pad("v_pad", 0), + h_pad("h_pad", 0), + line_spacing("line_spacing", 0), + text("text"), + font_shadow("font_shadow", LLFontGL::NO_SHADOW) +{} + +LLChatMsgBox::LLChatMsgBox(const LLChatMsgBox::Params& p) +: LLUICtrl(p), + mFontGL(p.font), + mHoverActive( p.highlight_on_hover ), + mHasHover( FALSE ), + mBackgroundVisible( p.bg_visible ), + mBorderVisible( p.border_visible ), + mShadowType( p.font_shadow ), + mBorderDropShadowVisible( p.border_drop_shadow_visible ), + mUseEllipses( p.use_ellipses ), + mHPad(p.h_pad), + mVPad(p.v_pad), + mVAlign( LLFontGL::TOP ), + mClickedCallback(NULL), + mTextColor(p.text_color()), + mDisabledColor(p.disabled_color()), + mBackgroundColor(p.background_color()), + mBorderColor(p.border_color()), + mHoverColor(p.hover_color()), + mHAlign(p.font_halign), + mLineSpacing(p.line_spacing), + mWordWrap( p.word_wrap ), + mFontStyle(LLFontGL::getStyleFromString(p.font.style)) +{ + setText( p.text() ); +} + +BOOL LLChatMsgBox::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback) + { + handled = TRUE; + + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } + + return handled; +} + +BOOL LLChatMsgBox::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback + && hasMouseCapture()) + { + handled = TRUE; + + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. + // If mouseup in the widget, it's been clicked + if (mClickedCallback) + { + mClickedCallback(); + } + } + + return handled; +} + +BOOL LLChatMsgBox::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x,y,mask); + if(mHoverActive) + { + mHasHover = TRUE; // This should be set every frame during a hover. + getWindow()->setCursor(UI_CURSOR_ARROW); + } + + return (handled || mHasHover); +} + +void LLChatMsgBox::addText( const LLStringExplicit& text ) +{ + boost::shared_ptr<text_block> t(new text_block()); + t->text = wrapText(text); + setLineLengths(*t); + mTextStrings.push_back(t); +} + +void LLChatMsgBox::setText(const LLStringExplicit& text) +{ + mTextStrings.clear(); + + addText(text); + +} + +void LLChatMsgBox::resetLineLengths() +{ + for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr<text_block> tblock = *it; + setLineLengths(*tblock); + } +} + +void LLChatMsgBox::setLineLengths(text_block& t) +{ + t.lines.clear(); + + std::string::size_type cur = 0; + std::string::size_type len = t.text.length(); + + while (cur < len) + { + std::string::size_type end = t.text.getWString().find('\n', cur); + std::string::size_type runLen; + + if (end == std::string::npos) + { + runLen = len - cur; + cur = len; + } + else + { + runLen = end - cur; + cur = end + 1; // skip the new line character + } + + t.lines.push_back( (S32)runLen ); + } +} + +std::string LLChatMsgBox::wrapText(const LLStringExplicit& in_text, F32 max_width) +{ + if (max_width < 0.0f) + { + max_width = (F32)getRect().getWidth(); + } + + LLWString wtext = utf8str_to_wstring(in_text); + LLWString final_wtext; + + LLWString::size_type cur = 0;; + LLWString::size_type len = wtext.size(); + while (cur < len) + { + LLWString::size_type end = wtext.find('\n', cur); + if (end == LLWString::npos) + { + end = len; + } + + LLWString::size_type runLen = end - cur; + if (runLen > 0) + { + LLWString run(wtext, cur, runLen); + LLWString::size_type useLen = + mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); + + final_wtext.append(wtext, cur, useLen); + cur += useLen; + // not enough room to add any more characters + if (useLen == 0) break; + } + + if (cur < len) + { + if (wtext[cur] == '\n') + cur += 1; + else + final_wtext += '\n'; + } + } + + std::string final_text = wstring_to_utf8str(final_wtext); + return final_text; +} + +S32 LLChatMsgBox::getTextLinesNum() +{ + S32 num_lines = 0; + for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr<text_block> tblock = *it; + num_lines+=tblock->lines.size(); + } + + if( num_lines < 1 ) + { + num_lines = 1; + } + + return num_lines; +} + +S32 LLChatMsgBox::getTextPixelHeight() +{ + S32 num_lines = getTextLinesNum(); + return (S32)(num_lines * mFontGL->getLineHeight() + (num_lines-1)*4); +} + +void LLChatMsgBox::setValue(const LLSD& value ) +{ + setText(value.asString()); +} + + +void LLChatMsgBox::draw() +{ + if (mBorderVisible) + { + gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); + } + + if( mBorderDropShadowVisible ) + { + static LLUICachedControl<LLColor4> color_drop_shadow ("ColorDropShadow", *(new LLColor4)); + static LLUICachedControl<S32> drop_shadow_tooltip ("DropShadowTooltip", 0); + gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, + color_drop_shadow, drop_shadow_tooltip); + } + + if (mBackgroundVisible) + { + LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + gl_rect_2d( r, mBackgroundColor.get() ); + } + + S32 text_x = 0; + switch( mHAlign ) + { + case LLFontGL::LEFT: + text_x = mHPad; + break; + case LLFontGL::HCENTER: + text_x = getRect().getWidth() / 2; + break; + case LLFontGL::RIGHT: + text_x = getRect().getWidth() - mHPad; + break; + } + + S32 text_y = getRect().getHeight() - mVPad; + + if ( getEnabled() ) + { + if(mHasHover) + { + drawText( text_x, text_y, mHoverColor.get() ); + } + else + { + drawText( text_x, text_y, mTextColor.get() ); + } + } + else + { + drawText( text_x, text_y, mDisabledColor.get() ); + } + + if (sDebugRects) + { + drawDebugRect(); + } + + //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) + //std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); + //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) + //{ + // drawDebugRect(); + //} + + mHasHover = FALSE; // This is reset every frame. +} + +void LLChatMsgBox::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + // reparse line lengths + LLView::reshape(width, height, called_from_parent); + resetLineLengths(); +} + +void LLChatMsgBox::drawText( S32 x, S32 y, const LLColor4& color ) +{ + S32 width = getRect().getWidth()-10; + + for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr<text_block> tblock = *it; + + S32 cur_pos = 0; + for (std::vector<S32>::iterator iter = tblock->lines.begin(); + iter != tblock->lines.end(); ++iter) + { + S32 line_length = *iter; + mFontGL->render(tblock->text, cur_pos, (F32)x, (F32)y, color, + mHAlign, mVAlign, + mFontStyle, + mShadowType, + line_length, getRect().getWidth(), NULL, TRUE, mUseEllipses ); + cur_pos += line_length + 1; + y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; + + } + std::vector< boost::shared_ptr<text_block> >::iterator next = it; + ++next; + if(next == mTextStrings.end()) + break; + //separator + gl_line_2d(5,y-2,width,y-2,LLColor4::grey); + y-=4; + } +} + diff --git a/indra/newview/llchatmsgbox.h b/indra/newview/llchatmsgbox.h new file mode 100644 index 0000000000..c0e1964afa --- /dev/null +++ b/indra/newview/llchatmsgbox.h @@ -0,0 +1,163 @@ +/** + * @file llchatmsgbox.h + * @brief chat history text box, able to show array of strings with separator + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-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_LLCHATMSGBOX_H +#define LL_LLCHATMSGBOX_H + + +#include "lluictrl.h" +#include "v4color.h" +#include "llstring.h" +#include "lluistring.h" + + +class LLChatMsgBox +: public LLUICtrl +{ +protected: + struct text_block + { + LLUIString text; + std::vector<S32> lines; + }; +public: + typedef boost::function<void (void)> callback_t; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<std::string> text; + + Optional<bool> highlight_on_hover, + border_visible, + border_drop_shadow_visible, + bg_visible, + use_ellipses, + word_wrap; + + Optional<LLFontGL::ShadowType> font_shadow; + + Optional<LLUIColor> text_color, + hover_color, + disabled_color, + background_color, + border_color; + + Optional<S32> v_pad, + h_pad, + line_spacing; + + Params(); + }; +protected: + LLChatMsgBox(const Params&); + friend class LLUICtrlFactory; +public: + virtual void draw(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + + void setColor( const LLColor4& c ) { mTextColor = c; } + void setDisabledColor( const LLColor4& c) { mDisabledColor = c; } + void setBackgroundColor( const LLColor4& c) { mBackgroundColor = c; } + void setBorderColor( const LLColor4& c) { mBorderColor = c; } + + void setHoverColor( const LLColor4& c ) { mHoverColor = c; } + void setHoverActive( BOOL active ) { mHoverActive = active; } + + void setText( const LLStringExplicit& text ); + void addText( const LLStringExplicit& text ); + + void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } + + void setBackgroundVisible(BOOL visible) { mBackgroundVisible = visible; } + void setBorderVisible(BOOL visible) { mBorderVisible = visible; } + void setBorderDropshadowVisible(BOOL visible){ mBorderDropShadowVisible = visible; } + void setHPad(S32 pixels) { mHPad = pixels; } + void setVPad(S32 pixels) { mVPad = pixels; } + void setRightAlign() { mHAlign = LLFontGL::RIGHT; } + void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } + void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button + + const LLFontGL* getFont() const { return mFontGL; } + + S32 getTextPixelHeight(); + S32 getTextLinesNum(); + + virtual void setValue(const LLSD& value ); + + + +private: + std::string wrapText (const LLStringExplicit& in_text, F32 max_width = -1.0); + + void setLineLengths (text_block& t); + void resetLineLengths (); + void drawText (S32 x, S32 y, const LLColor4& color ); + + const LLFontGL* mFontGL; + LLUIColor mTextColor; + LLUIColor mDisabledColor; + LLUIColor mBackgroundColor; + LLUIColor mBorderColor; + LLUIColor mHoverColor; + + BOOL mHoverActive; + BOOL mHasHover; + BOOL mBackgroundVisible; + BOOL mBorderVisible; + BOOL mWordWrap; + + U8 mFontStyle; // style bit flags for font + LLFontGL::ShadowType mShadowType; + BOOL mBorderDropShadowVisible; + BOOL mUseEllipses; + + S32 mLineSpacing; + + S32 mHPad; + S32 mVPad; + LLFontGL::HAlign mHAlign; + LLFontGL::VAlign mVAlign; + + callback_t mClickedCallback; + + + //same as mLineLengthList and mText in LLTextBox + std::vector< boost::shared_ptr<text_block> > mTextStrings; + +}; + +#endif + diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index bd946a79d6..38a7494b5b 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -62,9 +62,11 @@ LLNotificationChiclet::Params::Params() : button("button") , unread_notifications("unread_notifications") { + button.name("button"); button.tab_stop(FALSE); button.label(LLStringUtil::null); + unread_notifications.name("unread"); unread_notifications.font(LLFontGL::getFontSansSerif()); unread_notifications.text_color=(LLColor4::white); unread_notifications.font_halign(LLFontGL::HCENTER); @@ -327,9 +329,12 @@ BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) createPopupMenu(); updateMenuItems(); - - mPopupMenu->arrangeAndClear(); + if (mPopupMenu) + { + mPopupMenu->arrangeAndClear(); + } + LLMenuGL::showPopup(this, mPopupMenu, x, y); return TRUE; diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp new file mode 100644 index 0000000000..411aa72690 --- /dev/null +++ b/indra/newview/llnearbychat.cpp @@ -0,0 +1,362 @@ +/** + * @file LLNearbyChat.cpp + * @brief Nearby chat history scrolling panel implementation + * + * $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 "llnearbychat.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llrootview.h" +#include "llchatitemscontainerctrl.h" +#include "lliconctrl.h" +#include "llsidetray.h" +#include "llfocusmgr.h" +#include "llresizebar.h" +#include "llresizehandle.h" +#include "llmenugl.h" +#include "llviewermenu.h"//for gMenuHolder + +static const S32 RESIZE_BAR_THICKNESS = 3; + +LLNearbyChat::LLNearbyChat(const LLSD& key) : + LLFloater(key), + mEChatTearofState(CHAT_PINNED) +{ +} + +LLNearbyChat::~LLNearbyChat() +{ +} + +BOOL LLNearbyChat::postBuild() +{ + //resize bars + setCanResize(true); + + mResizeBar[LLResizeBar::BOTTOM]->setVisible(false); + mResizeBar[LLResizeBar::LEFT]->setVisible(false); + mResizeBar[LLResizeBar::RIGHT]->setVisible(false); + + mResizeHandle[0]->setVisible(false); + mResizeHandle[1]->setVisible(false); + mResizeHandle[2]->setVisible(false); + mResizeHandle[3]->setVisible(false); + + //menu + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + + enable_registrar.add("NearbyChat.Check", boost::bind(&LLNearbyChat::onNearbyChatCheckContextMenuItem, this, _2)); + registrar.add("NearbyChat.Action", boost::bind(&LLNearbyChat::onNearbyChatContextMenuItemClicked, this, _2)); + + + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_nearby_chat.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + + if(menu) + mPopupMenuHandle = menu->getHandle(); + + gSavedSettings.declareS32("nearbychat_showicons_and_names",2,"NearByChat header settings",true); + + LLChatItemsContainerCtrl* panel = getChild<LLChatItemsContainerCtrl>("chat_history",false,false); + if(panel) + { + panel->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + } + + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + + return LLFloater::postBuild(); +} + +void LLNearbyChat::addMessage(const LLChat& message) +{ + LLChatItemsContainerCtrl* panel = getChild<LLChatItemsContainerCtrl>("chat_history",false,false); + if(!panel) + return; + panel->addMessage(message); + +} + +void LLNearbyChat::onNearbySpeakers() +{ + LLSD param = "nearby_panel"; + LLSideTray::getInstance()->showPanel("panel_people",param); +} + +void LLNearbyChat::onTearOff() +{ + if(mEChatTearofState == CHAT_PINNED) + float_panel(); + else + pinn_panel(); +} + +void LLNearbyChat::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + + LLFloater::reshape(width, height, called_from_parent); + + LLPanel* caption = getChild<LLPanel>("chat_caption",false,false); + + LLRect resize_rect; + resize_rect.setLeftTopAndSize( 0, height, width, RESIZE_BAR_THICKNESS); + if (mResizeBar[LLResizeBar::TOP]) + { + mResizeBar[LLResizeBar::TOP]->reshape(width,RESIZE_BAR_THICKNESS); + mResizeBar[LLResizeBar::TOP]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( 0, RESIZE_BAR_THICKNESS, width, RESIZE_BAR_THICKNESS); + if (mResizeBar[LLResizeBar::BOTTOM]) + { + mResizeBar[LLResizeBar::BOTTOM]->reshape(width,RESIZE_BAR_THICKNESS); + mResizeBar[LLResizeBar::BOTTOM]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( 0, height, RESIZE_BAR_THICKNESS, height); + if (mResizeBar[LLResizeBar::LEFT]) + { + mResizeBar[LLResizeBar::LEFT]->reshape(RESIZE_BAR_THICKNESS,height); + mResizeBar[LLResizeBar::LEFT]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( width - RESIZE_BAR_THICKNESS, height, RESIZE_BAR_THICKNESS, height); + if (mResizeBar[LLResizeBar::RIGHT]) + { + mResizeBar[LLResizeBar::RIGHT]->reshape(RESIZE_BAR_THICKNESS,height); + mResizeBar[LLResizeBar::RIGHT]->setRect(resize_rect); + } + + + LLRect caption_rect; + if (caption) + { + caption_rect = caption->getRect(); + caption_rect.setLeftTopAndSize( 2, height - RESIZE_BAR_THICKNESS, width - 4, caption_rect.getHeight()); + caption->reshape( width - 4, caption_rect.getHeight(), 1); + caption->setRect(caption_rect); + } + + LLPanel* scroll_panel = getChild<LLPanel>("chat_history",false,false); + if (scroll_panel) + { + LLRect scroll_rect = scroll_panel->getRect(); + scroll_rect.setLeftTopAndSize( 2, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS, width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2); + scroll_panel->reshape( width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2, 1); + scroll_panel->setRect(scroll_rect); + } + + // + if(mEChatTearofState == CHAT_PINNED) + { + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + LLRect panel_rect; + panel_rect.setLeftTopAndSize( parent_rect.mLeft+2, parent_rect.mBottom+height+4, width, height); + setRect(panel_rect); + } + else + { + LLRect panel_rect; + panel_rect.setLeftTopAndSize( getRect().mLeft, getRect().mTop, width, height); + setRect(panel_rect); + } + +} + +BOOL LLNearbyChat::handleMouseDown (S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild<LLPanel>("chat_caption",false,false); + if(caption) + { + LLUICtrl* nearby_speakers_btn = caption->getChild<LLUICtrl>("nearby_speakers_btn"); + LLUICtrl* tearoff_btn = caption->getChild<LLUICtrl>("tearoff_btn"); + LLUICtrl* close_btn = caption->getChild<LLUICtrl>("close_btn"); + + S32 caption_local_x = x - caption->getRect().mLeft; + S32 caption_local_y = y - caption->getRect().mBottom; + + if(nearby_speakers_btn && tearoff_btn) + { + S32 local_x = caption_local_x - nearby_speakers_btn->getRect().mLeft; + S32 local_y = caption_local_y - nearby_speakers_btn->getRect().mBottom; + if(nearby_speakers_btn->pointInView(local_x, local_y)) + { + onNearbySpeakers(); + bringToFront( x, y ); + return true; + } + local_x = caption_local_x - tearoff_btn->getRect().mLeft; + local_y = caption_local_y- tearoff_btn->getRect().mBottom; + if(tearoff_btn->pointInView(local_x, local_y)) + { + onTearOff(); + bringToFront( x, y ); + return true; + } + + if(close_btn) + { + local_x = caption_local_x - close_btn->getRect().mLeft; + local_y = caption_local_y - close_btn->getRect().mBottom; + if(close_btn->pointInView(local_x, local_y)) + { + setVisible(false); + bringToFront( x, y ); + return true; + } + } + } + + if(mEChatTearofState == CHAT_UNPINNED && caption->pointInView(caption_local_x, caption_local_y) ) + { + //start draggind + gFocusMgr.setMouseCapture(this); + mStart_Y = y; + mStart_X = x; + bringToFront( x, y ); + return true; + } + } + + return LLFloater::handleMouseDown(x,y,mask); +} + +BOOL LLNearbyChat::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if( hasMouseCapture() ) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + mStart_X = 0; + mStart_Y = 0; + return true; + } + + return LLFloater::handleMouseUp(x,y,mask); +} + +BOOL LLNearbyChat::handleHover(S32 x, S32 y, MASK mask) +{ + if( hasMouseCapture() ) + { + translate(x-mStart_X,y-mStart_Y); + return true; + } + return LLFloater::handleHover(x,y,mask); +} + +void LLNearbyChat::pinn_panel() +{ + mEChatTearofState = CHAT_PINNED; + LLPanel* caption = getChild<LLPanel>("chat_caption",false,false); + LLIconCtrl* tearoff_btn = caption->getChild<LLIconCtrl>("tearoff_btn",false,false); + + tearoff_btn->setValue("inv_item_landmark_visited.tga"); + + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + LLRect panel_rect; + panel_rect.setLeftTopAndSize( parent_rect.mLeft+2, parent_rect.mBottom+getRect().getHeight()+4, getRect().getWidth(), getRect().getHeight()); + setRect(panel_rect); + + mResizeBar[LLResizeBar::BOTTOM]->setVisible(false); + mResizeBar[LLResizeBar::LEFT]->setVisible(false); + mResizeBar[LLResizeBar::RIGHT]->setVisible(false); + +} + +void LLNearbyChat::float_panel() +{ + mEChatTearofState = CHAT_UNPINNED; + LLPanel* caption = getChild<LLPanel>("chat_caption",false,false); + LLIconCtrl* tearoff_btn = caption->getChild<LLIconCtrl>("tearoff_btn",false,false); + + tearoff_btn->setValue("inv_item_landmark.tga"); + mResizeBar[LLResizeBar::BOTTOM]->setVisible(true); + mResizeBar[LLResizeBar::LEFT]->setVisible(true); + mResizeBar[LLResizeBar::RIGHT]->setVisible(true); +} + +void LLNearbyChat::onNearbyChatContextMenuItemClicked(const LLSD& userdata) +{ + LLChatItemsContainerCtrl* panel = getChild<LLChatItemsContainerCtrl>("chat_history",false,false); + if(!panel) + return; + + std::string str = userdata.asString(); + if(str == "show_buddy_icons") + panel->setHeaderVisibility(CHATITEMHEADER_SHOW_ONLY_ICON); + else if(str == "show_names") + panel->setHeaderVisibility(CHATITEMHEADER_SHOW_ONLY_NAME); + else if(str == "show_icons_and_names") + panel->setHeaderVisibility(CHATITEMHEADER_SHOW_BOTH); + + gSavedSettings.setS32("nearbychat_showicons_and_names", (S32)panel->getHeaderVisibility()); + + +} +bool LLNearbyChat::onNearbyChatCheckContextMenuItem(const LLSD& userdata) +{ + LLChatItemsContainerCtrl* panel = getChild<LLChatItemsContainerCtrl>("chat_history",false,false); + if(!panel) + return false; + std::string str = userdata.asString(); + if(str == "show_buddy_icons") + return panel->getHeaderVisibility() == CHATITEMHEADER_SHOW_ONLY_ICON; + else if(str == "show_names") + return panel->getHeaderVisibility() == CHATITEMHEADER_SHOW_ONLY_NAME; + else if(str == "show_icons_and_names") + return panel->getHeaderVisibility() == CHATITEMHEADER_SHOW_BOTH; + else if(str == "nearby_people") + onNearbySpeakers(); + return false; +} + +BOOL LLNearbyChat::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild<LLPanel>("chat_caption",false,false); + if(caption && caption->pointInView(x - caption->getRect().mLeft, y - caption->getRect().mBottom) ) + { + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + + if(menu) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + } + return true; + } + return LLFloater::handleRightMouseDown(x, y, mask); +} + diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h new file mode 100644 index 0000000000..61ff8890ea --- /dev/null +++ b/indra/newview/llnearbychat.h @@ -0,0 +1,98 @@ +/** + * @file llnearbychat.h + * @brief nearby chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-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_LLNEARBYCHAT_H_ +#define LL_LLNEARBYCHAT_H_ + +#include "llfloater.h" +#include "llscrollbar.h" +#include "llchat.h" + +class LLResizeBar; + +class LLNearbyChat: public LLFloater +{ +public: + // enumerations used by the chat system + typedef enum e_chat_tearof_state + { + CHAT_PINNED = 0, + CHAT_UNPINNED = 1, + } EChatTearofState; + + enum { RESIZE_BAR_COUNT=4 }; + + LLNearbyChat(const LLSD& key); + ~LLNearbyChat(); + + LLNearbyChat():mEChatTearofState(CHAT_PINNED){}; + LLNearbyChat(const Params& params):mEChatTearofState(CHAT_PINNED){}; + + //static LLNearbyChat* createInstance(); + //static LLNearbyChat* getInstance (); + + BOOL postBuild (); + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + BOOL handleMouseUp (S32 x, S32 y, MASK mask); + BOOL handleHover (S32 x, S32 y, MASK mask); + + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + void addMessage (const LLChat& message); + + void onNearbySpeakers (); + void onTearOff(); + + void onNearbyChatContextMenuItemClicked(const LLSD& userdata); + bool onNearbyChatCheckContextMenuItem(const LLSD& userdata); + + virtual void onClose(bool app_quitting) { if(app_quitting) destroy(); else setVisible(false); } + +private: + + void pinn_panel(); + void float_panel(); + +private: + EChatTearofState mEChatTearofState; + S32 mStart_X; + S32 mStart_Y; + + //LLResizeBar* mResizeBar[RESIZE_BAR_COUNT]; + LLHandle<LLView> mPopupMenuHandle; +}; + +#endif + + diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp new file mode 100644 index 0000000000..ab66421d35 --- /dev/null +++ b/indra/newview/llnearbychathandler.cpp @@ -0,0 +1,118 @@ +/** + * @file LLNearbyChatHandler.cpp + * @brief Nearby chat notification managment + * + * $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 "llnearbychathandler.h" + +#include "llchatitemscontainerctrl.h" +#include "llnearbychat.h" +#include "llrecentpeople.h" + +#include "llviewercontrol.h" + +#include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance + +//add LLNearbyChatHandler to LLNotificationsUI namespace +namespace LLNotificationsUI{ + + +LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id) +{ + mType = type; + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); + ///////////////////////////////////////////////////// + LLChannelManager::Params p; //TODO: check and correct + p.id = LLUUID(NEARBY_CHAT_ID); + p.channel_right_bound = nearby_chat->getRect().mRight; + p.channel_width = nearby_chat->getRect().mRight - 16; //HACK: 16 - ? + ///////////////////////////////////////////////////// + + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); + mChannel->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_TOP); + mChannel->setStoreToasts(false); +} +LLNearbyChatHandler::~LLNearbyChatHandler() +{ +} +void LLNearbyChatHandler::processChat(const LLChat& chat_msg) +{ + if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) + LLRecentPeople::instance().add(chat_msg.mFromID); + + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); + nearby_chat->addMessage(chat_msg); + if(nearby_chat->getVisible()) + return;//no need in toast if chat is visible + + LLUUID id; + id.generate(); + + LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); + + item->setMessage(chat_msg); + item->setWidth(nearby_chat->getRect().getWidth() - 16); + item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + + item->setVisible(true); + + + LLToast* toast = mChannel->addToast(id, item); + + toast->setOnMouseEnterCallback(boost::bind(&LLNearbyChatHandler::onToastDestroy, this, toast)); + toast->setAndStartTimer(10); //TODO: set correct time +} + +void LLNearbyChatHandler::onToastDestroy(LLToast* toast) +{ + //TODO: what should be done to toasts here? may be htey are to be destroyed? + //toast->hide(); + if(mChannel) + mChannel->removeToastsFromChannel(); + else if(toast) + toast->hide(); + + LLFloaterReg::showTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); +} + +void LLNearbyChatHandler::onChicletClick(void) +{ +} +void LLNearbyChatHandler::onChicletClose(void) +{ + +} + +} + diff --git a/indra/newview/llnearbychathandler.h b/indra/newview/llnearbychathandler.h new file mode 100644 index 0000000000..89ac08b9f0 --- /dev/null +++ b/indra/newview/llnearbychathandler.h @@ -0,0 +1,60 @@ +/** + * @file llnearbychathandler.h + * @brief nearby chat notify + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-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_LLNEARBYCHATHANDLER_H +#define LL_LLNEARBYCHATHANDLER_H + +#include "llnotificationhandler.h" + +#define NEARBY_CHAT_ID "E1158BD6-661C-4981-9DAD-4DCBFF062502" + +//add LLNearbyChatHandler to LLNotificationsUI namespace +namespace LLNotificationsUI{ + +class LLNearbyChatHandler : public LLChatHandler +{ +public: + LLNearbyChatHandler(e_notification_type type,const LLSD& id); + virtual ~LLNearbyChatHandler(); + + + virtual void processChat(const LLChat& chat_msg); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: +}; + +} + +#endif /* LL_LLNEARBYCHATHANDLER_H */ diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp new file mode 100644 index 0000000000..757a0e5999 --- /dev/null +++ b/indra/newview/llnotificationalerthandler.cpp @@ -0,0 +1,116 @@ +/** + * @file llnotificationalerthandler.cpp + * @brief Notification Handler Class for Alert Notifications + * + * $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 "llnotificationhandler.h" +#include "lltoastnotifypanel.h" +#include "llbottomtray.h" +#include "llviewercontrol.h" + +#include "lltoastalertpanel.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLAlertHandler::LLAlertHandler(e_notification_type type, const LLSD& id) : mIsModal(false) +{ + mType = type; + + LLBottomTray* tray = LLBottomTray::getInstance(); + LLChannelManager::Params p; + p.id = LLUUID("F3E07BC8-A973-476D-8C7F-F3B7293975D1"); + p.channel_right_bound = tray->getRect().getWidth() / 2; + p.channel_width = 0; + p.align = NA_CENTRE; + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); + mChannel->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP); +} + +//-------------------------------------------------------------------------- +LLAlertHandler::~LLAlertHandler() +{ +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::processNotification(const LLSD& notify) +{ + LLToast* toast = NULL; + + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "load") + { + LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); + + toast = mChannel->addToast(notification->getID(), (LLToastPanel*)alert_dialog); + if(!toast) + return; + toast->setHideButtonEnabled(false); + toast->setOnToastDestroyCallback((boost::bind(&LLAlertHandler::onToastDestroy, this, toast))); + toast->setCanFade(false); + toast->setModal(mIsModal); + } + else if (notify["sigtype"].asString() == "change") + { + LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); + mChannel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); + } + else + { + mChannel->killToastByNotificationID(notification->getID()); + } +} + +//-------------------------------------------------------------------------- + +void LLAlertHandler::onToastDestroy(LLToast* toast) +{ + toast->close(); +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::onChicletClick(void) +{ +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::onChicletClose(void) +{ +} + +//-------------------------------------------------------------------------- + + diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp new file mode 100644 index 0000000000..cde7efe901 --- /dev/null +++ b/indra/newview/llnotificationgrouphandler.cpp @@ -0,0 +1,117 @@ +/** + * @file llnotificationgrouphandler.cpp + * @brief Notification Handler Class for Group Notifications + * + * $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 "llnotificationhandler.h" +#include "lltoastgroupnotifypanel.h" +#include "llagent.h" +#include "llbottomtray.h" +#include "llviewercontrol.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLGroupHandler::LLGroupHandler(e_notification_type type, const LLSD& id) +{ + mType = type; + + // getting a Chiclet and creating params for a channel + LLBottomTray* tray = LLBottomTray::getInstance(); + mChiclet = tray->getSysWell(); + LLChannelManager::Params p; + p.chiclet = mChiclet; + p.channel_right_bound = tray->getRect().mRight - 10; //HACK: need to correctly resolve SysWell's position + p.channel_width = gSavedSettings.getS32("NotifyBoxWidth"); + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); +} + +//-------------------------------------------------------------------------- +LLGroupHandler::~LLGroupHandler() +{ +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::processNotification(const LLSD& notify) +{ + LLToast* toast = NULL; + + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") + { + LLPanel* notify_box = new LLToastGroupNotifyPanel(notification); + toast = mChannel->addToast(notification->getID(), notify_box); + if(!toast) + return; + toast->setAndStartTimer(5); + toast->setOnToastDestroyCallback((boost::bind(&LLGroupHandler::onToastDestroy, this, toast))); + mChiclet->setCounter(mChiclet->getCounter() + 1); + } + else if (notify["sigtype"].asString() == "delete") + { + mChannel->killToastByNotificationID(notification->getID()); + } +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onToastDestroy(LLToast* toast) +{ + mChiclet->setCounter(mChiclet->getCounter() - 1); + toast->close(); +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onChicletClick(void) +{ +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onChicletClose(void) +{ +} + +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- + diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h new file mode 100644 index 0000000000..7f53809c07 --- /dev/null +++ b/indra/newview/llnotificationhandler.h @@ -0,0 +1,178 @@ +/** + * @file llnotificationhandler.h + * @brief Here are implemented Notification Handling Classes. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLNOTIFICATIONHANDLER_H +#define LL_LLNOTIFICATIONHANDLER_H + + +#include "llwindow.h" + +#include "llnotifications.h" +#include "llchannelmanager.h" +#include "llchat.h" + +namespace LLNotificationsUI +{ + +// ENotificationType enumerates all possible types of notifications that could be met +// +typedef enum e_notification_type +{ + NT_NOTIFY, + NT_NOTIFYTIP, + NT_GROUPNOTIFY, + NT_IMCHAT, + NT_GROUPCHAT, + NT_NEARBYCHAT, + NT_ALERT, + NT_ALERTMODAL +} ENotificationType; + +/** + * Handler of notification events. + * This handler manages events related to toasts and chicklets. This is base class + * for chat and system notification handlers. + */ + +// LLEventHandler is a base class that specifies a common interface for all +// notification handlers. It states, that every handler must react on the follofing +// events: +// - destroying of a toast; +// - clicking on a correspondet chiclet; +// - closing of a correspondent chiclet. +// Also every handler must have the following attributes: +// - type of the notification that this handler is responsible to; +// - pointer to a correspondent chiclet; +// - pointer to a correspondent screen channel, in which all toasts of the handled notification's +// type should be displayed +// +class LLEventHandler +{ +public: + virtual ~LLEventHandler() {}; + + virtual void onToastDestroy(LLToast* toast)=0; + virtual void onChicletClick(void)=0; + virtual void onChicletClose(void)=0; + + LLScreenChannel* mChannel; + LLChiclet* mChiclet; + e_notification_type mType; +}; + +// LLSysHandler and LLChatHandler are more specific base classes +// that divide all notification handlers on to groups: +// - handlers for different system notifications (script dialogs, tips, group notices and alerts); +// - handlers for different messaging notifications (nearby chat, IM chat, group chat etc.) +/** + * Handler for system notifications. + */ +class LLSysHandler : public LLEventHandler +{ +public: + virtual ~LLSysHandler() {}; + + virtual void processNotification(const LLSD& notify)=0; +}; + +/** + * Handler for chat message notifications. + */ +class LLChatHandler : public LLEventHandler +{ +public: + virtual ~LLChatHandler() {}; + + virtual void processChat(const LLChat& chat_msg)=0; +}; + +/** + * Handler for system informational notices. + * It manages life time of tip and script notices. + */ +class LLInfoHandler : public LLSysHandler +{ +public: + LLInfoHandler(e_notification_type type, const LLSD& id); + virtual ~LLInfoHandler(); + + + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: +}; + + +/** + * Handler for group system notices. + */ +class LLGroupHandler : public LLSysHandler +{ +public: + LLGroupHandler(e_notification_type type, const LLSD& id); + virtual ~LLGroupHandler(); + + + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: +}; + +/** + * Handler for alert system notices. + */ +class LLAlertHandler : public LLSysHandler +{ +public: + LLAlertHandler(e_notification_type type, const LLSD& id); + virtual ~LLAlertHandler(); + + void setAlertMode(bool is_modal) { mIsModal = is_modal; } + + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: + bool mIsModal; +}; + +} +#endif + diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp new file mode 100644 index 0000000000..3eda0d0d14 --- /dev/null +++ b/indra/newview/llnotificationmanager.cpp @@ -0,0 +1,127 @@ +/** + * @file llnotificationmanager.cpp + * @brief Class implements a brige between the old and a new notification sistems + * + * $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 "llnotificationmanager.h" +#include "llnearbychathandler.h" + +#include "boost/bind.hpp" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLNotificationManager::LLNotificationManager() +{ + mNotifyHandlers.clear(); + init(); +} + +//-------------------------------------------------------------------------- +LLNotificationManager::~LLNotificationManager() +{ +} + +//-------------------------------------------------------------------------- +void LLNotificationManager::init() +{ + LLNotificationChannel::buildChannel("Notifications", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "notify")); + LLNotificationChannel::buildChannel("NotificationTips", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "notifytip")); + LLNotificationChannel::buildChannel("Group Notifications", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "groupnotify")); + LLNotificationChannel::buildChannel("Alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")); + LLNotificationChannel::buildChannel("AlertModal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")); + + LLNotifications::instance().getChannel("Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("NotificationTips")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("Group Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("Alerts")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("AlertModal")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + + mNotifyHandlers["notify"] = boost::shared_ptr<LLEventHandler>(new LLInfoHandler(NT_NOTIFY, LLSD())); + mNotifyHandlers["notifytip"] = mNotifyHandlers["notify"]; + mNotifyHandlers["groupnotify"] = boost::shared_ptr<LLEventHandler>(new LLGroupHandler(NT_GROUPNOTIFY, LLSD())); + mNotifyHandlers["alert"] = boost::shared_ptr<LLEventHandler>(new LLAlertHandler(NT_ALERT, LLSD())); + mNotifyHandlers["alertmodal"] = mNotifyHandlers["alert"]; + + mNotifyHandlers["nearbychat"] = boost::shared_ptr<LLEventHandler>(new LLNearbyChatHandler(NT_NEARBYCHAT, LLSD())); +} + +//-------------------------------------------------------------------------- +bool LLNotificationManager::onNotification(const LLSD& notify) +{ + LLSysHandler* handle = NULL; + + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (!notification) + return false; + + std::string notification_type = notification->getType(); + handle = dynamic_cast<LLSysHandler*>(mNotifyHandlers[notification_type].get()); + + if(!handle) + return false; + + if( notification_type == "alertmodal" ) + dynamic_cast<LLAlertHandler*>(handle)->setAlertMode(true); + + handle->processNotification(notify); + + return true; +} + +//-------------------------------------------------------------------------- +void LLNotificationManager::onChat(const LLChat& msg,ENotificationType type) +{ + switch(type) + { + case NT_NEARBYCHAT: + { + LLNearbyChatHandler* handle = dynamic_cast<LLNearbyChatHandler*>(mNotifyHandlers["nearbychat"].get()); + + if(handle) + handle->processChat(msg); + } + break; + default: //no need to handle all enum types + break; + } +} + +//-------------------------------------------------------------------------- + + + + diff --git a/indra/newview/llnotificationmanager.h b/indra/newview/llnotificationmanager.h new file mode 100644 index 0000000000..838a00ee11 --- /dev/null +++ b/indra/newview/llnotificationmanager.h @@ -0,0 +1,79 @@ +// Notification Manager Class +/** + * @file llnotificationmanager.h + * @brief Class implements a brige between the old and a new notification sistems + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLNOTIFICATIONMANAGER_H +#define LL_LLNOTIFICATIONMANAGER_H + +#include "lluictrl.h" +#include "llnotificationhandler.h" + + +#include <map> +#include <string> + +#include <boost/shared_ptr.hpp> + +namespace LLNotificationsUI { + +class LLToast; + +/** + * Responsible for registering notification handlers. + */ +class LLNotificationManager : public LLUICtrl, public LLSingleton<LLNotificationManager> +{ + typedef std::pair<std::string, LLEventHandler*> eventhandlers; +public: + LLNotificationManager(); + virtual ~LLNotificationManager(); + + //TODO: make private + // this method initialize handlers' map for different types of notifications + void init(void); + //TODO: combine processing and storage (*) + + // this method reacts on system notifications and calls an appropriate handler + bool onNotification(const LLSD& notification); + + // this method reacts on chat notifications and calls an appropriate handler + void onChat(const LLChat& msg,ENotificationType type); + +private: + //TODO (*) + std::map<std::string, boost::shared_ptr<LLEventHandler> > mNotifyHandlers; + std::map<std::string, LLChatHandler*> mChatHandlers; +}; + +} +#endif + diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp new file mode 100644 index 0000000000..78091ef05b --- /dev/null +++ b/indra/newview/llscreenchannel.cpp @@ -0,0 +1,357 @@ +/** + * @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 <algorithm> + +using namespace LLNotificationsUI; + +#define TOAST_MARGIN 5 +#define BOTTOMPANEL_MARGIN 35 +#define NAVBAR_MARGIN 60 + + +//-------------------------------------------------------------------------- +LLScreenChannel::LLScreenChannel(): mUnreadToastsPanel(NULL), + mToastAlignment(NA_BOTTOM), + mStoreToasts(true), + mOverflowToastHidden(false), + mIsHovering(false), + mControlHovering(false) +{ + setFollows(FOLLOWS_RIGHT | FOLLOWS_BOTTOM | FOLLOWS_TOP); +} + +void LLScreenChannel::init(S32 channel_position, LLView* root_view) +{ + root_view->addChild(this); + setRect( LLRect(channel_position, root_view->getRect().getHeight() - NAVBAR_MARGIN, + channel_position, root_view->getRect().mBottom + BOTTOMPANEL_MARGIN)); + +} + +//-------------------------------------------------------------------------- +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(); +} + +//-------------------------------------------------------------------------- +LLToast* LLScreenChannel::addToast(LLUUID id, LLPanel* panel) +{ + ToastElem new_toast_elem(id, panel); + + mOverflowToastHidden = false; + + mToastList.push_back(new_toast_elem); + getRootView()->addChild(new_toast_elem.toast); + 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)); + } + showToasts(); + + return new_toast_elem.toast; +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onToastFade(LLToast* toast) +{ + std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast)); + + bool destroy_toast = toast->isViewed() || !mStoreToasts || !toast->getCanBeStored(); + if(destroy_toast) + { + mToastList.erase(it); + toast->mOnToastDestroy(toast, LLSD()); + } + else + { + storeToast((*it)); + mToastList.erase(it); + } + + showToasts(); +} + +//-------------------------------------------------------------------------- + +void LLScreenChannel::storeToast(ToastElem& toast_elem) +{ + mStoredToastList.push_back(toast_elem); +} + +//-------------------------------------------------------------------------- +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::killToastByNotificationID(LLUUID id) +{ + std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id); + + if( it != mToastList.end()) + { + LLToast* toast = (*it).toast; + mToastList.erase(it); + toast->mOnToastDestroy(toast, LLSD()); + showToasts(); + } +} + +//-------------------------------------------------------------------------- +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->arrange(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()+TOAST_MARGIN, toast_rect.getWidth() ,toast_rect.getHeight()); + (*it).toast->setRect(toast_rect); + + if((*it).toast->getRect().mTop > getRect().getHeight()) + break; + + (*it).toast->setVisible(TRUE); + } + + if(it != mToastList.rend() && !mOverflowToastHidden) + { + mHiddenToastsNum = 0; + for(; it != mToastList.rend(); it++) + { + mHiddenToastsNum++; + } + createOverflowToast(bottom); + } +} + +//-------------------------------------------------------------------------- +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 + TOAST_MARGIN, toast_rect.getWidth() ,toast_rect.getHeight()); + (*it).toast->setRect(toast_rect); + + (*it).toast->setVisible(TRUE); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::showToastsTop() +{ +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::createOverflowToast(S32 bottom) +{ + LLRect toast_rect; + mUnreadToastsPanel = new LLToast(NULL); + + if(!mUnreadToastsPanel) + return; + + mUnreadToastsPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onOverflowToastHide, this)); + + LLTextBox* text_box = mUnreadToastsPanel->getChild<LLTextBox>("text"); + LLIconCtrl* icon = mUnreadToastsPanel->getChild<LLIconCtrl>("icon"); + + std::string toastsNumStr = llformat("%d", mHiddenToastsNum); + std::string text = "You have " + toastsNumStr + " new notifications."; + + text_box->setText(text); + text_box->setVisible(TRUE); + icon->setVisible(TRUE); + + toast_rect = mUnreadToastsPanel->getRect(); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+TOAST_MARGIN, toast_rect.getWidth() ,toast_rect.getHeight()); + mUnreadToastsPanel->setRect(toast_rect); + mUnreadToastsPanel->setAndStartTimer(5); + getRootView()->addChild(mUnreadToastsPanel); + mUnreadToastsPanel->setVisible(TRUE); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onOverflowToastHide() +{ + mOverflowToastHidden = true; +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::hideToastsFromScreen() +{ + if(mUnreadToastsPanel) + { + mUnreadToastsPanel->close(); + delete mUnreadToastsPanel; + mUnreadToastsPanel = NULL; + } + 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++) + { + (*it).toast->close(); + //toast->mOnToastDestroy(toast, LLSD()); //TODO: check OnToastDestroy handler for chat + } + 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(); +} + +//-------------------------------------------------------------------------- + + + + diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h new file mode 100644 index 0000000000..5a9946f772 --- /dev/null +++ b/indra/newview/llscreenchannel.h @@ -0,0 +1,136 @@ +/** + * @file llscreenchannel.h + * @brief Class implements a channel on a screen in which appropriate toasts may appear. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLSCREENCHANNEL_H +#define LL_LLSCREENCHANNEL_H + +#include "lltoast.h" + +#include <map> +#include <boost/shared_ptr.hpp> + +namespace LLNotificationsUI +{ + +typedef enum e_notification_toast_alignment +{ + NA_TOP, + NA_CENTRE, + NA_BOTTOM, +} EToastAlignment; + + +/** + * Screen channel manages toasts visibility and positioning on the screen. + */ +class LLScreenChannel : public LLUICtrl +{ +public: + LLScreenChannel(); + virtual ~LLScreenChannel(); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + LLToast* addToast(LLUUID id, LLPanel* panel); + void init(S32 channel_position, LLView* root_view); + + void killToastByNotificationID(LLUUID id); + void modifyToastByNotificationID(LLUUID id, LLPanel* panel); + + void setToastAlignment(e_notification_toast_alignment align) {mToastAlignment = align;} + + void setControlHovering(bool control) { mControlHovering = control; } + void setHovering(bool hovering) { mIsHovering = hovering; } + + void removeToastsFromChannel(); + void hideToastsFromScreen(); + + void setStoreToasts(bool store) { mStoreToasts = store; } + void loadStoredToastsToChannel(); + + void showToasts(); + + e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} + +private: + struct ToastElem + { + LLUUID id; + LLToast* toast; + ToastElem(LLUUID lluuid, LLPanel* panel) : id(lluuid) + { + toast = new LLToast(panel); + } + + ToastElem(const ToastElem& toast_elem) + { + id = toast_elem.id; + toast = toast_elem.toast; + } + + bool operator == (const LLUUID &id_op) const + { + return (id == id_op); + } + + bool operator == (LLPanel* panel_op) const + { + return (toast == panel_op); + } + }; + + void onToastHover(LLToast* toast, bool mouse_enter); + + void onToastFade(LLToast* toast); + void storeToast(ToastElem& toast_elem); + + void showToastsBottom(); + void showToastsCentre(); + void showToastsTop(); + + void createOverflowToast(S32 bottom); + void onOverflowToastHide(); + + bool mControlHovering; + bool mIsHovering; + bool mStoreToasts; + bool mOverflowToastHidden; + S32 mHiddenToastsNum; + LLToast* mUnreadToastsPanel; + std::vector<ToastElem> mToastList; + std::vector<ToastElem> mStoredToastList; + e_notification_toast_alignment mToastAlignment; + std::map<LLToast*, bool> mToastEventStack; +}; + +} +#endif diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index d8be1386c3..37262b736e 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -36,7 +36,7 @@ #include "llsidetray.h" #include "llviewerwindow.h" -#include "llaccordionpanel.h" +#include "llaccordionctrl.h" #include "llfocusmgr.h" #include "llrootview.h" @@ -113,7 +113,7 @@ bool LLSideTray::instanceCreated () return sInstance!=0; } -LLSideTrayTab::LLSideTrayTab(const Params& params):mAccordionPanel(0) +LLSideTrayTab::LLSideTrayTab(const Params& params):mAccordionCtrl(0) { mImagePath = params.image_path; @@ -131,18 +131,18 @@ void LLSideTrayTab::addPanel(LLPanel* panel) bool LLSideTrayTab::addChild(LLView* view, S32 tab_group) { - if(mAccordionPanel == 0) + if(mAccordionCtrl == 0) { - mAccordionPanel = new LLAccordionPanel(); - mAccordionPanel->setVisible(TRUE); - LLPanel::addChild(mAccordionPanel,tab_group); + mAccordionCtrl = new LLAccordionCtrl(); + mAccordionCtrl->setVisible(TRUE); + LLPanel::addChild(mAccordionCtrl,tab_group); } bool res = true; if(TAB_PANEL_CAPTION_NAME != view->getName())//skip our caption panel { - mAccordionPanel->addCollapsibleCtrl(view); + mAccordionCtrl->addCollapsibleCtrl(view); } else res = LLPanel::addChild(view,tab_group); @@ -185,17 +185,17 @@ void LLSideTrayTab::arrange(S32 width, S32 height ) offset = title_panel->getRect().getHeight(); } - LLRect sRect = mAccordionPanel->getRect(); + LLRect sRect = mAccordionCtrl->getRect(); sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); - mAccordionPanel->setRect(sRect); + mAccordionCtrl->setRect(sRect); - mAccordionPanel->setMaxWidth(sRect.getWidth()); - mAccordionPanel->arrange(); + mAccordionCtrl->setMaxWidth(sRect.getWidth()); + mAccordionCtrl->arrange(); } void LLSideTrayTab::reshape (S32 width, S32 height, BOOL called_from_parent ) { - if(!mAccordionPanel) + if(!mAccordionCtrl) return; S32 offset = 0; @@ -210,12 +210,12 @@ void LLSideTrayTab::reshape (S32 width, S32 height, BOOL called_from_parent ) - LLRect sRect = mAccordionPanel->getRect(); + LLRect sRect = mAccordionCtrl->getRect(); sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); - mAccordionPanel->setMaxWidth(sRect.getWidth()); - mAccordionPanel->reshape(sRect.getWidth(), sRect.getHeight()); + mAccordionCtrl->setMaxWidth(sRect.getWidth()); + mAccordionCtrl->reshape(sRect.getWidth(), sRect.getHeight()); - mAccordionPanel->setRect(sRect); + mAccordionCtrl->setRect(sRect); } @@ -231,7 +231,7 @@ void LLSideTrayTab::draw() void LLSideTrayTab::onOpen (const LLSD& key) { - mAccordionPanel->onOpen(key); + mAccordionCtrl->onOpen(key); } LLSideTrayTab* LLSideTrayTab::createInstance () diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h index acc7c83cd7..7487c71bfc 100644 --- a/indra/newview/llsidetray.h +++ b/indra/newview/llsidetray.h @@ -37,7 +37,7 @@ #include "string" class LLSideTray; -class LLAccordionPanel; +class LLAccordionCtrl; class LLSideTrayTab: public LLPanel { @@ -86,7 +86,7 @@ private: std::string mImagePath; std::string mDescription; - LLAccordionPanel* mAccordionPanel; + LLAccordionCtrl* mAccordionCtrl; }; diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp new file mode 100644 index 0000000000..954418f7fb --- /dev/null +++ b/indra/newview/lltoast.cpp @@ -0,0 +1,236 @@ +/** + * @file lltoast.cpp + * @brief This class implements a placeholder for any notification panel. + * + * $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 "llfocusmgr.h" +#include "lltoast.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLToast::LLToast(LLPanel* panel) : + LLFloater(), + mTimerValue(5), + mIsViewed(false), + mPanel(panel), + mCanFade(true), + mHideBtn(NULL), + mIsModal(false), + mCanBeStored(true) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_toast.xml"); + + mHideBtn = getChild<LLButton>("hide_btn"); + if(mHideBtn) + { + mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); + } + if(mPanel) + { + arrange(mPanel); + } + + // disable unnecessary Floater's functionality + setTitleVisible(FALSE); + setCanMinimize(FALSE); + setCanClose(FALSE); + setCanTearOff(FALSE); + setCanResize(FALSE); + setCanDrag(FALSE); +} + +//-------------------------------------------------------------------------- +void LLToast::setHideButtonEnabled(bool enabled) +{ + if(mHideBtn) + mHideBtn->setEnabled(enabled); +} + +//-------------------------------------------------------------------------- +LLToast::~LLToast() +{ + if(mIsModal) + { + gFocusMgr.unlockFocus(); + gFocusMgr.releaseFocusIfNeeded( this ); + } +} + +//-------------------------------------------------------------------------- +void LLToast::setAndStartTimer(F32 period) +{ + if(mCanFade) + { + mTimerValue = period; + mTimer.start(); + } +} + +//-------------------------------------------------------------------------- +bool LLToast::timerHasExpired() +{ + if (mTimer.getStarted()) + { + F32 elapsed_time = mTimer.getElapsedTimeF32(); + if (elapsed_time > 4) + { + setBackgroundOpaque(FALSE); + } + if (elapsed_time > mTimerValue) + { + return true; + } + } + return false; +} + +//-------------------------------------------------------------------------- +void LLToast::hide() +{ + setVisible(FALSE); //TODO: store in Chiclet's history + mIsViewed = false; + mTimer.stop(); + mOnFade(this, LLSD()); +} + +//-------------------------------------------------------------------------- +void LLToast::setCanFade(bool can_fade) +{ + mCanFade = can_fade; + if(!mCanFade) + mTimer.stop(); +} + +//-------------------------------------------------------------------------- +void LLToast::tick() +{ + if(mCanFade) + { + setVisible(FALSE); + mTimer.stop(); + mOnFade(this, LLSD()); + } +} + +//-------------------------------------------------------------------------- +void LLToast::arrange(LLPanel* panel) +{ + LLRect panel_rect, toast_rect; + + panel_rect = panel->getRect(); + reshape(panel_rect.getWidth(), panel_rect.getHeight()); + panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight()); + panel->setRect(panel_rect); + addChild(panel); +} + +//-------------------------------------------------------------------------- +void LLToast::draw() +{ + if(timerHasExpired()) + { + tick(); + } + + LLFloater::draw(); +} + +//-------------------------------------------------------------------------- +void LLToast::setModal(bool modal) +{ + mIsModal = modal; + if(mIsModal) + { + gFocusMgr.setMouseCapture( this ); + gFocusMgr.setTopCtrl( this ); + setFocus(TRUE); + } +} + +//-------------------------------------------------------------------------- +void LLToast::setVisible(BOOL show) +{ + if(show) + { + setBackgroundOpaque(TRUE); + } + LLPanel::setVisible(show); + if(mPanel) + { + if(!mPanel->isDead()) + { + mPanel->setVisible(show); + } + } +} + +//-------------------------------------------------------------------------- +void LLToast::onMouseEnter(S32 x, S32 y, MASK mask) +{ + mOnToastHover(this, MOUSE_ENTER); + + setVisibleAndFrontmost(); + setBackgroundOpaque(TRUE); + if(mCanFade && !mIsViewed) + { + mTimer.stop(); + } + + sendChildToFront(mHideBtn); + if(mHideBtn && mHideBtn->getEnabled()) + mHideBtn->setVisible(TRUE); + mOnMousEnter(this, LLSD()); +} + +//-------------------------------------------------------------------------- +void LLToast::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mOnToastHover(this, MOUSE_LEAVE); + + if(mCanFade && !mIsViewed) + { + mTimer.start(); + } + if(mHideBtn && mHideBtn->getEnabled()) + { + if( mHideBtn->getRect().pointInRect(x, y) ) + return; + mHideBtn->setVisible(FALSE); + } +} + +//-------------------------------------------------------------------------- + + + + diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h new file mode 100644 index 0000000000..2e2ac5b36c --- /dev/null +++ b/indra/newview/lltoast.h @@ -0,0 +1,114 @@ +/** + * @file lltoast.h + * @brief This class implements a placeholder for any notification panel. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLTOAST_H +#define LL_LLTOAST_H + + +#include "llpanel.h" +#include "llfloater.h" +#include "lltimer.h" +#include "lldate.h" + +#define MOUSE_LEAVE false +#define MOUSE_ENTER true + +namespace LLNotificationsUI +{ + +/** + * Represents toast pop-up. + * This is a parent view for all toast panels. + */ +class LLToast : public LLFloater +{ +public: + LLToast(LLPanel* panel); + virtual ~LLToast(); + + // + bool isViewed() { return mIsViewed; } + + void setCanFade(bool can_fade); + + void setHideButtonEnabled(bool enabled); + + void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } + bool getCanBeStored() { return mCanBeStored; } + // + void setAndStartTimer(F32 period); + // + void resetTimer() { mTimer.start(); } + void close() { die(); } + virtual void draw(); + virtual void setVisible(BOOL show); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual void hide(); + LLPanel* getPanel() { return mPanel; } + void arrange(LLPanel* panel); + void setModal(bool modal); + + + // Registers callbacks for events + boost::signals2::connection setOnFadeCallback(commit_callback_t cb) { return mOnFade.connect(cb); } + boost::signals2::connection setOnMouseEnterCallback(commit_callback_t cb) { return mOnMousEnter.connect(cb); } + boost::signals2::connection setOnToastDestroyCallback(commit_callback_t cb) { return mOnToastDestroy.connect(cb); } + typedef boost::function<void (LLToast* toast, bool mouse_enter)> toast_hover_check_callback_t; + typedef boost::signals2::signal<void (LLToast* toast, bool mouse_enter)> toast_hover_check_signal_t; + toast_hover_check_signal_t mOnToastHover; + boost::signals2::connection setOnToastHoverCallback(toast_hover_check_callback_t cb) { return mOnToastHover.connect(cb); } + + commit_signal_t mOnFade; + commit_signal_t mOnMousEnter; + commit_signal_t mOnToastDestroy; + +private: + + bool timerHasExpired(); + void tick(); + + LLTimer mTimer; + F32 mTimerValue; + + LLPanel* mPanel; + LLButton* mHideBtn; + + LLColor4 mBgColor; + bool mIsViewed; + bool mCanFade; + bool mIsModal; + bool mCanBeStored; +}; + +} +#endif diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp new file mode 100644 index 0000000000..afaa01a77a --- /dev/null +++ b/indra/newview/lltoastalertpanel.cpp @@ -0,0 +1,474 @@ +/** + * @file lltoastalertpanel.cpp + * @brief Panel for alert toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 "linden_common.h" + +#include "llboost.h" + +#include "lltoastalertpanel.h" +#include "llfontgl.h" +#include "lltextbox.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llkeyboard.h" +#include "llfocusmgr.h" +#include "lliconctrl.h" +#include "llui.h" +#include "lllineeditor.h" +#include "lluictrlfactory.h" +#include "llnotifications.h" +#include "llfunctorregistry.h" + +const S32 MAX_ALLOWED_MSG_WIDTH = 400; +const F32 DEFAULT_BUTTON_DELAY = 0.5f; +const S32 MSG_PAD = 8; + +/*static*/ LLControlGroup* LLToastAlertPanel::sSettings = NULL; +/*static*/ LLToastAlertPanel::URLLoader* LLToastAlertPanel::sURLLoader; + +//----------------------------------------------------------------------------- +// Private methods + +static const S32 VPAD = 16; +static const S32 HPAD = 25; +static const S32 BTN_HPAD = 8; + +LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) + : LLToastPanel(notification), + mDefaultOption( 0 ), + mCheck(NULL), + mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), + mLabel(notification->getName()), + mLineEditor(NULL) +{ + const LLFontGL* font = LLFontGL::getFontSansSerif(); + const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); + const S32 EDITOR_HEIGHT = 20; + + LLNotificationFormPtr form = mNotification->getForm(); + std::string edit_text_name; + std::string edit_text_contents; + bool is_password = false; + + LLToastPanel::setBackgroundVisible(FALSE); + LLToastPanel::setBackgroundOpaque(TRUE); + + + typedef std::vector<std::pair<std::string, std::string> > options_t; + options_t supplied_options; + + // for now, get LLSD to iterator over form elements + LLSD form_sd = form->asLLSD(); + + S32 option_index = 0; + for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) + { + std::string type = (*it)["type"].asString(); + if (type == "button") + { + if((*it)["default"]) + { + mDefaultOption = option_index; + } + + supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString())); + + ButtonData data; + if (option_index == mNotification->getURLOption()) + { + data.mURL = mNotification->getURL(); + data.mURLExternal = mNotification->getURLOpenExternally(); + } + + mButtonData.push_back(data); + option_index++; + } + else if (type == "text") + { + edit_text_contents = (*it)["value"].asString(); + edit_text_name = (*it)["name"].asString(); + } + else if (type == "password") + { + edit_text_contents = (*it)["value"].asString(); + edit_text_name = (*it)["name"].asString(); + is_password = true; + } + } + + // Buttons + options_t options; + if (supplied_options.empty()) + { + options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton"))); + + // add data for ok button. + ButtonData ok_button; + mButtonData.push_back(ok_button); + mDefaultOption = 0; + } + else + { + options = supplied_options; + } + + S32 num_options = options.size(); + + // Calc total width of buttons + S32 button_width = 0; + S32 sp = font->getWidth(std::string("OO")); + for( S32 i = 0; i < num_options; i++ ) + { + S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; + button_width = llmax( w, button_width ); + } + S32 btn_total_width = button_width; + if( num_options > 1 ) + { + btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD); + } + + // Message: create text box using raw string, as text has been structure deliberately + // Use size of created text box to generate dialog box size + std::string msg = mNotification->getMessage(); + llwarns << "Alert: " << msg << llendl; + LLTextBox::Params params; + params.name("Alert message"); + params.font(font); + params.tab_stop(false); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + + LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params); + // Compute max allowable height for the dialog text, so we can allocate + // space before wrapping the text to fit. + S32 max_allowed_msg_height = + gFloaterView->getRect().getHeight() + - LINE_HEIGHT // title bar + - 3*VPAD - BTN_HEIGHT; + msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height ); + msg_box->setWrappedText(msg, (F32)MAX_ALLOWED_MSG_WIDTH); + msg_box->reshapeToFitText(); + + const LLRect& text_rect = msg_box->getRect(); + S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD; + S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT; + + if (hasTitleBar()) + { + dialog_height += LINE_HEIGHT; // room for title bar + } + + // it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it + if (!edit_text_name.empty()) + { + dialog_height += EDITOR_HEIGHT + VPAD; + dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f)); + } + + if (mCaution) + { + // Make room for the caution icon. + dialog_width += 32 + HPAD; + } + + LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); + + S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD; + S32 msg_x = HPAD; + if (hasTitleBar()) + { + msg_y -= LINE_HEIGHT; // room for title + } + + static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor"); + static LLUIColor alert_text_color = LLUIColorTable::instance().getColor("AlertTextColor"); + if (mCaution) + { + LLIconCtrl::Params params; + params.name("icon"); + params.rect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32)); + params.mouse_opaque(false); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + params.tab_stop(false); + LLIconCtrl * icon = LLUICtrlFactory::create<LLIconCtrl> (params); + icon->setValue ("notify_caution_icon.tga"); + icon->setMouseOpaque(FALSE); + LLToastPanel::addChild(icon); + msg_x += 32 + HPAD; + msg_box->setColor( alert_caution_text_color ); + } + else + { + msg_box->setColor( alert_text_color ); + } + + LLRect rect; + rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); + msg_box->setRect( rect ); + LLToastPanel::addChild(msg_box); + + // Buttons + S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2; + + for( S32 i = 0; i < num_options; i++ ) + { + LLRect button_rect; + button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); + + LLButton::Params p; + p.name(options[i].first); + p.rect(button_rect); + p.click_callback.function(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i)); + p.font(font); + p.label(options[i].second); + + LLButton* btn = LLUICtrlFactory::create<LLButton>(p); + mButtonData[i].mButton = btn; + + LLToastPanel::addChild(btn); + + if( i == mDefaultOption ) + { + btn->setFocus(TRUE); + } + + button_left += button_width + BTN_HPAD; + } + + // (Optional) Edit Box + if (!edit_text_name.empty()) + { + S32 y = VPAD + BTN_HEIGHT + VPAD/2; + + LLLineEditor::Params params; + params.name(edit_text_name); + params.rect(LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y)); + params.default_text(edit_text_contents); + params.max_length_bytes(STD_STRING_STR_LEN); + mLineEditor = LLUICtrlFactory::create<LLLineEditor> (params); + + // make sure all edit keys get handled properly (DEV-22396) + mLineEditor->setHandleEditKeysDirectly(TRUE); + + LLToastPanel::addChild(mLineEditor); + } + + if (mLineEditor) + { + mLineEditor->setDrawAsterixes(is_password); + + setEditTextArgs(notification->getSubstitutions()); + } + + std::string ignore_label; + + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); + } + + gFloaterView->adjustToFitScreen(this, FALSE); + LLFloater::setFocus(TRUE); + if (mLineEditor) + { + mLineEditor->setFocus(TRUE); + mLineEditor->selectAll(); + } + if(mDefaultOption >= 0) + { + // delay before enabling default button + mDefaultBtnTimer.start(); + mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); + } +} + +bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control ) +{ + const LLFontGL* font = LLFontGL::getFontSansSerif(); + const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); + + // Extend dialog for "check next time" + S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD; + S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16; + max_msg_width = llmax(max_msg_width, check_width); + S32 dialog_width = max_msg_width + 2 * HPAD; + + S32 dialog_height = LLToastPanel::getRect().getHeight(); + dialog_height += LINE_HEIGHT; + dialog_height += LINE_HEIGHT / 2; + + LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); + + S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; + + LLCheckBoxCtrl::Params p; + p.name("check"); + p.rect.left(msg_x).bottom(VPAD+BTN_HEIGHT+LINE_HEIGHT/2).width(max_msg_width).height(LINE_HEIGHT); + p.label(check_title); + p.font(font); + p.commit_callback.function(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1)); + mCheck = LLUICtrlFactory::create<LLCheckBoxCtrl>(p); + LLToastPanel::addChild(mCheck); + + return true; +} + +void LLToastAlertPanel::setVisible( BOOL visible ) +{ + LLToastPanel::setVisible( visible ); + + if( visible ) + { + make_ui_sound("UISndAlert"); + } +} + +void LLToastAlertPanel::onClose(bool app_quitting) +{ + LLFloater::onClose(app_quitting); +} + +LLToastAlertPanel::~LLToastAlertPanel() +{ +} + +BOOL LLToastAlertPanel::hasTitleBar() const +{ + return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title + || isMinimizeable() + || isCloseable(); +} + +BOOL LLToastAlertPanel::handleKeyHere(KEY key, MASK mask ) +{ + if( KEY_RETURN == key && mask == MASK_NONE ) + { + return TRUE; + } + else if (KEY_RIGHT == key) + { + LLToastPanel::focusNextItem(FALSE); + return TRUE; + } + else if (KEY_LEFT == key) + { + LLToastPanel::focusPrevItem(FALSE); + return TRUE; + } + else if (KEY_TAB == key && mask == MASK_NONE) + { + LLToastPanel::focusNextItem(FALSE); + return TRUE; + } + else if (KEY_TAB == key && mask == MASK_SHIFT) + { + LLToastPanel::focusPrevItem(FALSE); + return TRUE; + } + else + { + return TRUE; + } +} + +// virtual +void LLToastAlertPanel::draw() +{ + // if the default button timer has just expired, activate the default button + if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted()) + { + mDefaultBtnTimer.stop(); // prevent this block from being run more than once + LLToastPanel::setDefaultBtn(mButtonData[mDefaultOption].mButton); + } + + static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); + static LLUICachedControl<S32> shadow_lines ("DropShadowFloater"); + + gl_drop_shadow( 0, LLToastPanel::getRect().getHeight(), LLToastPanel::getRect().getWidth(), 0, + shadow_color, shadow_lines); + + LLToastPanel::draw(); +} + +void LLToastAlertPanel::setEditTextArgs(const LLSD& edit_args) +{ + if (mLineEditor) + { + std::string msg = mLineEditor->getText(); + mLineEditor->setText(msg); + } + else + { + llwarns << "LLToastAlertPanel::setEditTextArgs called on dialog with no line editor" << llendl; + } +} + +void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button ) +{ + ButtonData* button_data = &mButtonData[button]; + + LLSD response = mNotification->getResponseTemplate(); + if (mLineEditor) + { + response[mLineEditor->getName()] = mLineEditor->getValue(); + } + response[button_data->mButton->getName()] = true; + + // If we declared a URL and chose the URL option, go to the url + if (!button_data->mURL.empty() && sURLLoader != NULL) + { + sURLLoader->load(button_data->mURL, button_data->mURLExternal); + } + + mNotification->respond(response); // new notification reponse + closeFloater(); // deletes self +} + +void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl) +{ + // checkbox sometimes means "hide and do the default" and + // other times means "warn me again". Yuck. JC + BOOL check = ctrl->getValue().asBoolean(); + if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h new file mode 100644 index 0000000000..f714630c77 --- /dev/null +++ b/indra/newview/lltoastalertpanel.h @@ -0,0 +1,124 @@ +/** + * @file lltoastalertpanel.h + * @brief Panel for alert toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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_TOASTALERTPANEL_H +#define LL_TOASTALERTPANEL_H + +#include "lltoastpanel.h" +#include "llfloater.h" +#include "llui.h" +#include "llnotifications.h" + +class LLButton; +class LLCheckBoxCtrl; +class LLAlertDialogTemplate; +class LLLineEditor; + +/** + * Toast panel for alert notification. + * Alerts notifications doesn't require user interaction. + * + * Replaces class LLAlertDialog. + * https://wiki.lindenlab.com/mediawiki/index.php?title=LLAlertDialog&oldid=81388 + */ + +class LLToastAlertPanel + : public LLToastPanel, + public LLFloater +{ +public: + typedef bool (*display_callback_t)(S32 modal); + + class URLLoader + { + public: + virtual void load(const std::string& url, bool force_open_externally = 0 ) = 0; + virtual ~URLLoader() {} + }; + + static void setURLLoader(URLLoader* loader) + { + sURLLoader = loader; + } + +public: + // User's responsibility to call show() after creating these. + LLToastAlertPanel( LLNotificationPtr notep, bool is_modal ); + + virtual BOOL handleKeyHere(KEY key, MASK mask ); + + virtual void draw(); + virtual void setVisible( BOOL visible ); + virtual void onClose(bool app_quitting); + + bool setCheckBox( const std::string&, const std::string& ); + void setCaution(BOOL val = TRUE) { mCaution = val; } + // If mUnique==TRUE only one copy of this message should exist + void setUnique(BOOL val = TRUE) { mUnique = val; } + void setEditTextArgs(const LLSD& edit_args); + + void onClickIgnore(LLUICtrl* ctrl); + void onButtonPressed(const LLSD& data, S32 button); + +private: + static std::map<std::string, LLToastAlertPanel*> sUniqueActiveMap; + + virtual ~LLToastAlertPanel(); + // No you can't kill it. It can only kill itself. + + // Does it have a readable title label, or minimize or close buttons? + BOOL hasTitleBar() const; + +private: + static URLLoader* sURLLoader; + static LLControlGroup* sSettings; + + struct ButtonData + { + LLButton* mButton; + std::string mURL; + U32 mURLExternal; + }; + std::vector<ButtonData> mButtonData; + + S32 mDefaultOption; + LLCheckBoxCtrl* mCheck; + BOOL mCaution; + BOOL mUnique; + LLUIString mLabel; + LLFrameTimer mDefaultBtnTimer; + // For Dialogs that take a line as text as input: + LLLineEditor* mLineEditor; + +}; + +#endif // LL_TOASTALERTPANEL_H diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp new file mode 100644 index 0000000000..83c25ddc77 --- /dev/null +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -0,0 +1,137 @@ +/** + * @file lltoastgroupnotifypanel.cpp + * @brief Panel for group notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 "lltoastgroupnotifypanel.h" + +#include "llfocusmgr.h" + +#include "llbutton.h" +#include "lliconctrl.h" +#include "llnotify.h" +#include "lltextbox.h" +#include "llviewertexteditor.h" +#include "lluiconstants.h" +#include "llui.h" +#include "llviewercontrol.h" +#include "llfloatergroupinfo.h" +#include "lltrans.h" +#include "llinitparam.h" + +#include "llglheaders.h" +#include "llagent.h" +#include "llavatariconctrl.h" + +LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification) +: LLToastPanel(notification), + mInventoryOffer(NULL) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_notify.xml"); + const LLSD& payload = notification->getPayload(); + LLGroupData groupData; + if (!gAgent.getGroupData(payload["group_id"].asUUID(),groupData)) + { + llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; + } + + //group icon + LLIconCtrl* pGroupIcon = getChild<LLIconCtrl>("group_icon", TRUE); + pGroupIcon->setValue(groupData.mInsigniaID); + + //header title + const std::string& from_name = payload["sender_name"].asString(); + std::stringstream from; + from << from_name << "/" << groupData.mName; + LLTextBox* pTitleText = this->getChild<LLTextBox>("title", TRUE, FALSE); + pTitleText->setValue(from.str()); + + //message body + const std::string& message = payload["message"].asString(); + LLTextEditor* pMessageText = getChild< LLTextEditor>("message", TRUE, FALSE); + pMessageText->setEnabled(FALSE); + pMessageText->setTakesFocus(FALSE); + pMessageText->setValue(message); + + //attachment + BOOL hasInventory = payload["inventory_offer"].isDefined(); + LLTextBox * pAttachLink = getChild<LLTextBox>("attachment", TRUE, FALSE); + pAttachLink->setVisible(hasInventory); + if (hasInventory) { + pAttachLink->setValue(payload["inventory_name"]); + mInventoryOffer = new LLOfferInfo(payload["inventory_offer"]); + childSetActionTextbox("attachment", boost::bind( + &LLToastGroupNotifyPanel::onClickAttachment, this)); + } + + //ok button + LLButton* pOkBtn = getChild<LLButton>("btn_ok", TRUE, FALSE); + pOkBtn->setClickedCallback((boost::bind(&LLToastGroupNotifyPanel::onClickOk, this))); + setDefaultBtn(pOkBtn); +} + + +// virtual +LLToastGroupNotifyPanel::~LLToastGroupNotifyPanel() +{ +} + +void LLToastGroupNotifyPanel::close() +{ + // The group notice dialog may be an inventory offer. + // If it has an inventory save button and that button is still enabled + // Then we need to send the inventory declined message + if(mInventoryOffer != NULL) + { + mInventoryOffer->forceResponse(IOR_DECLINE); + mInventoryOffer = NULL; + } + + die(); +} + +void LLToastGroupNotifyPanel::onClickOk() +{ + LLSD response = mNotification->getResponseTemplate(); + mNotification->respond(response); + close(); +} + +void LLToastGroupNotifyPanel::onClickAttachment() +{ + mInventoryOffer->forceResponse(IOR_ACCEPT); + + mInventoryOffer = NULL; + + LLTextBox * pAttachLink = getChild<LLTextBox>("attachment", TRUE, FALSE); + pAttachLink->setVisible(FALSE); +} diff --git a/indra/newview/lltoastgroupnotifypanel.h b/indra/newview/lltoastgroupnotifypanel.h new file mode 100644 index 0000000000..f00f840e94 --- /dev/null +++ b/indra/newview/lltoastgroupnotifypanel.h @@ -0,0 +1,82 @@ +/** + * @file lltoastgroupnotifypanel.h + * @brief Panel for group notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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_LLGROUPNOTIFY_H +#define LL_LLGROUPNOTIFY_H + +#include "llfontgl.h" +#include "lltoastpanel.h" +#include "lldarray.h" +#include "lltimer.h" +#include "llviewermessage.h" +#include "llnotifications.h" + +class LLButton; + +/** + * Toast panel for group notification. + * + * Replaces class LLGroupNotifyBox. + */ +class LLToastGroupNotifyPanel +: public LLToastPanel +{ +public: + void close(); + + static bool onNewNotification(const LLSD& notification); + + + // Non-transient messages. You can specify non-default button + // layouts (like one for script dialogs) by passing various + // numbers in for "layout". + LLToastGroupNotifyPanel(LLNotificationPtr& notification); + + /*virtual*/ ~LLToastGroupNotifyPanel(); +protected: + void onClickOk(); + void onClickAttachment(); +private: + + LLButton* mSaveInventoryBtn; + + LLUUID mGroupID; + LLOfferInfo* mInventoryOffer; +}; + +// This view contains the stack of notification windows. +//extern LLView* gGroupNotifyBoxView; + +const S32 GROUP_LAYOUT_DEFAULT = 0; +const S32 GROUP_LAYOUT_SCRIPT_DIALOG = 1; + +#endif diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp new file mode 100644 index 0000000000..c43618d330 --- /dev/null +++ b/indra/newview/lltoastnotifypanel.cpp @@ -0,0 +1,435 @@ +/** + * @file lltoastnotifypanel.cpp + * @brief Panel for notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 "lltoastnotifypanel.h" +#include "llviewercontrol.h" +#include "lluiconstants.h" +#include "llrect.h" +#include "lliconctrl.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "lldbstrings.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "lltrans.h" +#include "lloverlaybar.h" + + +const S32 BOTTOM_PAD = VPAD * 3; + +//static +const LLFontGL* LLToastNotifyPanel::sFont = NULL; +const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; + +LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification) { + mIsTip = notification->getType() == "notifytip"; + mNumOptions = 0; + mNumButtons = 0; + mIsScriptDialog = (notification->getName() == "ScriptDialog" + || notification->getName() == "ScriptDialogGroup"); + mAddedDefaultBtn = false; + + // clicking on a button does not steal current focus + setIsChrome(TRUE); + + // class init + if (!sFont) + { + sFont = LLFontGL::getFontSansSerif(); + sFontSmall = LLFontGL::getFontSansSerifSmall(); + } + + // setup paramaters + mMessage = notification->getMessage(); + + // initialize + setFocusRoot(!mIsTip); + + // caution flag can be set explicitly by specifying it in the + // notification payload, or it can be set implicitly if the + // notify xml template specifies that it is a caution + // + // tip-style notification handle 'caution' differently - + // they display the tip in a different color + mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; + + LLNotificationFormPtr form(notification->getForm()); + + mNumOptions = form->getNumElements(); + + LLRect rect = mIsTip ? getNotifyTipRect(mMessage) + : getNotifyRect(mNumOptions, mIsScriptDialog, mIsCaution); + setRect(rect); + setFollows(mIsTip ? (FOLLOWS_BOTTOM|FOLLOWS_RIGHT) : (FOLLOWS_TOP|FOLLOWS_RIGHT)); + setBackgroundVisible(FALSE); + setBackgroundOpaque(TRUE); + + LLIconCtrl* icon; + LLTextEditor* text; + + const S32 TOP = getRect().getHeight() - (mIsTip ? (S32)sFont->getLineHeight() : 32); + const S32 BOTTOM = (S32)sFont->getLineHeight(); + S32 x = HPAD + HPAD; + S32 y = TOP; + + LLIconCtrl::Params common_params; + common_params.rect(LLRect(x, y, x+32, TOP-32)); + common_params.mouse_opaque(false); + common_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + common_params.tab_stop(false); + + if (mIsTip) + { + // use the tip notification icon + common_params.image(LLUI::getUIImage("notify_tip_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + else if (mIsCaution) + { + // use the caution notification icon + common_params.image(LLUI::getUIImage("notify_caution_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + else + { + // use the default notification icon + common_params.image(LLUI::getUIImage("notify_box_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + + icon->setMouseOpaque(FALSE); + addChild(icon); + + x += HPAD + HPAD + 32; + + // add a caution textbox at the top of a caution notification + LLTextBox* caution_box = NULL; + if (mIsCaution && !mIsTip) + { + S32 caution_height = ((S32)sFont->getLineHeight() * 2) + VPAD; + LLTextBox::Params params; + params.name("caution_box"); + params.rect(LLRect(x, y, getRect().getWidth() - 2, caution_height)); + params.font(sFont); + params.mouse_opaque(false); + params.font.style("BOLD"); + params.text_color(LLUIColorTable::instance().getColor("NotifyCautionWarnColor")); + params.background_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor")); + params.border_visible(false); + caution_box = LLUICtrlFactory::create<LLTextBox> (params); + caution_box->setWrappedText(notification->getMessage()); + + addChild(caution_box); + + // adjust the vertical position of the next control so that + // it appears below the caution textbox + y = y - caution_height; + } + else + { + + const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); + + // Tokenization on \n is handled by LLTextBox + + const S32 MAX_LENGTH = 512 + 20 + + DB_FIRST_NAME_BUF_SIZE + + DB_LAST_NAME_BUF_SIZE + + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. + + LLTextEditor::Params params; + params.name("box"); + params.rect(LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16)); + params.max_text_length(MAX_LENGTH); + params.default_text(mMessage); + params.font(sFont); + params.allow_embedded_items(false); + params.word_wrap(true); + params.tab_stop(false); + params.mouse_opaque(false); + params.bg_readonly_color(LLColor4::transparent); + params.text_readonly_color(LLUIColorTable::instance().getColor("NotifyTextColor")); + params.takes_non_scroll_clicks(false); + params.hide_scrollbar(true); + params.enabled(false); + params.hide_border(true); + text = LLUICtrlFactory::create<LLTextEditor> (params); + addChild(text); + } + + if (mIsTip) + { + // TODO: Make a separate archive for these. + LLChat chat(mMessage); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChatHistory(chat); + } + else + { + LLButton::Params p; + p.name(std::string("next")); + p.rect(LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD)); + p.image_selected.name("notify_next.png"); + p.image_unselected.name("notify_next.png"); + p.font(sFont); + p.scale_image(true); + p.tool_tip(LLTrans::getString("next").c_str()); + + for (S32 i = 0; i < mNumOptions; i++) + { + + LLSD form_element = form->getElement(i); + if (form_element["type"].asString() != "button") + { + continue; + } + + addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean()); + } + + if (mNumButtons == 0) + { + addButton("OK", LLTrans::getString("ok"), FALSE, TRUE); + mAddedDefaultBtn = true; + } + + + } +} + +LLToastNotifyPanel::~LLToastNotifyPanel() { + std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer()); +} + + +LLRect LLToastNotifyPanel::getNotifyRect(S32 num_options, BOOL mIsScriptDialog, BOOL is_caution) +{ + S32 notify_height = gSavedSettings.getS32("NotifyBoxHeight"); + if (is_caution) + { + // make caution-style dialog taller to accomodate extra text, + // as well as causing the accept/decline buttons to be drawn + // in a different position, to help prevent "quick-click-through" + // of many permissions prompts + notify_height = gSavedSettings.getS32("PermissionsCautionNotifyBoxHeight"); + } + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + + const S32 TOP = getRect().getHeight(); + const S32 RIGHT =getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + if (num_options < 1) + { + num_options = 1; + } + + // Add two "blank" option spaces. + if (mIsScriptDialog) + { + num_options += 2; + } + + S32 additional_lines = (num_options-1) / 3; + + notify_height += additional_lines * (BTN_HEIGHT + VPAD); + + return LLRect(LEFT, TOP, RIGHT, TOP-notify_height); +} + +// static +LLRect LLToastNotifyPanel::getNotifyTipRect(const std::string &utf8message) +{ + S32 line_count = 1; + LLWString message = utf8str_to_wstring(utf8message); + S32 message_len = message.length(); + + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + // Make room for the icon area. + const S32 text_area_width = NOTIFY_WIDTH - HPAD * 4 - 32; + + const llwchar* wchars = message.c_str(); + const llwchar* start = wchars; + const llwchar* end; + S32 total_drawn = 0; + BOOL done = FALSE; + + do + { + line_count++; + + for (end=start; *end != 0 && *end != '\n'; end++) + ; + + if( *end == 0 ) + { + end = wchars + message_len; + done = TRUE; + } + + S32 remaining = end - start; + while( remaining ) + { + S32 drawn = sFont->maxDrawableChars( start, (F32)text_area_width, remaining, TRUE ); + + if( 0 == drawn ) + { + drawn = 1; // Draw at least one character, even if it doesn't all fit. (avoids an infinite loop) + } + + total_drawn += drawn; + start += drawn; + remaining -= drawn; + + if( total_drawn < message_len ) + { + if( (wchars[ total_drawn ] != '\n') ) + { + // wrap because line was too long + line_count++; + } + } + else + { + done = TRUE; + } + } + + total_drawn++; // for '\n' + end++; + start = end; + } while( !done ); + + const S32 MIN_NOTIFY_HEIGHT = 72; + const S32 MAX_NOTIFY_HEIGHT = 600; + S32 notify_height = llceil((F32) (line_count+1) * sFont->getLineHeight()); + if(gOverlayBar) + { + notify_height += gOverlayBar->getBoundingRect().mTop; + } + else + { + // *FIX: this is derived from the padding caused by the + // rounded rects, shouldn't be a const here. + notify_height += 10; + } + notify_height += VPAD; + notify_height = llclamp(notify_height, MIN_NOTIFY_HEIGHT, MAX_NOTIFY_HEIGHT); + + const S32 RIGHT = getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + return LLRect(LEFT, notify_height, RIGHT, 0); +} + + +// static +void LLToastNotifyPanel::onClickButton(void* data) +{ + InstanceAndS32* self_and_button = (InstanceAndS32*)data; + LLToastNotifyPanel* self = self_and_button->mSelf; + std::string button_name = self_and_button->mButtonName; + + LLSD response = self->mNotification->getResponseTemplate(); + if (!self->mAddedDefaultBtn && !button_name.empty()) + { + response[button_name] = true; + } + self->mNotification->respond(response); +} + +// virtual +LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::string& label, BOOL is_option, BOOL is_default) +{ + // make caution notification buttons slightly narrower + // so that 3 of them can fit without overlapping the "next" button + S32 btn_width = mIsCaution? 84 : 90; + + LLRect btn_rect; + LLButton* btn; + S32 btn_height= BTN_HEIGHT; + const LLFontGL* font = sFont; + S32 ignore_pad = 0; + S32 button_index = mNumButtons; + S32 index = button_index; + S32 x = (HPAD * 4) + 32; + + if (mIsScriptDialog) + { + // Add two "blank" option spaces, before the "Ignore" button + index = button_index + 2; + if (button_index == 0) + { + // Ignore button is smaller, less wide + btn_height = BTN_HEIGHT_SMALL; + font = sFontSmall; + ignore_pad = 10; + } + } + + btn_rect.setOriginAndSize(x + (index % 3) * (btn_width+HPAD+HPAD) + ignore_pad, + BOTTOM_PAD + (index / 3) * (BTN_HEIGHT+VPAD), + btn_width - 2*ignore_pad, + btn_height); + + InstanceAndS32* userdata = new InstanceAndS32; + userdata->mSelf = this; + userdata->mButtonName = is_option ? name : ""; + + mBtnCallbackData.push_back(userdata); + + LLButton::Params p; + p.name(name); + p.label(label); + p.rect(btn_rect); + p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata)); + p.font(font); + if (mIsCaution) + { + p.image_color(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + p.image_color_disabled(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + } + btn = LLUICtrlFactory::create<LLButton>(p); + + + addChild(btn, -1); + + if (is_default) + { + setDefaultBtn(btn); + } + + mNumButtons++; + return btn; +} diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h new file mode 100644 index 0000000000..df58c06f25 --- /dev/null +++ b/indra/newview/lltoastnotifypanel.h @@ -0,0 +1,86 @@ +/** + * @file lltoastnotifypanel.h + * @brief Panel for notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 LLTOASTNOTIFYPANEL_H_ +#define LLTOASTNOTIFYPANEL_H_ + +#include "llpanel.h" +#include "llfontgl.h" +#include "llnotifications.h" +#include "llbutton.h" +#include "lltoastpanel.h" + + +/** + * Toast panel for notification. + * Notification panel should be used for notifications that require a response from the user. + * + * Replaces class LLNotifyBox. + */ +class LLToastNotifyPanel: public LLToastPanel { +public: + LLToastNotifyPanel(LLNotificationPtr&); + virtual ~LLToastNotifyPanel(); + bool isTip() {return mIsTip;} + static LLToastNotifyPanel * buildNotifyPanel(LLNotificationPtr notification); + +protected: + LLButton* addButton(std::string const &name, const std::string& label, BOOL is_option, BOOL is_default); + // Used for callbacks + struct InstanceAndS32 + { + LLToastNotifyPanel* mSelf; + std::string mButtonName; + }; + std::vector<InstanceAndS32*> mBtnCallbackData; + +private: + + // Returns the rect, relative to gNotifyView, where this + // notify box should be placed. + LLRect getNotifyRect(S32 num_options, BOOL layout_script_dialog, BOOL is_caution); + LLRect getNotifyTipRect(const std::string &message); + // internal handler for button being clicked + static void onClickButton(void* data); + bool mIsTip; + bool mAddedDefaultBtn; + bool mIsScriptDialog; + bool mIsCaution; // is this a caution notification? + std::string mMessage; + S32 mNumOptions; + S32 mNumButtons; + + static const LLFontGL* sFont; + static const LLFontGL* sFontSmall; +}; + +#endif /* LLTOASTNOTIFYPANEL_H_ */ diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp new file mode 100644 index 0000000000..79a7d45bbf --- /dev/null +++ b/indra/newview/lltoastpanel.cpp @@ -0,0 +1,42 @@ +/** + * @file lltoastpanel.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $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" + +#include "lltoastpanel.h" + +LLToastPanel::LLToastPanel(LLNotificationPtr& notification) { + mNotification = notification; +} + +LLToastPanel::~LLToastPanel() { +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h new file mode 100644 index 0000000000..82e2a74672 --- /dev/null +++ b/indra/newview/lltoastpanel.h @@ -0,0 +1,53 @@ +/** + * @file lltoastpanel.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_LLTOASTPANEL_H +#define LL_LLTOASTPANEL_H + +#include "llpanel.h" +#include "llnotifications.h" + +/** + * Base class for all panels that can be added to the toast. + * All toast panels should contain necessary logic for representing certain notification + * but shouldn't contain logic related to this panel lifetime control and positioning + * on the parent view. + */ +class LLToastPanel: public LLPanel { +public: + LLToastPanel(LLNotificationPtr&); + virtual ~LLToastPanel() = 0; +protected: + LLNotificationPtr mNotification; +}; + +#endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 403b710459..5c38be86d5 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -81,7 +81,7 @@ #include "llfloaterinventory.h" #include "llmediaremotectrl.h" #include "llmoveview.h" -#include "llnearbychathistory.h" +#include "llnearbychat.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" @@ -109,6 +109,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>); LLFloaterReg::add("chat", "floater_chat_history.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChat>); + LLFloaterReg::add("nearby_chat", "floater_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>); LLFloaterReg::add("communicate", "floater_chatterbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatterBox>); LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); LLFloaterReg::add("contacts", "floater_my_friends.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyFriends>); @@ -134,7 +135,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("mini_inspector", "panel_mini_inspector.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMiniInspector>); LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); - LLFloaterReg::add("nearby_chat", "floater_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChatHistory>); + LLFloaterReg::add("nearby_chat", "floater_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>); LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index bfc258506f..abaac42874 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -43,6 +43,8 @@ #include "llviewertexture.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" #include "llviewerwindow.h" #include "llversionviewer.h" #include "llviewertexturelist.h" diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e46748edf0..8f1b105ba6 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -143,6 +143,9 @@ #include "llwindebug.h" // For the invalid message handler #endif +//#include "llnearbychathistory.h" +#include "llnotificationmanager.h" + // // Constants // @@ -2370,15 +2373,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) switch(chat.mChatType) { case CHAT_TYPE_WHISPER: - verb = " " + LLTrans::getString("whisper") + " "; + verb = "(" + LLTrans::getString("whisper") + ")"; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: case CHAT_TYPE_NORMAL: - verb = ": "; + verb = ""; break; case CHAT_TYPE_SHOUT: - verb = " " + LLTrans::getString("shout") + " "; + verb = "(" + LLTrans::getString("shout") + ")"; break; case CHAT_TYPE_START: case CHAT_TYPE_STOP: @@ -2386,12 +2389,12 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; default: LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - verb = " say, "; + verb = ""; break; } - chat.mText = from_name; + chat.mText = ""; chat.mText += verb; chat.mText += mesg; } @@ -2419,12 +2422,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) && (is_linden || !is_busy || is_owned_by_me)) { // show on screen and add to history - LLFloaterChat::addChat(chat, FALSE, FALSE); + LLNotificationsUI::LLNotificationManager::instance().onChat( + chat, LLNotificationsUI::NT_NEARBYCHAT); } else { + LLNotificationsUI::LLNotificationManager::instance().onChat( + chat, LLNotificationsUI::NT_NEARBYCHAT); // just add to chat history - LLFloaterChat::addChatHistory(chat); } } } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1468b376b0..24479485ef 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -184,9 +184,11 @@ #include "llpostprocess.h" #include "llbottomtray.h" +#include "llnotificationmanager.h" + #include "llfloaternotificationsconsole.h" -#include "llnearbychathistory.h" +#include "llnearbychat.h" #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods @@ -1641,6 +1643,15 @@ void LLViewerWindow::initWorldUI() getRootView()->sendChildToFront(gNotifyBoxView); // menu holder appears on top to get first pass at all mouse events getRootView()->sendChildToFront(gMenuHolder); + + //Channel Manager + LLNotificationsUI::LLChannelManager * channel_manager + = LLNotificationsUI::LLChannelManager::getInstance(); + getRootView()->addChild(channel_manager); + //Notification Manager + LLNotificationsUI::LLNotificationManager* notify_manager = + LLNotificationsUI::LLNotificationManager::getInstance(); + getRootView()->addChild(notify_manager); } // Destroy the UI @@ -2384,6 +2395,29 @@ void LLViewerWindow::moveCursorToCenter() LLUI::setCursorPositionScreen(x, y); } +void LLViewerWindow::updateBottomTrayRect() +{ + if(LLBottomTray::instanceExists() && LLSideTray::instanceCreated()) + { + S32 side_tray_width = 0; + if(LLSideTray::getInstance()->getVisible()) + { + side_tray_width = LLSideTray::getInstance()->getTrayWidth(); + } + + LLBottomTray* bottom_tray = LLBottomTray::getInstance(); + S32 right = llround((F32)mWindowRect.mRight / mDisplayScale.mV[VX]) - side_tray_width; + + LLRect rc = bottom_tray->getRect(); + if (right != rc.mRight) + { + rc.mRight = right; + bottom_tray->reshape(rc.getWidth(), rc.getHeight(), FALSE); + bottom_tray->setRect(rc); + } + } +} + ////////////////////////////////////////////////////////////////////// // // Hover handlers @@ -2397,15 +2431,7 @@ void LLViewerWindow::updateUI() updateWorldViewRect(); - if(LLBottomTray::instanceExists() && LLSideTray::instanceCreated()) - { - S32 delta = 0; - if(LLSideTray::getInstance()->getVisible()) - { - delta = llround((F32)LLSideTray::getInstance()->getTrayWidth() * mDisplayScale.mV[VX]); - } - LLBottomTray::getInstance()->updateRightPosition(mWindowRect.mRight - delta); - } + updateBottomTrayRect(); LLView::sMouseHandlerMessage.clear(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index a1120b303b..35173c8922 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -278,6 +278,7 @@ public: void updatePicking(S32 x, S32 y, MASK mask); void updateWorldViewRect(bool use_full_window=false); + void updateBottomTrayRect(); BOOL handleKey(KEY key, MASK mask); void handleScrollWheel (S32 clicks); diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h index 33cf7d8cb0..a273320b3d 100644 --- a/indra/newview/macview_Prefix.h +++ b/indra/newview/macview_Prefix.h @@ -75,7 +75,6 @@ #include "llfloatertools.h" #include "llhudeffectlookat.h" #include "llhudmanager.h" -#include "llinventoryview.h" #include "lljoystickbutton.h" #include "llmenugl.h" #include "llmorphview.h" diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml index afac4a4051..3052571b1e 100644 --- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml @@ -28,5 +28,5 @@ color="1 1 1 1" enabled="true" image_name="closebox.tga" name="close_btn"/> </panel> - <chat_history_view bottom="0" width="250" height="320" follows="left|right|top|bottom" name="chat_scroll" /> + <chat_items_container bottom="0" width="250" height="320" follows="left|right|top|bottom" name="chat_history" /> </floater> diff --git a/indra/newview/skins/default/xui/en/menu_nearby_chat.xml b/indra/newview/skins/default/xui/en/menu_nearby_chat.xml index 5eb4b10af9..02a2f83d14 100644 --- a/indra/newview/skins/default/xui/en/menu_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/menu_nearby_chat.xml @@ -1,10 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <menu bottom="100" color="MenuDefaultBgColor" drop_shadow="true" height="101" left="100" mouse_opaque="false" name="NearBy Chat Menu" opaque="true" width="128" visible="false"> - <menu_item_call bottom_delta="-18" height="18" label="Keep Visible" left="0" mouse_opaque="true" - name="keep_visible" width="128"> - <menu_item_call.on_click function="NearbyChat.Action" userdata="keep_visible" /> - </menu_item_call> <menu_item_call bottom_delta="-18" height="18" label="Show Nearby People..." left="0" mouse_opaque="true" name="nearby_people" width="128"> <menu_item_call.on_click function="NearbyChat.Action" userdata="nearby_people" /> diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 7006203dcd..7ac068df4b 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -301,9 +301,11 @@ height="20" left="22" top="23"/> +<!-- <chiclet_notification.commit_callback function="Notification.Show" parameter="ClickUnimplemented" /> + --> </chiclet_notification> </layout_panel> <icon diff --git a/indra/newview/skins/default/xui/en/panel_chat_item.xml b/indra/newview/skins/default/xui/en/panel_chat_item.xml new file mode 100644 index 0000000000..b628ee3aa1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_chat_item.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<!-- All our XML is utf-8 encoded. --> + +<panel + name="instant_message" + width="300" + height="180" + background_opaque="false" + background_visible="true" + follows="left|top|right|bottom" + bg_alpha_color="0.3 0.3 0.3 1.0"> + <panel width="250" height="30" background_visible="true" background_opaque="false" bg_alpha_color="0.0 0.0 0.0 1.0" name="msg_caption"> + <avatar_icon + top="25" left="10" width="20" height="20" follows="left|top" + color="1 1 1 1" enabled="true" name="avatar_icon" + /> + <text + width="160" top="25" left="40" height="20" follows="left|right|top" + font="SansSerifBigBold" text_color="white" word_wrap="true" + mouse_opaque="true" name="sender_name" > + Jerry Knight + </text> + <icon top="22" left="170" width="15" height="15" follows="top|right" + image_name="icn_voice-pvtfocus.tga" visible="false" name="msg_inspector"/> + <icon top="22" left="190" width="10" height="10" follows="top|right" + image_name="speaking_indicator.tga" name="msg_icon"/> + <text width="35" top="22" left="205" height="20" follows="right|top" + text_color="white" word_wrap="true" mouse_opaque="true" name="msg_time" > + 10:32 + </text> + </panel> + <text_chat + top="-35" left="10" right="-10" height="120" follows="left|right|bottom" + font="SansSerifSmall" text_color="white" word_wrap="true" + mouse_opaque="true" name="msg_text" > + </text_chat> +</panel> + diff --git a/indra/newview/skins/default/xui/en/panel_group_notify.xml b/indra/newview/skins/default/xui/en/panel_group_notify.xml new file mode 100644 index 0000000000..1757197372 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_group_notify.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel background_visible="true" bevel_style="in" bg_alpha_color="0 0 0 0" + height="200" label="instant_message" layout="topleft" left="0" + name="panel_group_notify" top="0" width="350"> + <panel background_visible="true" bevel_style="in" bg_alpha_color="black" + height="50" label="header" layout="topleft" left="0" name="header" + top="0" width="350"> + <icon follows="left|top|right|bottom" height="40" width="40" layout="topleft" + top="5" left="5" mouse_opaque="true" name="group_icon"/> + <text type="string" length="1" follows="left|top|right|bottom" + font="SansSerifBigBold" height="20" layout="topleft" left="60" name="title" + text_color="white" top="20" width="300"> + Sender Name / Group Name + </text> + </panel> + <text_editor type="string" length="1" bg_readonly_color="0 0 0 0" + follows="left|top|right|bottom" height="70" hide_scrollbar="true" + hide_border="true" layout="topleft" top="55" left="25" name="message" + text_color="white" text_readonly_color="white" width="300" word_wrap="true"> + Message + Body + </text_editor> + <text font="SansSerif" font.style="UNDERLINE" font_shadow="hard" + type="string" length="1" follows="left|top|right|bottom" layout="topleft" + left="25" top="135" height="15" width="300" name="attachment" + text_color="white"> + Attachment + </text> + <button label="OK" layout="topleft" top="170" left="140" height="20" + width="70" name="btn_ok" /> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml index 366c3ecf6c..1743e016ee 100644 --- a/indra/newview/skins/default/xui/en/panel_places.xml +++ b/indra/newview/skins/default/xui/en/panel_places.xml @@ -81,7 +81,7 @@ top_delta="0" width="60" /> <button - enabled="false" + enabled="true" follows="bottom|right" font="SansSerifSmallBold" height="25" diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml index 01052f4bbe..76a92a1087 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml @@ -17,7 +17,7 @@ background_visible="true" bg_opaque_color="0.5 0.5 0.5 1.0" > - <accordionctrl_tab + <accordion_tab name="people_accordion" title="People" collapsable="true" @@ -35,7 +35,7 @@ label="People" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> <!-- *TODO Vadim: isn't the sidetray_tab "label" attribute redundant since we have "tab_title" ? --> <sidetray_tab @@ -48,7 +48,7 @@ background_visible="true" bg_opaque_color="0.5 0.5 0.5 1.0" > - <accordionctrl_tab + <accordion_tab name="places_accordian" title="Places" collapsable="true" @@ -63,7 +63,7 @@ label="Places" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> <sidetray_tab @@ -75,7 +75,7 @@ background_visible="true" bg_opaque_color="0.5 0.5 0.5 1.0" > - <accordionctrl_tab + <accordion_tab name="me_accordion" title="Me" collapsable="false" @@ -90,7 +90,7 @@ label="Me" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> <!-- @@ -103,7 +103,7 @@ tab_title="Groups" description="Manage Groups." > - <accordionctrl_tab + <accordion_tab name="group_accordion" title="Group General" expanded="true" @@ -119,8 +119,8 @@ label="Group" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="groupland_accordion" title="Group Land and Money" expanded="false" @@ -136,8 +136,8 @@ label="Group" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="groupnotices_accordion" title="Group Notices" expanded="false" @@ -153,8 +153,8 @@ label="Group" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="grouproles_accordion" title="Group Roles" expanded="false" @@ -170,7 +170,7 @@ label="Group" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> @@ -184,7 +184,7 @@ tab_title="Previews" description="Previews." > - <accordionctrl_tab + <accordion_tab name="floater_preview_animation" title="Preview Animation" collapsable="true" @@ -202,8 +202,8 @@ label="Preview_Animation" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_preview_gesture" title="Preview Gesture" collapsable="true" @@ -221,8 +221,8 @@ label="Preview_Gesture" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_preview_existing_landmark" title="Preview Existing Landmark" collapsable="true" @@ -240,8 +240,8 @@ label="Preview_Existing_Landmark" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_preview_sound" title="Preview Sound" collapsable="true" @@ -259,8 +259,8 @@ label="Preview_Sound" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_preview_url" title="Preview URL" collapsable="true" @@ -278,8 +278,8 @@ label="Preview_URL" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_URL_entry" title="URL Entry" collapsable="true" @@ -297,7 +297,7 @@ label="URL_entry" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> <sidetray_tab @@ -310,7 +310,7 @@ tab_title="Region" description="Region." > - <accordionctrl_tab + <accordion_tab name="panel_region_covenant" title="Region Covenant" collapsable="true" @@ -328,8 +328,8 @@ label="Panel_Region_Covenant" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="panel_region_debug" title="Region Debug" collapsable="true" @@ -347,8 +347,8 @@ label="Panel_Region_Debug" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="panel_region_estate" title="Region Estate" collapsable="true" @@ -366,8 +366,8 @@ label="Panel_Region_Estate" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="panel_region_general" title="Region General" collapsable="true" @@ -385,8 +385,8 @@ label="Panel_Region_General" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="panel_region_terrain" title="Region Terrain" collapsable="true" @@ -404,8 +404,8 @@ label="Panel_Region_Terrain" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="panel_region_texture" title="Region Texture" collapsable="true" @@ -423,8 +423,8 @@ label="Panel_Region_Texture" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_region_info" title="Region Info" collapsable="true" @@ -442,7 +442,7 @@ label="Floater_Region_Info" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> <sidetray_tab @@ -455,7 +455,7 @@ tab_title="Build" description="Build" > - <accordionctrl_tab + <accordion_tab name="floater_tools" title="Tools" collapsable="true" @@ -473,8 +473,8 @@ label="Tools" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_bulk_perms" title="Bulk Perms" collapsable="true" @@ -492,8 +492,8 @@ label="Tools" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_build_options" title="Build Options" collapsable="true" @@ -511,7 +511,7 @@ label="Tools" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> @@ -525,7 +525,7 @@ tab_title="Other Tools" description="Other Tools" > - <accordionctrl_tab + <accordion_tab name="floater_gesture" title="Gestures" collapsable="true" @@ -543,9 +543,9 @@ label="Gesture" border="true" /> - </accordionctrl_tab> + </accordion_tab> - <accordionctrl_tab + <accordion_tab name="floater_buy_contents" title="Buy Contents" collapsable="true" @@ -563,8 +563,8 @@ label="buy_contents" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_buy_object" title="Buy Object" collapsable="true" @@ -583,7 +583,7 @@ border="true" /> </collapsible_ctrl> - <accordionctrl_tab + <accordion_tab name="floater_inventory_view_finder" title="Inventory View Finder" collapsable="true" @@ -601,8 +601,8 @@ label="view_finder" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_mute" title="Mute" collapsable="true" @@ -620,8 +620,8 @@ label="mute" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_sell_land" title="Sell Land" collapsable="true" @@ -639,8 +639,8 @@ label="sell_land" border="true" /> - </accordionctrl_tab> - <accordionctrl_tab + </accordion_tab> + <accordion_tab name="floater_telehub" title="Telehub" collapsable="true" @@ -658,7 +658,7 @@ label="telehub" border="true" /> - </accordionctrl_tab> + </accordion_tab> </sidetray_tab> --> diff --git a/indra/newview/skins/default/xui/en/panel_toast.xml b/indra/newview/skins/default/xui/en/panel_toast.xml new file mode 100644 index 0000000000..8952ea1307 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_toast.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<!-- All our XML is utf-8 encoded. --> + +<panel + name="toast" + title="toast" + visible="false" + layout="topleft" + width="350" + height="72" + left="100" + top="500" + follows="right|bottom" + background_opaque="true" + background_visible="true" + bevel_style="in" + bg_alpha_color="0.3 0.3 0.3 1.0"> + + <text + type="string" + visible="false" + follows="left|top|right|bottom" + font="SansSerifBold" + height="40" + layout="topleft" + left="60" + name="text" + text_color="white" + top="30" + width="290"> + Toast text; + </text> + <icon + top="20" + left="10" + width="32" + height="32" + follows="top|left" + layout="topleft" + visible="false" + color="1 1 1 1" + enabled="true" + image_name="notify_tip_icon.tga" + mouse_opaque="true" + name="icon" + /> + <button + layout="topleft" + top="-5" + left="335" + width="20" + height="20" + follows="top|right" + visible="false" + enabled="true" + mouse_opaque="true" + name="hide_btn" + label="" + image_unselected="toast_hide_btn.tga" + image_disabled="toast_hide_btn.tga" + image_selected="toast_hide_btn.tga" + image_hover_selected="toast_hide_btn.tga" + image_disabled_selected="toast_hide_btn.tga" + /> +</panel> |