summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorWilliam Todd Stinson <stinson@lindenlab.com>2012-10-03 17:48:01 -0700
committerWilliam Todd Stinson <stinson@lindenlab.com>2012-10-03 17:48:01 -0700
commit36df0f8a06629c5a14358c07d0f12ce1019f066e (patch)
tree7cf7bbbaeb351b84888032ff98627b04fd871b60 /indra
parent3d5e24d135bd5d2636f075f9ef12ffba2129c61f (diff)
parent046e90a8f74f3c13107a7edc72e912799a5e62e9 (diff)
Pull and merge from ssh://stinson@hg.lindenlab.com/richard/viewer-chui/.
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/llfloater.cpp5
-rw-r--r--indra/llui/llfloater.h7
-rw-r--r--indra/llui/llfolderview.cpp29
-rw-r--r--indra/llui/llfolderview.h2
-rwxr-xr-xindra/llui/llfolderviewitem.cpp169
-rwxr-xr-xindra/llui/llfolderviewitem.h45
-rw-r--r--indra/llui/llfolderviewmodel.h12
-rw-r--r--indra/llui/lllayoutstack.cpp2
-rw-r--r--indra/llui/llview.cpp11
-rw-r--r--indra/llui/llview.h1
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/commands.xml10
-rw-r--r--indra/newview/llappviewer.cpp3
-rwxr-xr-xindra/newview/llavataractions.cpp17
-rw-r--r--indra/newview/llavataractions.h5
-rw-r--r--indra/newview/llcallfloater.cpp3
-rw-r--r--indra/newview/llcallfloater.h4
-rw-r--r--indra/newview/llconversationmodel.cpp218
-rwxr-xr-xindra/newview/llconversationmodel.h39
-rwxr-xr-xindra/newview/llconversationview.cpp319
-rwxr-xr-xindra/newview/llconversationview.h29
-rw-r--r--indra/newview/llfloaterchatvoicevolume.cpp44
-rw-r--r--indra/newview/llfloaterchatvoicevolume.h44
-rw-r--r--indra/newview/llimconversation.cpp22
-rw-r--r--indra/newview/llimconversation.h4
-rw-r--r--indra/newview/llimfloater.cpp76
-rw-r--r--indra/newview/llimfloater.h4
-rw-r--r--[-rwxr-xr-x]indra/newview/llimfloatercontainer.cpp475
-rw-r--r--indra/newview/llimfloatercontainer.h20
-rw-r--r--indra/newview/llinventorybridge.cpp9
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llinventorypanel.cpp4
-rw-r--r--indra/newview/llnearbychat.cpp26
-rw-r--r--indra/newview/llnearbychat.h7
-rw-r--r--indra/newview/llnearbychathandler.cpp1
-rw-r--r--indra/newview/llnotificationscripthandler.cpp5
-rw-r--r--indra/newview/lloutputmonitorctrl.cpp30
-rw-r--r--indra/newview/lloutputmonitorctrl.h5
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp1
-rw-r--r--indra/newview/llparticipantlist.cpp28
-rw-r--r--indra/newview/llparticipantlist.h9
-rw-r--r--indra/newview/llspeakers.cpp15
-rw-r--r--indra/newview/llspeakers.h9
-rw-r--r--indra/newview/llviewerfloaterreg.cpp4
-rw-r--r--indra/newview/llviewermenu.cpp16
-rw-r--r--indra/newview/skins/default/textures/icons/nearby_chat_icon.pngbin0 -> 793 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_conversation_log.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_container.xml5
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml11
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml48
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation.xml127
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_friends_view.xml8
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_nearby.xml10
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml13
-rw-r--r--indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_conversation_list_item.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_outbox_inventory.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml16
-rwxr-xr-xindra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml13
-rw-r--r--indra/newview/skins/default/xui/en/widgets/conversation_view_session.xml9
-rw-r--r--indra/newview/skins/default/xui/en/widgets/folder_view_item.xml8
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml8
64 files changed, 1671 insertions, 442 deletions
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 029c47c726..58b17f74a8 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -240,6 +240,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mTitle(p.title),
mShortTitle(p.short_title),
mSingleInstance(p.single_instance),
+ mIsReuseInitialized(p.reuse_instance.isProvided()),
mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default
mKey(key),
mCanTearOff(p.can_tear_off),
@@ -631,6 +632,10 @@ void LLFloater::setVisible( BOOL visible )
void LLFloater::setIsSingleInstance(BOOL is_single_instance)
{
mSingleInstance = is_single_instance;
+ if (!mIsReuseInitialized)
+ {
+ mReuseInstance = is_single_instance; // reuse single-instance floaters by default
+ }
}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 4b738f88ea..07b79d5523 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -447,9 +447,10 @@ private:
LLUIString mTitle;
LLUIString mShortTitle;
- BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater
- bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
- std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
+ BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater
+ bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
+ bool mIsReuseInitialized; // true if mReuseInstance already set from parameters
+ std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
BOOL mCanTearOff;
BOOL mCanMinimize;
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 11004fe390..9a4a90206b 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -56,11 +56,7 @@
const S32 RENAME_WIDTH_PAD = 4;
const S32 RENAME_HEIGHT_PAD = 1;
const S32 AUTO_OPEN_STACK_DEPTH = 16;
-const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH
- + LLFolderViewItem::ICON_PAD
- + LLFolderViewItem::ARROW_SIZE
- + LLFolderViewItem::TEXT_PAD
- + /*first few characters*/ 40;
+
const S32 MINIMUM_RENAMER_WIDTH = 80;
// *TODO: move in params in xml if necessary. Requires modification of LLFolderView & LLInventoryPanel Params.
@@ -142,7 +138,8 @@ LLFolderView::Params::Params()
use_label_suffix("use_label_suffix"),
allow_multiselect("allow_multiselect", true),
show_empty_message("show_empty_message", true),
- use_ellipses("use_ellipses", false)
+ use_ellipses("use_ellipses", false),
+ options_menu("options_menu", "")
{
folder_indentation = -4;
}
@@ -211,10 +208,11 @@ LLFolderView::LLFolderView(const Params& p)
// Textbox
LLTextBox::Params text_p;
LLFontGL* font = getLabelFontForStyle(mLabelStyle);
- LLRect new_r = LLRect(rect.mLeft + ICON_PAD,
- rect.mTop - TEXT_PAD,
+ //mIconPad, mTextPad are set in folder_view_item.xml
+ LLRect new_r = LLRect(rect.mLeft + mIconPad,
+ rect.mTop - mTextPad,
rect.mRight,
- rect.mTop - TEXT_PAD - font->getLineHeight());
+ rect.mTop - mTextPad - font->getLineHeight());
text_p.rect(new_r);
text_p.name(std::string(p.name));
text_p.font(font);
@@ -231,7 +229,7 @@ LLFolderView::LLFolderView(const Params& p)
// make the popup menu available
- LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
if (!menu)
{
menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
@@ -1533,14 +1531,18 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
&& menu )
{
if (mCallbackRegistrar)
+ {
mCallbackRegistrar->pushScope();
+ }
updateMenuOptions(menu);
menu->updateParent(LLMenuGL::sMenuContainer);
LLMenuGL::showPopup(this, menu, x, y);
if (mCallbackRegistrar)
+ {
mCallbackRegistrar->popScope();
+ }
}
else
{
@@ -1652,12 +1654,13 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr
S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight();
S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight();
// when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder
- S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight();
+ S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight();
// get portion of item that we want to see...
LLRect item_local_rect = LLRect(item->getIndentation(),
local_rect.getHeight(),
- llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()),
+ //+40 is supposed to include few first characters
+ llmin(item->getLabelXPos() - item->getIndentation() + 40, local_rect.getWidth()),
llmax(0, local_rect.getHeight() - max_height_to_show));
LLRect item_doc_rect;
@@ -1874,7 +1877,7 @@ void LLFolderView::updateRenamerPosition()
if(mRenameItem)
{
// See also LLFolderViewItem::draw()
- S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mRenameItem->getIndentation();
+ S32 x = mRenameItem->getLabelXPos();
S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD;
mRenameItem->localPointToScreen( x, y, &x, &y );
screenPointToLocal( x, y, &x, &y );
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 81b0f087e8..487391a477 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -94,6 +94,8 @@ public:
use_ellipses,
show_item_link_overlays;
Mandatory<LLFolderViewModelInterface*> view_model;
+ Mandatory<std::string> options_menu;
+
Params();
};
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index a20ce23b18..0b04288950 100755
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -44,6 +44,18 @@ static LLDefaultChildRegistry::Register<LLFolderViewItem> r("folder_view_item");
// statics
std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts
+LLUIColor LLFolderViewItem::sFgColor;
+LLUIColor LLFolderViewItem::sHighlightBgColor;
+LLUIColor LLFolderViewItem::sHighlightFgColor;
+LLUIColor LLFolderViewItem::sFocusOutlineColor;
+LLUIColor LLFolderViewItem::sMouseOverColor;
+LLUIColor LLFolderViewItem::sFilterBGColor;
+LLUIColor LLFolderViewItem::sFilterTextColor;
+LLUIColor LLFolderViewItem::sSuffixColor;
+LLUIColor LLFolderViewItem::sLibraryColor;
+LLUIColor LLFolderViewItem::sLinkColor;
+LLUIColor LLFolderViewItem::sSearchStatusColor;
+
// only integers can be initialized in header
const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f;
const F32 LLFolderViewItem::FOLDER_OPEN_TIME_CONSTANT = 0.03f;
@@ -90,7 +102,14 @@ LLFolderViewItem::Params::Params()
item_height("item_height"),
item_top_pad("item_top_pad"),
creation_date(),
- allow_open("allow_open", true)
+ allow_open("allow_open", true),
+ left_pad("left_pad", 0),
+ icon_pad("icon_pad", 0),
+ icon_width("icon_width", 0),
+ text_pad("text_pad", 0),
+ text_pad_right("text_pad_right", 0),
+ arrow_size("arrow_size", 0),
+ max_folder_item_overlap("max_folder_item_overlap", 0)
{}
// Default constructor
@@ -98,7 +117,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
: LLView(p),
mLabelWidth(0),
mLabelWidthDirty(false),
- mLabelPaddingRight(DEFAULT_TEXT_PADDING_RIGHT),
+ mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT),
mParentFolder( NULL ),
mIsSelected( FALSE ),
mIsCurSelection( FALSE ),
@@ -114,12 +133,31 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mRoot(p.root),
mViewModelItem(p.listener),
mIsMouseOverTitle(false),
- mAllowOpen(p.allow_open)
-{
+ mAllowOpen(p.allow_open),
+ mLeftPad(p.left_pad),
+ mIconPad(p.icon_pad),
+ mIconWidth(p.icon_width),
+ mTextPad(p.text_pad),
+ mTextPadRight(p.text_pad_right),
+ mArrowSize(p.arrow_size),
+ mMaxFolderItemOverlap(p.max_folder_item_overlap)
+{
+ sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
+ sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
+ sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
+ sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
+ sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
+ sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
+ sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
+ sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
+ sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
+ sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
+
if (mViewModelItem)
{
mViewModelItem->setFolderViewItem(this);
-}
+ }
}
BOOL LLFolderViewItem::postBuild()
@@ -216,7 +254,7 @@ void LLFolderViewItem::refresh()
mLabel = vmi.getDisplayName();
- setToolTip(mLabel);
+ setToolTip(vmi.getName());
mIcon = vmi.getIcon();
mIconOpen = vmi.getIconOpen();
mIconOverlay = vmi.getIconOverlay();
@@ -291,11 +329,11 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
: 0;
if (mLabelWidthDirty)
{
- mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
+ mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
mLabelWidthDirty = false;
}
- *width = llmax(*width, mLabelWidth + mIndentation);
+ *width = llmax(*width, mLabelWidth);
// determine if we need to use ellipses to avoid horizontal scroll. EXT-719
bool use_ellipses = getRoot()->getUseEllipses();
@@ -313,6 +351,21 @@ S32 LLFolderViewItem::getItemHeight()
return mItemHeight;
}
+S32 LLFolderViewItem::getLabelXPos()
+{
+ return getIndentation() + mArrowSize + mTextPad + mIconWidth + mIconPad;
+}
+
+S32 LLFolderViewItem::getIconPad()
+{
+ return mIconPad;
+}
+
+S32 LLFolderViewItem::getTextPad()
+{
+ return mTextPad;
+}
+
// *TODO: This can be optimized a lot by simply recording that it is
// selected in the appropriate places, and assuming that set selection
// means 'deselect' for a leaf item. Do this optimization after
@@ -484,7 +537,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()
&& root->getCurSelectedItem()
&& root->startDrag())
- {
+ {
// RN: when starting drag and drop, clear out last auto-open
root->autoOpenTest(NULL);
root->setShowSelectionContext(TRUE);
@@ -495,13 +548,13 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
gFocusMgr.setKeyboardFocus(NULL);
getWindow()->setCursor(UI_CURSOR_ARROW);
- return TRUE;
- }
- else
+ }
+ else if (x != mDragStartX || y != mDragStartY)
{
getWindow()->setCursor(UI_CURSOR_NOLOCKED);
- return TRUE;
}
+
+ return TRUE;
}
else
{
@@ -595,6 +648,22 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
return handled;
}
+void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color)
+{
+ //--------------------------------------------------------------------------------//
+ // Draw open folder arrow
+ //
+ const S32 TOP_PAD = default_params.item_top_pad;
+
+ if (hasVisibleChildren() || getViewModelItem()->hasChildren())
+ {
+ LLUIImage* arrow_image = default_params.folder_arrow_image;
+ gl_draw_scaled_rotated_image(
+ mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD,
+ mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color);
+ }
+}
+
void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &bgColor,
const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor)
{
@@ -705,18 +774,6 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y
void LLFolderViewItem::draw()
{
- static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
- static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
- static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
- static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
- static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
- static LLUIColor sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
- static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
- static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
- static LLUIColor sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
- static LLUIColor sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
- static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
-
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled
@@ -727,24 +784,14 @@ void LLFolderViewItem::draw()
getViewModelItem()->update();
- //--------------------------------------------------------------------------------//
- // Draw open folder arrow
- //
- if (hasVisibleChildren() || getViewModelItem()->hasChildren())
- {
- LLUIImage* arrow_image = default_params.folder_arrow_image;
- gl_draw_scaled_rotated_image(
- mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD - TOP_PAD,
- ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, arrow_image->getImage(), sFgColor);
- }
-
+ drawOpenFolderArrow(default_params, sFgColor);
drawHighlight(show_context, filled, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
//--------------------------------------------------------------------------------//
// Draw open icon
//
- const S32 icon_x = mIndentation + ARROW_SIZE + TEXT_PAD;
+ const S32 icon_x = mIndentation + mArrowSize + mTextPad;
if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders
{
mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1);
@@ -769,8 +816,8 @@ void LLFolderViewItem::draw()
std::string::size_type filter_string_length = mViewModelItem->hasFilterStringMatch() ? mViewModelItem->getFilterStringSize() : 0;
F32 right_x = 0;
- F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;
- F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation);
+ F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
+ F32 text_left = (F32)getLabelXPos();
std::string combined_string = mLabel + mLabelSuffix;
if (filter_string_length > 0)
@@ -804,14 +851,15 @@ void LLFolderViewItem::draw()
if (filter_string_length > 0)
{
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mViewModelItem->getFilterStringOffset());
- F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;
+ F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
filter_string_length, S32_MAX, &right_x, FALSE );
}
-
- LLView::draw();
+ //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
+ //be distorted...oddly. I initially added this in but didn't need it after all. So removing to prevent unnecessary bug.
+ //LLView::draw();
}
const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const
@@ -847,6 +895,22 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
{
}
+void LLFolderViewFolder::updateLabelRotation()
+{
+ if (mAutoOpenCountdown != 0.f)
+ {
+ mControlLabelRotation = mAutoOpenCountdown * -90.f;
+ }
+ else if (isOpen())
+ {
+ mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f));
+ }
+ else
+ {
+ mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f));
+ }
+}
+
// Destroys the object
LLFolderViewFolder::~LLFolderViewFolder( void )
{
@@ -987,7 +1051,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
folders_t::iterator fit = iter++;
// number of pixels that bottom of folder label is from top of parent folder
if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight()
- > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP)
+ > llround(mCurHeight) + mMaxFolderItemOverlap)
{
// hide if beyond current folder height
(*fit)->setVisible(FALSE);
@@ -1000,7 +1064,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
items_t::iterator iit = iter++;
// number of pixels that bottom of item label is from top of parent folder
if (getRect().getHeight() - (*iit)->getRect().mBottom
- > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP)
+ > llround(mCurHeight) + mMaxFolderItemOverlap)
{
(*iit)->setVisible(FALSE);
}
@@ -1760,7 +1824,7 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask )
}
if( !handled )
{
- if(mIndentation < x && x < mIndentation + ARROW_SIZE + TEXT_PAD)
+ if(mIndentation < x && x < mIndentation + mArrowSize + mTextPad)
{
toggleOpen();
handled = TRUE;
@@ -1784,7 +1848,7 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
}
if( !handled )
{
- if(mIndentation < x && x < mIndentation + ARROW_SIZE + TEXT_PAD)
+ if(mIndentation < x && x < mIndentation + mArrowSize + mTextPad)
{
// don't select when user double-clicks plus sign
// so as not to contradict single-click behavior
@@ -1802,18 +1866,7 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
void LLFolderViewFolder::draw()
{
- if (mAutoOpenCountdown != 0.f)
- {
- mControlLabelRotation = mAutoOpenCountdown * -90.f;
- }
- else if (isOpen())
- {
- mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f));
- }
- else
- {
- mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f));
- }
+ updateLabelRotation();
LLFolderViewItem::draw();
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 5c97407bc1..d4002c3184 100755
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -60,18 +60,18 @@ public:
Optional<time_t> creation_date;
Optional<bool> allow_open;
+ Optional<S32> left_pad,
+ icon_pad,
+ icon_width,
+ text_pad,
+ text_pad_right,
+ arrow_size,
+ max_folder_item_overlap;
Params();
};
- // layout constants
- static const S32 LEFT_PAD = 5,
- ICON_PAD = 2,
- ICON_WIDTH = 16,
- TEXT_PAD = 1,
- DEFAULT_TEXT_PADDING_RIGHT = 4,
- ARROW_SIZE = 12,
- MAX_FOLDER_ITEM_OVERLAP = 2;
-
+
+ static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4;
// animation parameters
static const F32 FOLDER_CLOSE_TIME_CONSTANT,
FOLDER_OPEN_TIME_CONSTANT;
@@ -99,6 +99,14 @@ protected:
S32 mDragStartX,
mDragStartY;
+ S32 mLeftPad,
+ mIconPad,
+ mIconWidth,
+ mTextPad,
+ mTextPadRight,
+ mArrowSize,
+ mMaxFolderItemOverlap;
+
F32 mControlLabelRotation;
LLFolderView* mRoot;
bool mHasVisibleChildren,
@@ -108,6 +116,19 @@ protected:
mAllowOpen,
mSelectPending;
+ // For now assuming all colors are the same in derived classes.
+ static LLUIColor sFgColor;
+ static LLUIColor sHighlightBgColor;
+ static LLUIColor sHighlightFgColor;
+ static LLUIColor sFocusOutlineColor;
+ static LLUIColor sMouseOverColor;
+ static LLUIColor sFilterBGColor;
+ static LLUIColor sFilterTextColor;
+ static LLUIColor sSuffixColor;
+ static LLUIColor sLibraryColor;
+ static LLUIColor sLinkColor;
+ static LLUIColor sSearchStatusColor;
+
// this is an internal method used for adding items to folders. A
// no-op at this level, but reimplemented in derived classes.
virtual void addItem(LLFolderViewItem*) { }
@@ -136,6 +157,9 @@ public:
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height );
virtual S32 getItemHeight();
+ virtual S32 getLabelXPos();
+ S32 getIconPad();
+ S32 getTextPad();
// If 'selection' is 'this' then note that otherwise ignore.
// Returns TRUE if this item ends up being selected.
@@ -236,6 +260,7 @@ public:
// virtual void handleDropped();
virtual void draw();
+ void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color);
void drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &bgColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor);
void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -263,6 +288,8 @@ protected:
LLFolderViewFolder( const LLFolderViewItem::Params& );
friend class LLUICtrlFactory;
+ void updateLabelRotation();
+
public:
typedef std::list<LLFolderViewItem*> items_t;
typedef std::list<LLFolderViewFolder*> folders_t;
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index 22bfc4dfb4..c6030c9b71 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -226,7 +226,7 @@ public:
mParent(NULL),
mRootViewModel(root_view_model)
{
- std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
+ mChildren.clear();
}
void requestSort() { mSortVersion = -1; }
@@ -254,6 +254,16 @@ public:
virtual void addChild(LLFolderViewModelItem* child)
{
+ // Avoid duplicates: bail out if that child is already present in the list
+ // Note: this happens when models are created before views
+ child_list_t::const_iterator iter;
+ for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
+ {
+ if (child == *iter)
+ {
+ return;
+ }
+ }
mChildren.push_back(child);
child->setParent(this);
dirtyFilter();
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 4c730286da..be6d359c9a 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -767,7 +767,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
{ // freeze new size as fraction
F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)
? MAX_FRACTIONAL_SIZE
- : llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
+ : llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim() - 1) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
fraction_remaining -= panelp->mFractionalSize;
panelp->mFractionalSize = new_fractional_size;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 5c2b3236f6..8323bfc12f 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -873,13 +873,12 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
// allow "scrubbing" over ui by showing next tooltip immediately
// if previous one was still visible
F32 timeout = LLToolTipMgr::instance().toolTipVisible()
- ? LLUI::sSettingGroups["config"]->getF32( "ToolTipFastDelay" )
- : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
+ ? LLUI::sSettingGroups["config"]->getF32( "ToolTipFastDelay" )
+ : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
LLToolTipMgr::instance().show(LLToolTip::Params()
- .message(tooltip)
- .sticky_rect(calcScreenRect())
- .delay_time(timeout));
-
+ .message(tooltip)
+ .sticky_rect(calcScreenRect())
+ .delay_time(timeout));
handled = TRUE;
}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 1c35349510..15b85a6418 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -67,7 +67,6 @@ const BOOL NOT_MOUSE_OPAQUE = FALSE;
const U32 GL_NAME_UI_RESERVED = 2;
-
// maintains render state during traversal of UI tree
class LLViewDrawContext
{
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 6436a85105..345c81b838 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -197,6 +197,7 @@ set(viewer_SOURCE_FILES
llfloaterbuycurrencyhtml.cpp
llfloaterbuyland.cpp
llfloatercamera.cpp
+ llfloaterchatvoicevolume.cpp
llfloatercolorpicker.cpp
llfloaterconversationlog.cpp
llfloaterconversationpreview.cpp
@@ -781,6 +782,7 @@ set(viewer_HEADER_FILES
llfloaterbuycurrencyhtml.h
llfloaterbuyland.h
llfloatercamera.h
+ llfloaterchatvoicevolume.h
llfloatercolorpicker.h
llfloaterconversationlog.h
llfloaterconversationpreview.h
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index 51211a8ce5..d4bbd84d0f 100644
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -239,14 +239,4 @@
is_running_function="Floater.IsOpen"
is_running_parameters="camera"
/>
- <command name="voice"
- available_in_toybox="true"
- icon="Command_Voice_Icon"
- label_ref="Command_Voice_Label"
- tooltip_ref="Command_Voice_Tooltip"
- execute_function="Floater.ToggleOrBringToFront"
- execute_parameters="voice_controls"
- is_running_function="Floater.IsOpen"
- is_running_parameters="voice_controls"
- />
</commands>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 08a1a237f5..6b15e4b21a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -42,6 +42,7 @@
#include "llagentcamera.h"
#include "llagentlanguage.h"
#include "llagentwearables.h"
+#include "llimfloatercontainer.h"
#include "llwindow.h"
#include "llviewerstats.h"
#include "llviewerstatsrecorder.h"
@@ -1204,7 +1205,7 @@ bool LLAppViewer::mainLoop()
LLVoiceChannel::initClass();
LLVoiceClient::getInstance()->init(gServicePump);
- LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::sOnCurrentChannelChanged, _1), true);
+ LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLIMFloaterContainer::onCurrentChannelChanged, _1), true);
LLTimer frameTimer,idleTimer;
LLTimer debugTime;
LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 42a0376774..248685b964 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -42,6 +42,7 @@
#include "llappviewer.h" // for gLastVersionChannel
#include "llcachename.h"
#include "llcallingcard.h" // for LLAvatarTracker
+#include "llconversationlog.h"
#include "llfloateravatarpicker.h" // for LLFloaterAvatarPicker
#include "llfloatergroupinvite.h"
#include "llfloatergroups.h"
@@ -897,6 +898,22 @@ void LLAvatarActions::inviteToGroup(const LLUUID& id)
}
}
+// static
+void LLAvatarActions::viewChatHistory(const LLUUID& id)
+{
+ const std::vector<LLConversation>& conversations = LLConversationLog::instance().getConversations();
+ std::vector<LLConversation>::const_iterator iter = conversations.begin();
+
+ for (; iter != conversations.end(); ++iter)
+ {
+ if (iter->getParticipantID() == id)
+ {
+ LLFloaterReg::showInstance("preview_conversation", iter->getSessionID(), true);
+ break;
+ }
+ }
+}
+
//== private methods ========================================================================================
// static
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 473b9cecc3..6e60f624ad 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -218,6 +218,11 @@ public:
*/
static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string);
+ /**
+ * Opens the chat history for avatar
+ */
+ static void viewChatHistory(const LLUUID& id);
+
static std::set<LLUUID> getInventorySelectedUUIDs();
private:
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index 38b755004c..e767609d74 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -364,7 +364,8 @@ void LLCallFloater::onAvatarListRefreshed()
}
// static
-void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
+// This entry point now disable, but left for later use.
+void LLCallFloater::onCurrentChannelChanged(const LLUUID& /*session_id*/)
{
LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel();
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 181c92276d..e1c7b3f43a 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -74,7 +74,7 @@ public:
*/
/*virtual*/ void onParticipantsChanged();
- static void sOnCurrentChannelChanged(const LLUUID& session_id);
+ static void onCurrentChannelChanged(const LLUUID& session_id);
private:
typedef enum e_voice_controls_type
@@ -260,7 +260,7 @@ private:
*
* Is used to ignore voice channel changed callback for the same channel.
*
- * @see sOnCurrentChannelChanged()
+ * @see onCurrentChannelChanged()
*/
static LLVoiceChannel* sCurrentVoiceChannel;
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 612744c3e9..5fc305da81 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -28,6 +28,7 @@
#include "llviewerprecompiledheaders.h"
#include "llconversationmodel.h"
+#include "llimview.h" //For LLIMModel
//
// Conversation items : common behaviors
@@ -38,7 +39,8 @@ LLConversationItem::LLConversationItem(std::string display_name, const LLUUID& u
mName(display_name),
mUUID(uuid),
mNeedsRefresh(true),
- mConvType(CONV_UNKNOWN)
+ mConvType(CONV_UNKNOWN),
+ mLastActiveTime(0.0)
{
}
@@ -47,7 +49,8 @@ LLConversationItem::LLConversationItem(const LLUUID& uuid, LLFolderViewModelInte
mName(""),
mUUID(uuid),
mNeedsRefresh(true),
- mConvType(CONV_UNKNOWN)
+ mConvType(CONV_UNKNOWN),
+ mLastActiveTime(0.0)
{
}
@@ -56,7 +59,8 @@ LLConversationItem::LLConversationItem(LLFolderViewModelInterface& root_view_mod
mName(""),
mUUID(),
mNeedsRefresh(true),
- mConvType(CONV_UNKNOWN)
+ mConvType(CONV_UNKNOWN),
+ mLastActiveTime(0.0)
{
}
@@ -81,6 +85,24 @@ void LLConversationItem::showProperties(void)
{
}
+void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items)
+{
+ items.push_back(std::string("view_profile"));
+ items.push_back(std::string("im"));
+ items.push_back(std::string("offer_teleport"));
+ items.push_back(std::string("voice_call"));
+ items.push_back(std::string("chat_history"));
+ items.push_back(std::string("separator_chat_history"));
+ items.push_back(std::string("add_friend"));
+ items.push_back(std::string("remove_friend"));
+ items.push_back(std::string("invite_to_group"));
+ items.push_back(std::string("separator_invite_to_group"));
+ items.push_back(std::string("map"));
+ items.push_back(std::string("share"));
+ items.push_back(std::string("pay"));
+ items.push_back(std::string("block_unblock"));
+}
+
//
// LLConversationItemSession
//
@@ -167,9 +189,100 @@ void LLConversationItemSession::setParticipantIsModerator(const LLUUID& particip
}
}
+void LLConversationItemSession::setTimeNow(const LLUUID& participant_id)
+{
+ mLastActiveTime = LLFrameTimer::getElapsedSeconds();
+ mNeedsRefresh = true;
+ LLConversationItemParticipant* participant = findParticipant(participant_id);
+ if (participant)
+ {
+ participant->setTimeNow();
+ }
+}
+
+void LLConversationItemSession::setDistance(const LLUUID& participant_id, F64 dist)
+{
+ LLConversationItemParticipant* participant = findParticipant(participant_id);
+ if (participant)
+ {
+ participant->setDistance(dist);
+ mNeedsRefresh = true;
+ }
+}
+
+void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ lldebugs << "LLConversationItemParticipant::buildContextMenu()" << llendl;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if(this->getType() == CONV_SESSION_1_ON_1)
+ {
+ items.push_back(std::string("close_conversation"));
+ items.push_back(std::string("separator_disconnect_from_voice"));
+ buildParticipantMenuOptions(items);
+ }
+ else if(this->getType() == CONV_SESSION_GROUP)
+ {
+ items.push_back(std::string("close_conversation"));
+ addVoiceOptions(items);
+ items.push_back(std::string("chat_history"));
+ items.push_back(std::string("separator_chat_history"));
+ items.push_back(std::string("group_profile"));
+ items.push_back(std::string("activate_group"));
+ items.push_back(std::string("leave_group"));
+ }
+ else if(this->getType() == CONV_SESSION_AD_HOC)
+ {
+ items.push_back(std::string("close_conversation"));
+ addVoiceOptions(items);
+ items.push_back(std::string("chat_history"));
+ }
+
+ hide_context_entries(menu, items, disabled_items);
+}
+
+void LLConversationItemSession::addVoiceOptions(menuentry_vec_t& items)
+{
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL;
+
+ if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel())
+ {
+ items.push_back(std::string("open_voice_conversation"));
+ }
+ else
+ {
+ items.push_back(std::string("disconnect_from_voice"));
+ }
+}
+
+// The time of activity of a session is the time of the most recent activity, session and participants included
+const bool LLConversationItemSession::getTime(F64& time) const
+{
+ F64 most_recent_time = mLastActiveTime;
+ bool has_time = (most_recent_time > 0.1);
+ LLConversationItemParticipant* participant = NULL;
+ child_list_t::const_iterator iter;
+ for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
+ {
+ participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
+ F64 participant_time;
+ if (participant->getTime(participant_time))
+ {
+ has_time = true;
+ most_recent_time = llmax(most_recent_time,participant_time);
+ }
+ }
+ if (has_time)
+ {
+ time = most_recent_time;
+ }
+ return has_time;
+}
+
void LLConversationItemSession::dumpDebugData()
{
- llinfos << "Merov debug : session, uuid = " << mUUID << ", name = " << mName << ", is loaded = " << mIsLoaded << llendl;
+ llinfos << "Merov debug : session " << this << ", uuid = " << mUUID << ", name = " << mName << ", is loaded = " << mIsLoaded << llendl;
LLConversationItemParticipant* participant = NULL;
child_list_t::iterator iter;
for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
@@ -186,21 +299,34 @@ void LLConversationItemSession::dumpDebugData()
LLConversationItemParticipant::LLConversationItemParticipant(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
LLConversationItem(display_name,uuid,root_view_model),
mIsMuted(false),
- mIsModerator(false)
+ mIsModerator(false),
+ mDistToAgent(-1.0)
{
mConvType = CONV_PARTICIPANT;
}
LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) :
- LLConversationItem(uuid,root_view_model)
+ LLConversationItem(uuid,root_view_model),
+ mIsMuted(false),
+ mIsModerator(false),
+ mDistToAgent(-1.0)
{
mConvType = CONV_PARTICIPANT;
}
+void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ buildParticipantMenuOptions(items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_name)
{
- mName = av_name.mDisplayName;
- // *TODO : we should also store that one, to be used in the tooltip : av_name.mUsername
+ mName = (av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername);
+ mDisplayName = (av_name.mDisplayName.empty() ? av_name.mUsername : av_name.mDisplayName);
mNeedsRefresh = true;
if (mParent)
{
@@ -210,13 +336,14 @@ void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_nam
void LLConversationItemParticipant::dumpDebugData()
{
- llinfos << "Merov debug : participant, uuid = " << mUUID << ", name = " << mName << ", muted = " << mIsMuted << ", moderator = " << mIsModerator << llendl;
+ llinfos << "Merov debug : participant, uuid = " << mUUID << ", name = " << mName << ", display name = " << mDisplayName << ", muted = " << mIsMuted << ", moderator = " << mIsModerator << llendl;
}
//
// LLConversationSort
//
+// Comparison operator: returns "true" is a comes before b, "false" otherwise
bool LLConversationSort::operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const
{
LLConversationItem::EConversationType type_a = a->getType();
@@ -224,54 +351,93 @@ bool LLConversationSort::operator()(const LLConversationItem* const& a, const LL
if ((type_a == LLConversationItem::CONV_PARTICIPANT) && (type_b == LLConversationItem::CONV_PARTICIPANT))
{
- // If both are participants
+ // If both items are participants
U32 sort_order = getSortOrderParticipants();
if (sort_order == LLConversationFilter::SO_DATE)
{
- F32 time_a = 0.0;
- F32 time_b = 0.0;
- if (a->getTime(time_a) && b->getTime(time_b))
+ F64 time_a = 0.0;
+ F64 time_b = 0.0;
+ bool has_time_a = a->getTime(time_a);
+ bool has_time_b = b->getTime(time_b);
+ if (has_time_a && has_time_b)
{
+ // Most recent comes first
return (time_a > time_b);
}
+ else if (has_time_a || has_time_b)
+ {
+ // If we have only one time available, the element with time must come first
+ return has_time_a;
+ }
+ // If no time available, we'll default to sort by name at the end of this method
}
else if (sort_order == LLConversationFilter::SO_DISTANCE)
{
- F32 dist_a = 0.0;
- F32 dist_b = 0.0;
- if (a->getDistanceToAgent(dist_a) && b->getDistanceToAgent(dist_b))
+ F64 dist_a = 0.0;
+ F64 dist_b = 0.0;
+ bool has_dist_a = a->getDistanceToAgent(dist_a);
+ bool has_dist_b = b->getDistanceToAgent(dist_b);
+ if (has_dist_a && has_dist_b)
{
- return (dist_a > dist_b);
+ // Closest comes first
+ return (dist_a < dist_b);
}
+ else if (has_dist_a || has_dist_b)
+ {
+ // If we have only one distance available, the element with it must come first
+ return has_dist_a;
+ }
+ // If no distance available, we'll default to sort by name at the end of this method
}
}
else if ((type_a > LLConversationItem::CONV_PARTICIPANT) && (type_b > LLConversationItem::CONV_PARTICIPANT))
{
// If both are sessions
U32 sort_order = getSortOrderSessions();
- if (sort_order == LLConversationFilter::SO_DATE)
+ if ((type_a == LLConversationItem::CONV_SESSION_NEARBY) || (type_b == LLConversationItem::CONV_SESSION_NEARBY))
{
- F32 time_a = 0.0;
- F32 time_b = 0.0;
- if (a->getTime(time_a) && b->getTime(time_b))
+ // If one is the nearby session, put nearby session *always* first
+ return (type_a == LLConversationItem::CONV_SESSION_NEARBY);
+ }
+ else if (sort_order == LLConversationFilter::SO_DATE)
+ {
+ // Sort by time
+ F64 time_a = 0.0;
+ F64 time_b = 0.0;
+ bool has_time_a = a->getTime(time_a);
+ bool has_time_b = b->getTime(time_b);
+ if (has_time_a && has_time_b)
{
+ // Most recent comes first
return (time_a > time_b);
}
+ else if (has_time_a || has_time_b)
+ {
+ // If we have only one time available, the element with time must come first
+ return has_time_a;
+ }
+ // If no time available, we'll default to sort by name at the end of this method
}
else if (sort_order == LLConversationFilter::SO_SESSION_TYPE)
{
- return (type_a < type_b);
+ if (type_a != type_b)
+ {
+ // Lowest types come first. See LLConversationItem definition of types
+ return (type_a < type_b);
+ }
+ // If types are identical, we'll default to sort by name at the end of this method
}
}
else
{
- // If one is a participant and the other a session, the session is always "less" than the participant
+ // If one item is a participant and the other a session, the session comes before the participant
// so we simply compare the type
// Notes: as a consequence, CONV_UNKNOWN (which should never get created...) always come first
- return (type_a < type_b);
+ return (type_a > type_b);
}
- // By default, in all other possible cases (including sort order of type LLConversationFilter::SO_NAME of course), sort by name
- S32 compare = LLStringUtil::compareDict(a->getDisplayName(), b->getDisplayName());
+ // By default, in all other possible cases (including sort order type LLConversationFilter::SO_NAME of course),
+ // we sort by name
+ S32 compare = LLStringUtil::compareDict(a->getName(), b->getName());
return (compare < 0);
}
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index dbc04223af..bc72cd96ea 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -41,6 +41,8 @@ class LLConversationItemParticipant;
typedef std::map<LLUUID, LLConversationItem*> conversations_items_map;
typedef std::map<LLUUID, LLFolderViewItem*> conversations_widgets_map;
+typedef std::vector<std::string> menuentry_vec_t;
+
// Conversation items: we hold a list of those and create an LLFolderViewItem widget for each
// that we tuck into the mConversationsListPanel.
class LLConversationItem : public LLFolderViewModelItemCommon
@@ -104,10 +106,10 @@ public:
virtual void selectItem(void) { }
virtual void showProperties(void);
- // Methods used in sorting (see LLConversationSort::operator()
+ // Methods used in sorting (see LLConversationSort::operator())
EConversationType const getType() const { return mConvType; }
- virtual const bool getTime(F32& time) const { return false; }
- virtual const bool getDistanceToAgent(F32& distance) const { return false; }
+ virtual const bool getTime(F64& time) const { time = mLastActiveTime; return (time > 0.1); }
+ virtual const bool getDistanceToAgent(F64& distance) const { return false; }
// This method will be called to determine if a drop can be
// performed, and will set drop to TRUE if a drop is
@@ -124,11 +126,14 @@ public:
void resetRefresh() { mNeedsRefresh = false; }
bool needsRefresh() { return mNeedsRefresh; }
+ void buildParticipantMenuOptions(menuentry_vec_t& items);
+
protected:
std::string mName; // Name of the session or the participant
LLUUID mUUID; // UUID of the session or the participant
EConversationType mConvType; // Type of conversation item
bool mNeedsRefresh; // Flag signaling to the view that something changed for this item
+ F64 mLastActiveTime;
};
class LLConversationItemSession : public LLConversationItem
@@ -149,9 +154,15 @@ public:
void setParticipantIsMuted(const LLUUID& participant_id, bool is_muted);
void setParticipantIsModerator(const LLUUID& participant_id, bool is_moderator);
+ void setTimeNow(const LLUUID& participant_id);
+ void setDistance(const LLUUID& participant_id, F64 dist);
bool isLoaded() { return mIsLoaded; }
+ void buildContextMenu(LLMenuGL& menu, U32 flags);
+ void addVoiceOptions(menuentry_vec_t& items);
+ virtual const bool getTime(F64& time) const;
+
void dumpDebugData();
private:
@@ -165,18 +176,27 @@ public:
LLConversationItemParticipant(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model);
virtual ~LLConversationItemParticipant() {}
+ virtual const std::string& getDisplayName() const { return mDisplayName; }
+
bool isMuted() { return mIsMuted; }
bool isModerator() {return mIsModerator; }
void setIsMuted(bool is_muted) { mIsMuted = is_muted; mNeedsRefresh = true; }
void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; }
-
+ void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; }
+ void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; }
+
+ void buildContextMenu(LLMenuGL& menu, U32 flags);
void onAvatarNameCache(const LLAvatarName& av_name);
+ virtual const bool getDistanceToAgent(F64& dist) const { dist = mDistToAgent; return (dist >= 0.0); }
+
void dumpDebugData();
private:
bool mIsMuted; // default is false
bool mIsModerator; // default is false
+ std::string mDisplayName;
+ F64 mDistToAgent; // Distance to the agent. A negative (meaningless) value means the distance has not been set.
};
// We don't want to ever filter conversations but we need to declare that class to create a conversation view model.
@@ -260,4 +280,15 @@ public:
private:
};
+// Utility function to hide all entries except those in the list
+// Can be called multiple times on the same menu (e.g. if multiple items
+// are selected). If "append" is false, then only common enabled items
+// are set as enabled.
+
+//(defined in inventorybridge.cpp)
+//TODO: Gilbert Linden - Refactor to make this function non-global
+void hide_context_entries(LLMenuGL& menu,
+ const menuentry_vec_t &entries_to_show,
+ const menuentry_vec_t &disabled_entries);
+
#endif // LL_LLCONVERSATIONMODEL_H
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index 721abd5892..d4eb551f7a 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -30,10 +30,12 @@
#include "llconversationview.h"
#include <boost/bind.hpp>
+#include "llagentdata.h"
#include "llconversationmodel.h"
#include "llimconversation.h"
#include "llimfloatercontainer.h"
#include "llfloaterreg.h"
+#include "llgroupiconctrl.h"
#include "lluictrlfactory.h"
//
@@ -43,6 +45,30 @@ static LLDefaultChildRegistry::Register<LLConversationViewSession> r_conversatio
const LLColor4U DEFAULT_WHITE(255, 255, 255);
+class LLNearbyVoiceClientStatusObserver : public LLVoiceClientStatusObserver
+{
+public:
+
+ LLNearbyVoiceClientStatusObserver(LLConversationViewSession* conv)
+ : conversation(conv)
+ {}
+
+ virtual void onChange(EStatusType status, const std::string &channelURI, bool proximal)
+ {
+ if (conversation
+ && status != STATUS_JOINING
+ && status != STATUS_LEFT_CHANNEL
+ && LLVoiceClient::getInstance()->voiceEnabled()
+ && LLVoiceClient::getInstance()->isVoiceWorking())
+ {
+ conversation->showVoiceIndicator();
+ }
+ }
+
+private:
+ LLConversationViewSession* conversation;
+};
+
LLConversationViewSession::Params::Params() :
container()
{}
@@ -51,157 +77,109 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes
LLFolderViewFolder(p),
mContainer(p.container),
mItemPanel(NULL),
- mSessionTitle(NULL)
+ mCallIconLayoutPanel(NULL),
+ mSessionTitle(NULL),
+ mSpeakingIndicator(NULL),
+ mVoiceClientObserver(NULL),
+ mMinimizedMode(false)
{
}
+LLConversationViewSession::~LLConversationViewSession()
+{
+ mActiveVoiceChannelConnection.disconnect();
+
+ if(LLVoiceClient::instanceExists() && mVoiceClientObserver)
+ {
+ LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver);
+ }
+}
+
BOOL LLConversationViewSession::postBuild()
{
LLFolderViewItem::postBuild();
mItemPanel = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>("panel_conversation_list_item.xml", NULL, LLPanel::child_registry_t::instance());
-
addChild(mItemPanel);
+ mCallIconLayoutPanel = mItemPanel->getChild<LLPanel>("call_icon_panel");
mSessionTitle = mItemPanel->getChild<LLTextBox>("conversation_title");
- refresh();
+ mActiveVoiceChannelConnection = LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLConversationViewSession::onCurrentVoiceSessionChanged, this, _1));
+ mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicatorn");
- return TRUE;
-}
-
-void LLConversationViewSession::draw()
-{
-// *TODO Seth PE: remove the code duplicated from LLFolderViewFolder::draw()
-// ***** LLFolderViewFolder::draw() code begin *****
- if (mAutoOpenCountdown != 0.f)
- {
- mControlLabelRotation = mAutoOpenCountdown * -90.f;
- }
- else if (isOpen())
- {
- mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f));
- }
- else
- {
- mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f));
- }
-// ***** LLFolderViewFolder::draw() code end *****
-
-// *TODO Seth PE: remove the code duplicated from LLFolderViewItem::draw()
-// ***** LLFolderViewItem::draw() code begin *****
-
- static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
- static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
- static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
- static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
-
- const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
- const S32 TOP_PAD = default_params.item_top_pad;
- const S32 FOCUS_LEFT = 1;
-
- getViewModelItem()->update();
-
- //--------------------------------------------------------------------------------//
- // Draw open folder arrow
- //
- if (hasVisibleChildren() || getViewModelItem()->hasChildren())
- {
- LLUIImage* arrow_image = default_params.folder_arrow_image;
- gl_draw_scaled_rotated_image(
- mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD - TOP_PAD,
- ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, arrow_image->getImage(), sFgColor);
- }
-
-
- //--------------------------------------------------------------------------------//
- // Draw highlight for selected items
- //
- const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
- const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled
- const S32 focus_top = getRect().getHeight();
- const S32 focus_bottom = getRect().getHeight() - mItemHeight;
- const bool folder_open = (getRect().getHeight() > mItemHeight + 4);
- if (mIsSelected) // always render "current" item. Only render other selected items if mShowSingleSelection is FALSE
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
+ if (vmi)
{
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLColor4 bg_color = sHighlightBgColor;
- if (!mIsCurSelection)
+ switch(vmi->getType())
{
- // do time-based fade of extra objects
- F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f);
- if (getRoot() && getRoot()->getShowSingleSelection())
- {
- // fading out
- bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f);
- }
- else
+ case LLConversationItem::CONV_PARTICIPANT:
+ case LLConversationItem::CONV_SESSION_1_ON_1:
+ {
+ LLIMModel::LLIMSession* session= LLIMModel::instance().findIMSession(vmi->getUUID());
+ if (session)
{
- // fading in
- bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]);
+ LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon");
+ icon->setVisible(true);
+ icon->setValue(session->mOtherParticipantID);
+ mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true);
}
+ break;
}
- gl_rect_2d(FOCUS_LEFT,
- focus_top,
- getRect().getWidth() - 2,
- focus_bottom,
- bg_color, filled);
- if (mIsCurSelection)
+ case LLConversationItem::CONV_SESSION_AD_HOC:
{
- gl_rect_2d(FOCUS_LEFT,
- focus_top,
- getRect().getWidth() - 2,
- focus_bottom,
- sFocusOutlineColor, FALSE);
+ LLGroupIconCtrl* icon = mItemPanel->getChild<LLGroupIconCtrl>("group_icon");
+ icon->setVisible(true);
+ mSpeakingIndicator->setSpeakerId(gAgentID, vmi->getUUID(), true);
}
- if (folder_open)
+ case LLConversationItem::CONV_SESSION_GROUP:
{
- gl_rect_2d(FOCUS_LEFT,
- focus_bottom + 1, // overlap with bottom edge of above rect
- getRect().getWidth() - 2,
- 0,
- sFocusOutlineColor, FALSE);
- if (show_context)
+ LLGroupIconCtrl* icon = mItemPanel->getChild<LLGroupIconCtrl>("group_icon");
+ icon->setVisible(true);
+ icon->setValue(vmi->getUUID());
+ mSpeakingIndicator->setSpeakerId(gAgentID, vmi->getUUID(), true);
+ break;
+ }
+ case LLConversationItem::CONV_SESSION_NEARBY:
+ {
+ LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("nearby_chat_icon");
+ icon->setVisible(true);
+ mSpeakingIndicator->setSpeakerId(gAgentID, LLUUID::null, true);
+ if(LLVoiceClient::instanceExists())
{
- gl_rect_2d(FOCUS_LEFT,
- focus_bottom + 1,
- getRect().getWidth() - 2,
- 0,
- sHighlightBgColor, TRUE);
+ LLNearbyVoiceClientStatusObserver* mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this);
+ LLVoiceClient::getInstance()->addObserver(mVoiceClientObserver);
}
+ break;
+ }
+ default:
+ break;
}
- }
- else if (mIsMouseOverTitle)
- {
- gl_rect_2d(FOCUS_LEFT,
- focus_top,
- getRect().getWidth() - 2,
- focus_bottom,
- sMouseOverColor, FALSE);
}
- //--------------------------------------------------------------------------------//
- // Draw DragNDrop highlight
- //
- if (mDragAndDropTarget)
+ refresh();
+
+ return TRUE;
+}
+
+void LLConversationViewSession::draw()
+{
+ getViewModelItem()->update();
+
+ const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
+ const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
+
+ // we don't draw the open folder arrow in minimized mode
+ if (!mMinimizedMode)
{
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gl_rect_2d(FOCUS_LEFT,
- focus_top,
- getRect().getWidth() - 2,
- focus_bottom,
- sHighlightBgColor, FALSE);
- if (folder_open)
- {
- gl_rect_2d(FOCUS_LEFT,
- focus_bottom + 1, // overlap with bottom edge of above rect
- getRect().getWidth() - 2,
- 0,
- sHighlightBgColor, FALSE);
- }
- mDragAndDropTarget = FALSE;
+ // update the rotation angle of open folder arrow
+ updateLabelRotation();
+
+ drawOpenFolderArrow(default_params, sFgColor);
}
-// ***** LLFolderViewItem::draw() code end *****
+
+ // draw highlight for selected items
+ drawHighlight(show_context, true, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
// draw children if root folder, or any other folder that is open or animating to closed state
bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this)
@@ -227,7 +205,8 @@ void LLConversationViewSession::draw()
// virtual
S32 LLConversationViewSession::arrange(S32* width, S32* height)
{
- LLRect rect(getIndentation() + ARROW_SIZE,
+ S32 h_pad = getIndentation() + mArrowSize;
+ LLRect rect(mMinimizedMode ? getLocalRect().mLeft : h_pad,
getLocalRect().mTop,
getLocalRect().mRight,
getLocalRect().mTop - getItemHeight());
@@ -236,6 +215,16 @@ S32 LLConversationViewSession::arrange(S32* width, S32* height)
return LLFolderViewFolder::arrange(width, height);
}
+// virtual
+void LLConversationViewSession::toggleOpen()
+{
+ // conversations should not be opened while in minimized mode
+ if (!mMinimizedMode)
+ {
+ LLFolderViewFolder::toggleOpen();
+ }
+}
+
void LLConversationViewSession::selectItem()
{
@@ -257,6 +246,18 @@ void LLConversationViewSession::selectItem()
LLFolderViewItem::selectItem();
}
+void LLConversationViewSession::toggleMinimizedMode(bool is_minimized)
+{
+ mMinimizedMode = is_minimized;
+
+ // hide the layout stack which contains all item's child widgets
+ // except for the icon which we display in minimized mode
+ getChild<LLView>("conversation_item_stack")->setVisible(!mMinimizedMode);
+
+ S32 h_pad = getIndentation() + mArrowSize;
+ mItemPanel->translate(mMinimizedMode ? -h_pad : h_pad, 0);
+}
+
void LLConversationViewSession::setVisibleIfDetached(BOOL visible)
{
// Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized
@@ -288,6 +289,14 @@ LLConversationViewParticipant* LLConversationViewSession::findParticipant(const
return (iter == getItemsEnd() ? NULL : participant);
}
+void LLConversationViewSession::showVoiceIndicator()
+{
+ if (LLVoiceChannel::getCurrentVoiceChannel()->getSessionID().isNull())
+ {
+ mCallIconLayoutPanel->setVisible(true);
+ }
+}
+
void LLConversationViewSession::refresh()
{
// Refresh the session view from its model data
@@ -305,6 +314,25 @@ void LLConversationViewSession::refresh()
LLFolderViewFolder::refresh();
}
+void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id)
+{
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
+
+ if (vmi)
+ {
+ bool is_active = vmi->getUUID() == session_id;
+ bool is_nearby = vmi->getType() == LLConversationItem::CONV_SESSION_NEARBY;
+
+ if (is_nearby)
+ {
+ mSpeakingIndicator->setSpeakerId(is_active ? gAgentID : LLUUID::null);
+ }
+
+ mSpeakingIndicator->switchIndicator(is_active);
+ mCallIconLayoutPanel->setVisible(is_active);
+ }
+}
+
//
// Implementation of conversations list participant (avatar) widgets
//
@@ -336,7 +364,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti
applyXUILayout(avatar_icon_params, this);
LLAvatarIconCtrl * avatarIcon = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_icon_params);
addChild(avatarIcon);
-
+
LLButton::Params info_button_params(params.info_button());
applyXUILayout(info_button_params, this);
LLButton * button = LLUICtrlFactory::create<LLButton>(info_button_params);
@@ -366,7 +394,7 @@ BOOL LLConversationViewParticipant::postBuild()
sStaticInitialized = true;
}
- computeLabelRightPadding();
+ updateChildren();
return LLFolderViewItem::postBuild();
}
@@ -381,16 +409,11 @@ void LLConversationViewParticipant::draw()
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled
- const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
- const S32 TOP_PAD = default_params.item_top_pad;
-
const LLFontGL* font = getLabelFontForStyle(mLabelStyle);
F32 right_x = 0;
- //TEXT_PAD, TOP_PAD, ICON_PAD and mIndentation are temporary values and will non-const eventually since they don't
- //apply to every single layout
- F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;
- F32 text_left = (F32)(mAvatarIcon->getRect().mRight + ICON_PAD + mIndentation);
+ F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad;
+ F32 text_left = (F32)getLabelXPos();
LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor;
drawHighlight(show_context, filled, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
@@ -437,15 +460,20 @@ void LLConversationViewParticipant::onInfoBtnClick()
void LLConversationViewParticipant::onMouseEnter(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(true);
- computeLabelRightPadding();
+ updateChildren();
LLFolderViewItem::onMouseEnter(x, y, mask);
}
void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(false);
- computeLabelRightPadding();
- LLFolderViewItem::onMouseEnter(x, y, mask);
+ updateChildren();
+ LLFolderViewItem::onMouseLeave(x, y, mask);
+}
+
+S32 LLConversationViewParticipant::getLabelXPos()
+{
+ return mAvatarIcon->getRect().mRight + mIconPad;
}
// static
@@ -463,12 +491,14 @@ void LLConversationViewParticipant::initChildrenWidths(LLConversationViewPartici
llassert(index == 0);
}
-void LLConversationViewParticipant::computeLabelRightPadding()
+void LLConversationViewParticipant::updateChildren()
{
- mLabelPaddingRight = DEFAULT_TEXT_PADDING_RIGHT;
+ mLabelPaddingRight = DEFAULT_LABEL_PADDING_RIGHT;
LLView* control;
S32 ctrl_width;
+ LLRect controlRect;
+ //Cycles through controls starting from right to left
for (S32 i = 0; i < ALIC_COUNT; ++i)
{
control = getItemChildView((EAvatarListItemChildIndex)i);
@@ -476,9 +506,22 @@ void LLConversationViewParticipant::computeLabelRightPadding()
// skip invisible views
if (!control->getVisible()) continue;
+ //Get current pos/dimensions
+ controlRect = control->getRect();
+
ctrl_width = sChildrenWidths[i]; // including space between current & left controls
// accumulate the amount of space taken by the controls
mLabelPaddingRight += ctrl_width;
+
+ //Reposition visible controls in case adjacent controls to the right are hidden.
+ controlRect.setLeftTopAndSize(
+ getLocalRect().getWidth() - mLabelPaddingRight,
+ controlRect.mTop,
+ controlRect.getWidth(),
+ controlRect.getHeight());
+
+ //Sets the new position
+ control->setShape(controlRect);
}
}
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 075ad09d5b..c81c70b456 100755
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -38,6 +38,8 @@ class LLIMFloaterContainer;
class LLConversationViewSession;
class LLConversationViewParticipant;
+class LLVoiceClientStatusObserver;
+
// Implementation of conversations list session widgets
class LLConversationViewSession : public LLFolderViewFolder
@@ -57,7 +59,7 @@ protected:
LLIMFloaterContainer* mContainer;
public:
- virtual ~LLConversationViewSession( void ) { }
+ virtual ~LLConversationViewSession();
virtual void selectItem();
/*virtual*/ BOOL postBuild();
@@ -65,14 +67,31 @@ public:
/*virtual*/ S32 arrange(S32* width, S32* height);
+ /*virtual*/ void toggleOpen();
+
+ void toggleMinimizedMode(bool is_minimized);
+
void setVisibleIfDetached(BOOL visible);
LLConversationViewParticipant* findParticipant(const LLUUID& participant_id);
+ void showVoiceIndicator();
+
virtual void refresh();
private:
- LLPanel* mItemPanel;
- LLTextBox* mSessionTitle;
+
+ void onCurrentVoiceSessionChanged(const LLUUID& session_id);
+
+ LLPanel* mItemPanel;
+ LLPanel* mCallIconLayoutPanel;
+ LLTextBox* mSessionTitle;
+ LLOutputMonitorCtrl* mSpeakingIndicator;
+
+ bool mMinimizedMode;
+
+ LLVoiceClientStatusObserver* mVoiceClientObserver;
+
+ boost::signals2::connection mActiveVoiceChannelConnection;
};
// Implementation of conversations list participant (avatar) widgets
@@ -101,6 +120,8 @@ public:
void onMouseEnter(S32 x, S32 y, MASK mask);
void onMouseLeave(S32 x, S32 y, MASK mask);
+ /*virtual*/ S32 getLabelXPos();
+
protected:
friend class LLUICtrlFactory;
LLConversationViewParticipant( const Params& p );
@@ -125,7 +146,7 @@ private:
static bool sStaticInitialized; // this variable is introduced to improve code readability
static S32 sChildrenWidths[ALIC_COUNT];
static void initChildrenWidths(LLConversationViewParticipant* self);
- void computeLabelRightPadding();
+ void updateChildren();
LLView* getItemChildView(EAvatarListItemChildIndex child_view_index);
};
diff --git a/indra/newview/llfloaterchatvoicevolume.cpp b/indra/newview/llfloaterchatvoicevolume.cpp
new file mode 100644
index 0000000000..3c76a3a43c
--- /dev/null
+++ b/indra/newview/llfloaterchatvoicevolume.cpp
@@ -0,0 +1,44 @@
+/**
+ * @file llfloaterchatvoicevolume.cpp
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterchatvoicevolume.h"
+
+LLFloaterChatVoiceVolume::LLFloaterChatVoiceVolume(const LLSD& key)
+: LLInspect(key)
+{
+}
+
+void LLFloaterChatVoiceVolume::onOpen(const LLSD& key)
+{
+ LLInspect::onOpen(key);
+ LLUI::positionViewNearMouse(this);
+}
+
+LLFloaterChatVoiceVolume::~LLFloaterChatVoiceVolume()
+{
+ LLTransientFloaterMgr::getInstance()->removeControlView(this);
+};
diff --git a/indra/newview/llfloaterchatvoicevolume.h b/indra/newview/llfloaterchatvoicevolume.h
new file mode 100644
index 0000000000..61ad92b6da
--- /dev/null
+++ b/indra/newview/llfloaterchatvoicevolume.h
@@ -0,0 +1,44 @@
+/**
+ * @file llfloaterchatvoicevolume.h
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLFLOATERCHATVOICEVOLUME_H_
+#define LLFLOATERCHATVOICEVOLUME_H_
+
+#include "llinspect.h"
+#include "lltransientfloatermgr.h"
+
+class LLFloaterChatVoiceVolume : public LLInspect, LLTransientFloater
+{
+public:
+
+ LLFloaterChatVoiceVolume(const LLSD& key);
+ virtual ~LLFloaterChatVoiceVolume();
+
+ virtual void onOpen(const LLSD& key);
+
+ /*virtual*/ LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::GLOBAL; }
+};
+
+#endif /* LLFLOATERCHATVOICEVOLUME_H_ */
diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp
index a2efe63546..2ad7f9b193 100644
--- a/indra/newview/llimconversation.cpp
+++ b/indra/newview/llimconversation.cpp
@@ -42,18 +42,19 @@
const F32 REFRESH_INTERVAL = 0.2f;
-LLIMConversation::LLIMConversation(const LLUUID& session_id)
+LLIMConversation::LLIMConversation(const LLSD& session_id)
: LLTransientDockableFloater(NULL, true, session_id)
, mIsP2PChat(false)
, mExpandCollapseBtn(NULL)
, mTearOffBtn(NULL)
, mCloseBtn(NULL)
- , mSessionID(session_id)
+ , mSessionID(session_id.asUUID())
, mParticipantList(NULL)
, mChatHistory(NULL)
, mInputEditor(NULL)
, mInputEditorTopPad(0)
, mRefreshTimer(new LLTimer())
+ , mHasFocus(false)
{
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
@@ -216,10 +217,10 @@ void LLIMConversation::onFocusReceived()
LLTransientDockableFloater::onFocusReceived();
- mHasFocus = mHaveFocus;
- mHaveFocus = true;
+ mHadFocus = mHasFocus;
+ mHasFocus = true;
- if (! mHasFocus)
+ if (! mHadFocus)
{
LLIMFloaterContainer* container = LLIMFloaterContainer::getInstance();
container->setConvItemSelect(mSessionID);
@@ -229,7 +230,7 @@ void LLIMConversation::onFocusReceived()
void LLIMConversation::onFocusLost()
{
setBackgroundOpaque(false);
- mHaveFocus = false;
+ mHasFocus = false;
LLTransientDockableFloater::onFocusLost();
}
@@ -250,6 +251,14 @@ std::string LLIMConversation::appendTime()
void LLIMConversation::appendMessage(const LLChat& chat, const LLSD &args)
{
+ // Update the participant activity time
+ LLIMFloaterContainer* im_box = LLIMFloaterContainer::findInstance();
+ if (im_box)
+ {
+ im_box->setTimeNow(mSessionID,chat.mFromID);
+ }
+
+
LLChat& tmp_chat = const_cast<LLChat&>(chat);
if(tmp_chat.mTimeStr.empty())
@@ -415,6 +424,7 @@ void LLIMConversation::updateHeaderAndToolbar()
mExpandCollapseBtn->setEnabled(!is_torn_off || !mIsP2PChat);
mTearOffBtn->setImageOverlay(getString(is_torn_off? "return_icon" : "tear_off_icon"));
+ mTearOffBtn->setToolTip(getString(!is_torn_off? "tooltip_to_separate_window" : "tooltip_to_main_window"));
mCloseBtn->setVisible(!is_torn_off && !mIsNearbyChat);
diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h
index e09ba79a6a..c54081d316 100644
--- a/indra/newview/llimconversation.h
+++ b/indra/newview/llimconversation.h
@@ -47,7 +47,7 @@ class LLIMConversation
public:
LOG_CLASS(LLIMConversation);
- LLIMConversation(const LLUUID& session_id);
+ LLIMConversation(const LLSD& session_id);
~LLIMConversation();
// reload all message with new settings of visual modes
@@ -140,8 +140,8 @@ private:
LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
+ bool mHadFocus;
bool mHasFocus;
- bool mHaveFocus;
};
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 2474fe0891..99337bd5f3 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -111,23 +111,25 @@ void LLIMFloater::onClickCloseBtn()
{
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID);
- if (session == NULL)
+ if (session != NULL)
{
- llwarns << "Empty session with id: " << (mSessionID.asString()) << llendl;
- return;
- }
+ bool is_call_with_chat = session->isGroupSessionType()
+ || session->isAdHocSessionType() || session->isP2PSessionType();
- bool is_call_with_chat = session->isGroupSessionType()
- || session->isAdHocSessionType() || session->isP2PSessionType();
-
- LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
- if (is_call_with_chat && voice_channel != NULL
- && voice_channel->isActive())
+ if (is_call_with_chat && voice_channel != NULL
+ && voice_channel->isActive())
+ {
+ LLSD payload;
+ payload["session_id"] = mSessionID;
+ LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
+ return;
+ }
+ }
+ else
{
- LLSD payload;
- payload["session_id"] = mSessionID;
- LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
+ llwarns << "Empty session with id: " << (mSessionID.asString()) << llendl;
return;
}
@@ -582,13 +584,14 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
build_names_string(temp_uuids, ui_title);
updateSessionName(ui_title, ui_title);
}
- }
+}
-//static
-LLIMFloater* LLIMFloater::addToIMContainer(const LLUUID& session_id)
+void LLIMFloater::addToHost(const LLUUID& session_id, const bool force)
{
- if (!gIMMgr->hasSession(session_id))
- return NULL;
+ if (!LLIMConversation::isChatMultiTab() || !gIMMgr->hasSession(session_id))
+ {
+ return;
+ }
// Test the existence of the floater before we try to create it
bool exist = findInstance(session_id);
@@ -612,19 +615,22 @@ LLIMFloater* LLIMFloater::addToIMContainer(const LLUUID& session_id)
}
}
- if (floater_container && floater_container->getVisible())
- {
- floater->openFloater(floater->getKey());
- floater->setVisible(TRUE);
- }
- else
+ if (force)
{
- floater->setVisible(FALSE);
+ if (floater_container && floater_container->getVisible())
+ {
+ floater->openFloater(floater->getKey());
+ floater->setVisible(TRUE);
+ }
+ else
+ {
+ floater->setVisible(FALSE);
+ }
}
}
- return floater;
}
+
//static
LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
{
@@ -907,6 +913,7 @@ void LLIMFloater::updateMessages()
chat.mText = message;
}
+ // Add the message to the chat log
appendMessage(chat);
mLastMessageIndex = msg["index"].asInteger();
@@ -1322,23 +1329,6 @@ void LLIMFloater::onIMChicletCreated( const LLUUID& session_id )
{
LLIMFloater::addToHost(session_id);
}
-void LLIMFloater::addToHost(const LLUUID& session_id)
- {
- if (LLIMConversation::isChatMultiTab())
-{
- LLIMFloaterContainer* im_box = LLIMFloaterContainer::findInstance();
- if (!im_box)
- {
- im_box = LLIMFloaterContainer::getInstance();
- }
-
- if (im_box && !LLIMFloater::findInstance(session_id))
- {
- LLIMFloater* new_tab = LLIMFloater::getInstance(session_id);
- im_box->addFloater(new_tab, FALSE, LLTabContainer::END);
- }
- }
-}
boost::signals2::connection LLIMFloater::setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb)
{
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index e4a67a3d56..5ed1d1ab35 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -71,14 +71,13 @@ public:
static LLIMFloater* findInstance(const LLUUID& session_id);
static LLIMFloater* getInstance(const LLUUID& session_id);
- static void addToHost(const LLUUID& session_id);
+ static void addToHost(const LLUUID& session_id, const bool force = false);
// LLFloater overrides
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
// Make IM conversion visible and update the message history
static LLIMFloater* show(const LLUUID& session_id);
- static LLIMFloater* addToIMContainer(const LLUUID& session_id);
// Toggle panel specified by session_id
// Returns true iff panel became visible
@@ -128,6 +127,7 @@ public:
static void onIMChicletCreated(const LLUUID& session_id);
bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; }
+ const LLUUID& getOtherParticipantUUID() {return mOtherParticipantUUID;}
static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb);
static floater_showed_signal_t sIMFloaterShowedSignal;
diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp
index 4e0fba9502..4af170b3db 100755..100644
--- a/indra/newview/llimfloatercontainer.cpp
+++ b/indra/newview/llimfloatercontainer.cpp
@@ -39,6 +39,7 @@
#include "llavatariconctrl.h"
#include "llavatarnamecache.h"
#include "llcallbacklist.h"
+#include "llgroupactions.h"
#include "llgroupiconctrl.h"
#include "llfloateravatarpicker.h"
#include "llfloaterpreference.h"
@@ -47,6 +48,7 @@
#include "llviewercontrol.h"
#include "llconversationview.h"
#include "llcallbacklist.h"
+#include "llworld.h"
//
// LLIMFloaterContainer
@@ -57,8 +59,14 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
mConversationsRoot(NULL),
mInitialized(false)
{
+ mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));
mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLIMFloaterContainer::onCustomAction, this, _2));
- mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));
+
+ mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLIMFloaterContainer::checkContextMenuItem, this, _2));
+ mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLIMFloaterContainer::enableContextMenuItem, this, _2));
+ mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelected, this, _2));
+
+ mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelectedGroup, this, _2));
// Firstly add our self to IMSession observers, so we catch session events
LLIMMgr::getInstance()->addSessionObserver(this);
@@ -85,13 +93,13 @@ LLIMFloaterContainer::~LLIMFloaterContainer()
void LLIMFloaterContainer::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
{
- LLIMFloater::addToIMContainer(session_id);
+ LLIMFloater::addToHost(session_id, true);
addConversationListItem(session_id);
}
void LLIMFloaterContainer::sessionVoiceOrIMStarted(const LLUUID& session_id)
{
- LLIMFloater::addToIMContainer(session_id);
+ LLIMFloater::addToHost(session_id, true);
addConversationListItem(session_id);
}
@@ -106,6 +114,16 @@ void LLIMFloaterContainer::sessionRemoved(const LLUUID& session_id)
removeConversationListItem(session_id);
}
+// static
+void LLIMFloaterContainer::onCurrentChannelChanged(const LLUUID& session_id)
+{
+ if (session_id != LLUUID::null)
+ {
+ LLIMFloater::show(session_id);
+ }
+}
+
+
BOOL LLIMFloaterContainer::postBuild()
{
mNewMessageConnection = LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1));
@@ -132,7 +150,10 @@ BOOL LLIMFloaterContainer::postBuild()
p.listener = base_item;
p.view_model = &mConversationViewModel;
p.root = NULL;
+ p.use_ellipses = true;
+ p.options_menu = "menu_conversation.xml";
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
+ mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
// a scroller for folder view
LLRect scroller_view_rect = mConversationsListPanel->getRect();
@@ -157,8 +178,7 @@ BOOL LLIMFloaterContainer::postBuild()
collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed"));
collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed"));
- LLAvatarNameCache::addUseDisplayNamesCallback(
- boost::bind(&LLIMConversation::processChatHistoryStyleUpdate));
+ LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLIMConversation::processChatHistoryStyleUpdate));
if (! mMessagesPane->isCollapsed())
{
@@ -175,8 +195,11 @@ BOOL LLIMFloaterContainer::postBuild()
mInitialized = true;
- // Add callback: we'll take care of view updates on idle
+ // Add callbacks:
+ // We'll take care of view updates on idle
gIdleCallbacks.addFunction(idle, this);
+ // When display name option change, we need to reload all participant names
+ LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLIMFloaterContainer::processParticipantsStyleUpdate, this));
return TRUE;
}
@@ -220,8 +243,8 @@ void LLIMFloaterContainer::addFloater(LLFloater* floaterp,
floaterp->mCloseSignal.connect(boost::bind(&LLIMFloaterContainer::onCloseFloater, this, session_id));
}
else
- {
- LLUUID avatar_id = LLIMModel::getInstance()->getOtherParticipantID(session_id);
+ { LLUUID avatar_id = session_id.notNull()?
+ LLIMModel::getInstance()->getOtherParticipantID(session_id) : LLUUID();
LLAvatarIconCtrl::Params icon_params;
icon_params.avatar_id = avatar_id;
@@ -329,10 +352,48 @@ void LLIMFloaterContainer::setMinimized(BOOL b)
}
}
+// Update all participants in the conversation lists
+void LLIMFloaterContainer::processParticipantsStyleUpdate()
+{
+ // On each session in mConversationsItems
+ for (conversations_items_map::iterator it_session = mConversationsItems.begin(); it_session != mConversationsItems.end(); it_session++)
+ {
+ // Get the current session descriptors
+ LLConversationItem* session_model = it_session->second;
+ // Iterate through each model participant child
+ LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = session_model->getChildrenBegin();
+ LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd();
+ while (current_participant_model != end_participant_model)
+ {
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
+ // Get the avatar name for this participant id from the cache and update the model
+ LLUUID participant_id = participant_model->getUUID();
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(participant_id,&av_name);
+ // Avoid updating the model though if the cache is still waiting for its first update
+ if (!av_name.mDisplayName.empty())
+ {
+ participant_model->onAvatarNameCache(av_name);
+ }
+ // Bind update to the next cache name signal
+ LLAvatarNameCache::get(participant_id, boost::bind(&LLConversationItemParticipant::onAvatarNameCache, participant_model, _2));
+ // Next participant
+ current_participant_model++;
+ }
+ }
+}
+
// static
void LLIMFloaterContainer::idle(void* user_data)
{
LLIMFloaterContainer* self = static_cast<LLIMFloaterContainer*>(user_data);
+
+ // Update the distance to agent in the nearby chat session if required
+ // Note: it makes no sense of course to update the distance in other session
+ if (self->mConversationViewModel.getSorter().getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE)
+ {
+ self->setNearbyDistances();
+ }
self->mConversationsRoot->update();
}
@@ -385,6 +446,8 @@ void LLIMFloaterContainer::draw()
}
// Reset the need for refresh
session_model->resetRefresh();
+ mConversationViewModel.requestSortAll();
+ mConversationsRoot->arrangeAll();
// Next participant
current_participant_model++;
}
@@ -410,11 +473,11 @@ void LLIMFloaterContainer::tabClose()
}
void LLIMFloaterContainer::setVisible(BOOL visible)
-{
+{ LLNearbyChat* nearby_chat;
if (visible)
{
// Make sure we have the Nearby Chat present when showing the conversation container
- LLIMConversation* nearby_chat = LLFloaterReg::findTypedInstance<LLIMConversation>("nearby_chat");
+ nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat");
if (nearby_chat == NULL)
{
// If not found, force the creation of the nearby chat conversation panel
@@ -424,6 +487,12 @@ void LLIMFloaterContainer::setVisible(BOOL visible)
}
}
+ nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat");
+ if (nearby_chat && !nearby_chat->isHostSet())
+ {
+ nearby_chat->addToHost();
+ }
+
// We need to show/hide all the associated conversations that have been torn off
// (and therefore, are not longer managed by the multifloater),
// so that they show/hide with the conversations manager.
@@ -488,6 +557,22 @@ void LLIMFloaterContainer::collapseConversationsPane(bool collapse)
S32 collapsed_width = mConversationsPane->getMinDim();
updateState(collapse, gSavedPerAccountSettings.getS32("ConversationsListPaneWidth") - collapsed_width);
+
+ for (conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
+ widget_it != mConversationsWidgets.end(); ++widget_it)
+ {
+ LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second);
+ if (widget)
+ {
+ widget->toggleMinimizedMode(collapse);
+
+ // force closing all open conversations when collapsing to minimized state
+ if (collapse)
+ {
+ widget->setOpen(false);
+ }
+}
+ }
}
void LLIMFloaterContainer::updateState(bool collapse, S32 delta_width)
@@ -650,63 +735,338 @@ void LLIMFloaterContainer::setSortOrder(const LLConversationSort& order)
gSavedSettings.setU32("ConversationSortOrder", (U32)order);
}
-void LLIMFloaterContainer::repositioningWidgets()
+void LLIMFloaterContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids)
+{
+ const std::set<LLFolderViewItem*> selectedItems = mConversationsRoot->getSelectionList();
+
+ std::set<LLFolderViewItem*>::const_iterator it = selectedItems.begin();
+ const std::set<LLFolderViewItem*>::const_iterator it_end = selectedItems.end();
+ LLConversationItem * conversationItem;
+
+ for (; it != it_end; ++it)
+ {
+ conversationItem = static_cast<LLConversationItem *>((*it)->getViewModelItem());
+ selected_uuids.push_back(conversationItem->getUUID());
+ }
+}
+
+const LLConversationItem * LLIMFloaterContainer::getCurSelectedViewModelItem()
+{
+ LLConversationItem * conversationItem = NULL;
+
+ if(mConversationsRoot &&
+ mConversationsRoot->getCurSelectedItem() &&
+ mConversationsRoot->getCurSelectedItem()->getViewModelItem())
+ {
+ conversationItem = static_cast<LLConversationItem *>(mConversationsRoot->getCurSelectedItem()->getViewModelItem());
+ }
+
+ return conversationItem;
+}
+
+void LLIMFloaterContainer::getParticipantUUIDs(uuid_vec_t& selected_uuids)
+{
+ //Find the conversation floater associated with the selected id
+ const LLConversationItem * conversationItem = getCurSelectedViewModelItem();
+
+ if(conversationItem->getType() == LLConversationItem::CONV_PARTICIPANT)
+ {
+ getSelectedUUIDs(selected_uuids);
+ }
+ //When a one-on-one conversation exists, retrieve the participant id from the conversation floater
+ else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_1_ON_1)
+ {
+ LLIMFloater *conversationFloater = LLIMFloater::findInstance(conversationItem->getUUID());
+ LLUUID participantID = conversationFloater->getOtherParticipantUUID();
+ selected_uuids.push_back(participantID);
+ }
+}
+
+void LLIMFloaterContainer::doToParticipants(const std::string& command, uuid_vec_t& selectedIDS)
+{
+ if(selectedIDS.size() > 0)
{
- if (!mInitialized)
+ const LLUUID userID = selectedIDS.front();
+
+ if ("view_profile" == command)
+ {
+ LLAvatarActions::showProfile(userID);
+ }
+ else if("im" == command)
+ {
+ LLAvatarActions::startIM(userID);
+ }
+ else if("offer_teleport" == command)
+ {
+ LLAvatarActions::offerTeleport(selectedIDS);
+ }
+ else if("voice_call" == command)
+ {
+ LLAvatarActions::startCall(userID);
+ }
+ else if("chat_history" == command)
+ {
+ LLAvatarActions::viewChatHistory(userID);
+ }
+ else if("add_friend" == command)
+ {
+ LLAvatarActions::requestFriendshipDialog(userID);
+ }
+ else if("remove_friend" == command)
+ {
+ LLAvatarActions::removeFriendDialog(userID);
+ }
+ else if("invite_to_group" == command)
+ {
+ LLAvatarActions::inviteToGroup(userID);
+ }
+ else if("map" == command)
+ {
+ LLAvatarActions::showOnMap(userID);
+ }
+ else if("share" == command)
+ {
+ LLAvatarActions::share(userID);
+ }
+ else if("pay" == command)
+ {
+ LLAvatarActions::pay(userID);
+ }
+ else if("block_unblock" == command)
+ {
+ LLAvatarActions::toggleBlock(userID);
+ }
+}
+}
+
+void LLIMFloaterContainer::doToSelectedConversation(const std::string& command, uuid_vec_t& selectedIDS)
+{
+ //Find the conversation floater associated with the selected id
+ const LLConversationItem * conversationItem = getCurSelectedViewModelItem();
+ LLIMFloater *conversationFloater = LLIMFloater::findInstance(conversationItem->getUUID());
+
+ if(conversationFloater)
+ {
+ //Close the selected conversation
+ if("close_conversation" == command)
+ {
+ LLFloater::onClickClose(conversationFloater);
+ }
+ else if("open_voice_conversation" == command)
+ {
+ gIMMgr->startCall(conversationItem->getUUID());
+ }
+ else if("disconnect_from_voice" == command)
+ {
+ gIMMgr->endCall(conversationItem->getUUID());
+ }
+ else if("chat_history" == command)
+ {
+ LLAvatarActions::viewChatHistory(conversationItem->getUUID());
+ }
+ else
+ {
+ doToParticipants(command, selectedIDS);
+ }
+ }
+}
+
+void LLIMFloaterContainer::doToSelected(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+ const LLConversationItem * conversationItem = getCurSelectedViewModelItem();
+ uuid_vec_t selected_uuids;
+
+ getParticipantUUIDs(selected_uuids);
+
+ if(conversationItem->getType() == LLConversationItem::CONV_PARTICIPANT)
+ {
+ doToParticipants(command, selected_uuids);
+ }
+ else
+ {
+ doToSelectedConversation(command, selected_uuids);
+ }
+}
+
+void LLIMFloaterContainer::doToSelectedGroup(const LLSD& userdata)
+{
+ std::string action = userdata.asString();
+ LLUUID selected_group = getCurSelectedViewModelItem()->getUUID();
+
+ if (action == "group_profile")
+ {
+ LLGroupActions::show(selected_group);
+ }
+ else if (action == "activate_group")
+ {
+ LLGroupActions::activate(selected_group);
+ }
+ else if (action == "leave_group")
+ {
+ LLGroupActions::leave(selected_group);
+ }
+}
+
+bool LLIMFloaterContainer::enableContextMenuItem(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ uuid_vec_t mUUIDs;
+ getParticipantUUIDs(mUUIDs);
+
+ if(mUUIDs.size() <= 0)
+ {
+ return false;
+ }
+
+ // Note: can_block and can_delete is used only for one person selected menu
+ // so we don't need to go over all uuids.
+
+ if (item == std::string("can_block"))
+ {
+ const LLUUID& id = mUUIDs.front();
+ return LLAvatarActions::canBlock(id);
+ }
+ else if (item == std::string("can_add"))
+ {
+ // We can add friends if:
+ // - there are selected people
+ // - and there are no friends among selection yet.
+
+ //EXT-7389 - disable for more than 1
+ if(mUUIDs.size() > 1)
+ {
+ return false;
+ }
+
+ bool result = true;
+
+ uuid_vec_t::const_iterator
+ id = mUUIDs.begin(),
+ uuids_end = mUUIDs.end();
+
+ for (;id != uuids_end; ++id)
+ {
+ if ( LLAvatarActions::isFriend(*id) )
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+ else if (item == std::string("can_delete"))
+ {
+ // We can remove friends if:
+ // - there are selected people
+ // - and there are only friends among selection.
+
+ bool result = (mUUIDs.size() > 0);
+
+ uuid_vec_t::const_iterator
+ id = mUUIDs.begin(),
+ uuids_end = mUUIDs.end();
+
+ for (;id != uuids_end; ++id)
+ {
+ if ( !LLAvatarActions::isFriend(*id) )
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+ else if (item == std::string("can_call"))
+ {
+ return LLAvatarActions::canCall();
+ }
+ else if (item == std::string("can_show_on_map"))
+ {
+ const LLUUID& id = mUUIDs.front();
+
+ return (LLAvatarTracker::instance().isBuddyOnline(id) && is_agent_mappable(id))
+ || gAgent.isGodlike();
+ }
+ else if(item == std::string("can_offer_teleport"))
+ {
+ return LLAvatarActions::canOfferTeleport(mUUIDs);
+ }
+ return false;
+}
+
+bool LLIMFloaterContainer::checkContextMenuItem(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ uuid_vec_t mUUIDs;
+ getParticipantUUIDs(mUUIDs);
+
+ if(mUUIDs.size() > 0 )
+ {
+ if (item == std::string("is_blocked"))
+ {
+ return LLAvatarActions::isBlocked(mUUIDs.front());
+ }
+ }
+
+ return false;
+}
+
+void LLIMFloaterContainer::setConvItemSelect(const LLUUID& session_id)
+{
+ LLFolderViewItem* widget = mConversationsWidgets[session_id];
+ if (widget && mSelectedSession != session_id)
{
- return;
+ mSelectedSession = session_id;
+ (widget->getRoot())->setSelection(widget, FALSE, FALSE);
}
+}
- if (!mConversationsPane->isCollapsed())
+void LLIMFloaterContainer::setTimeNow(const LLUUID& session_id, const LLUUID& participant_id)
+{
+ conversations_items_map::iterator item_it = mConversationsItems.find(session_id);
+ if (item_it != mConversationsItems.end())
{
- S32 list_width = (mConversationsPane->getRect()).getWidth();
- gSavedPerAccountSettings.setS32("ConversationsListPaneWidth", list_width);
- }
- LLRect panel_rect = mConversationsListPanel->getRect();
- S32 item_height = 16;
- int index = 0;
- for (conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
- widget_it != mConversationsWidgets.end();
- widget_it++)
- {
- LLFolderViewFolder* widget = dynamic_cast<LLFolderViewFolder*>(widget_it->second);
- widget->setVisible(TRUE);
- widget->setRect(LLRect(0,
- panel_rect.getHeight() - item_height*index,
- panel_rect.getWidth(),
- panel_rect.getHeight() - item_height*(index+1)));
- index++;
- // Reposition the children as well
- // Merov : This is highly suspiscious but gets the debug hack to work. This needs to be revised though.
- if (widget->getItemsCount() != 0)
+ LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(item_it->second);
+ if (item)
{
- BOOL is_open = widget->isOpen();
- widget->setOpen(TRUE);
- LLFolderViewFolder::items_t::const_iterator current = widget->getItemsBegin();
- LLFolderViewFolder::items_t::const_iterator end = widget->getItemsEnd();
- while (current != end)
- {
- LLFolderViewItem* item = (*current);
- item->setVisible(TRUE);
- item->setRect(LLRect(0,
- panel_rect.getHeight() - item_height*index,
- panel_rect.getWidth(),
- panel_rect.getHeight() - item_height*(index+1)));
- index++;
- current++;
- }
- widget->setOpen(is_open);
+ item->setTimeNow(participant_id);
+ mConversationViewModel.requestSortAll();
+ mConversationsRoot->arrangeAll();
}
}
}
-void LLIMFloaterContainer::setConvItemSelect(LLUUID& session_id)
+void LLIMFloaterContainer::setNearbyDistances()
{
- LLFolderViewItem* widget = mConversationsWidgets[session_id];
- if (widget && mSelectedSession != session_id)
+ // Get the nearby chat session: that's the one with uuid nul in mConversationsItems
+ conversations_items_map::iterator item_it = mConversationsItems.find(LLUUID());
+ if (item_it != mConversationsItems.end())
{
- mSelectedSession = session_id;
- (widget->getRoot())->setSelection(widget, FALSE, FALSE);
+ LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(item_it->second);
+ if (item)
+ {
+ // Get the positions of the nearby avatars and their ids
+ std::vector<LLVector3d> positions;
+ uuid_vec_t avatar_ids;
+ LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
+ // Get the position of the agent
+ const LLVector3d& me_pos = gAgent.getPositionGlobal();
+ // For each nearby avatar, compute and update the distance
+ int avatar_count = positions.size();
+ for (int i = 0; i < avatar_count; i++)
+ {
+ F64 dist = dist_vec_squared(positions[i], me_pos);
+ item->setDistance(avatar_ids[i],dist);
+ }
+ // Also does it for the agent itself
+ item->setDistance(gAgent.getID(),0.0f);
+ // Request resort
+ mConversationViewModel.requestSortAll();
+ mConversationsRoot->arrangeAll();
+ }
}
}
@@ -763,7 +1123,12 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
participant_view->addToFolder(widget);
current_participant_model++;
}
+
+ setConvItemSelect(uuid);
+ // set the widget to minimized mode if conversations pane is collapsed
+ widget->toggleMinimizedMode(mConversationsPane->isCollapsed());
+
return;
}
diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h
index 1f526091bb..76e468f979 100644
--- a/indra/newview/llimfloatercontainer.h
+++ b/indra/newview/llimfloatercontainer.h
@@ -62,15 +62,15 @@ public:
/*virtual*/ void addFloater(LLFloater* floaterp,
BOOL select_added_floater,
LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
- void setConvItemSelect(LLUUID& session_id);
+ void setConvItemSelect(const LLUUID& session_id);
/*virtual*/ void tabClose();
static LLFloater* getCurrentVoiceFloater();
-
static LLIMFloaterContainer* findInstance();
-
static LLIMFloaterContainer* getInstance();
+ static void onCurrentChannelChanged(const LLUUID& session_id);
+
virtual void setMinimized(BOOL b);
void collapseMessagesPane(bool collapse);
@@ -96,11 +96,11 @@ private:
void onNewMessageReceived(const LLSD& data);
void onExpandCollapseButtonClicked();
+ void processParticipantsStyleUpdate();
void collapseConversationsPane(bool collapse);
void updateState(bool collapse, S32 delta_width);
- void repositioningWidgets();
void onAddButtonClicked();
void onAvatarPicked(const uuid_vec_t& ids);
@@ -111,6 +111,16 @@ private:
void setSortOrderParticipants(const LLConversationFilter::ESortOrderType order);
void setSortOrder(const LLConversationSort& order);
+ void getSelectedUUIDs(uuid_vec_t& selected_uuids);
+ const LLConversationItem * getCurSelectedViewModelItem();
+ void getParticipantUUIDs(uuid_vec_t& selected_uuids);
+ void doToSelected(const LLSD& userdata);
+ void doToSelectedConversation(const std::string& command, uuid_vec_t& selectedIDS);
+ void doToParticipants(const std::string& item, uuid_vec_t& selectedIDS);
+ void doToSelectedGroup(const LLSD& userdata);
+ bool checkContextMenuItem(const LLSD& userdata);
+ bool enableContextMenuItem(const LLSD& userdata);
+
LLButton* mExpandCollapseBtn;
LLLayoutPanel* mMessagesPane;
LLLayoutPanel* mConversationsPane;
@@ -124,6 +134,8 @@ private:
public:
void removeConversationListItem(const LLUUID& uuid, bool change_focus = true);
void addConversationListItem(const LLUUID& uuid);
+ void setTimeNow(const LLUUID& session_id, const LLUUID& participant_id);
+ void setNearbyDistances();
private:
LLConversationViewSession* createConversationItemWidget(LLConversationItem* item);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 72c54e5ce2..139713b96e 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1531,6 +1531,15 @@ LLUIImagePtr LLItemBridge::getIcon() const
return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT);
}
+LLUIImagePtr LLItemBridge::getIconOverlay() const
+{
+ if (getItem() && getItem()->getIsLinkType())
+ {
+ return LLUI::getUIImage("Inv_Link");
+ }
+ return NULL;
+}
+
PermissionMask LLItemBridge::getPermissionMask() const
{
LLViewerInventoryItem* item = getItem();
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 6beccf19ae..b33972167c 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -228,6 +228,7 @@ public:
virtual BOOL isItemCopyable() const;
virtual bool hasChildren() const { return FALSE; }
virtual BOOL isUpToDate() const { return TRUE; }
+ virtual LLUIImagePtr getIconOverlay() const;
LLViewerInventoryItem* getItem() const;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 2a84616ddf..a8d99ad7de 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -172,6 +172,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
p.show_empty_message = mShowEmptyMessage;
p.show_item_link_overlays = mShowItemLinkOverlays;
p.root = NULL;
+ p.options_menu = "menu_inventory.xml";
return LLUICtrlFactory::create<LLFolderView>(p);
}
@@ -441,8 +442,9 @@ void LLInventoryPanel::modelChanged(U32 mask)
handled = true;
if (model_item && view_item && viewmodel_item)
{
+ const LLUUID& idp = viewmodel_item->getUUID();
view_item->destroyView();
- removeItemID(viewmodel_item->getUUID());
+ removeItemID(idp);
}
view_item = buildNewViews(item_id);
viewmodel_item =
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 76626bd5a6..b96b486868 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -88,29 +88,36 @@ static LLChatTypeTrigger sChatTypeTriggers[] = {
LLNearbyChat::LLNearbyChat(const LLSD& llsd)
-: LLIMConversation(llsd.asUUID()),
+: LLIMConversation(llsd),
//mOutputMonitor(NULL),
mSpeakerMgr(NULL),
- mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT)
+ mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT),
+ mIsHostSet(false)
{
mIsP2PChat = false;
mIsNearbyChat = true;
setIsChrome(TRUE);
- mKey = LLSD(LLUUID());
mSpeakerMgr = LLLocalSpeakerMgr::getInstance();
mSessionID = LLUUID();
- setName("nearby_chat");
- setIsSingleInstance(TRUE);
+}
+
+//static
+LLNearbyChat* LLNearbyChat::buildFloater(const LLSD& key)
+{
+ LLFloaterReg::getInstance("im_container");
+ return new LLNearbyChat(key);
}
//virtual
BOOL LLNearbyChat::postBuild()
{
+ setIsSingleInstance(TRUE);
BOOL result = LLIMConversation::postBuild();
mInputEditor->setCommitCallback(boost::bind(&LLNearbyChat::onChatBoxCommit, this));
mInputEditor->setKeystrokeCallback(boost::bind(&onChatBoxKeystroke, _1, this));
mInputEditor->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this));
mInputEditor->setFocusReceivedCallback(boost::bind(&LLNearbyChat::onChatBoxFocusReceived, this));
+ mInputEditor->setLabel(LLTrans::getString("NearbyChatTitle"));
// mOutputMonitor = getChild<LLOutputMonitorCtrl>("chat_zone_indicator");
// mOutputMonitor->setVisible(FALSE);
@@ -122,8 +129,6 @@ BOOL LLNearbyChat::postBuild()
// it is used for show the item's name in the conversations list
setTitle(LLTrans::getString("NearbyChatTitle"));
- addToHost();
-
//for menu
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
@@ -306,9 +311,16 @@ void LLNearbyChat::addToHost()
setHost(NULL);
}
}
+
+ mIsHostSet = true;
}
}
+bool LLNearbyChat::isHostSet()
+{
+ return mIsHostSet;
+}
+
// virtual
void LLNearbyChat::onOpen(const LLSD& key)
{
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index 648098113a..93168ba96a 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -45,9 +45,11 @@ class LLNearbyChat
{
public:
// constructor for inline chat-bars (e.g. hosted in chat history window)
- LLNearbyChat(const LLSD& key = LLSD());
+ LLNearbyChat(const LLSD& key = LLSD(LLUUID()));
~LLNearbyChat() {}
+ static LLNearbyChat* buildFloater(const LLSD& key);
+
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
@@ -76,6 +78,8 @@ public:
static void startChat(const char* line);
static void stopChat();
+ bool isHostSet();
+
static void sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate);
static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate);
@@ -117,6 +121,7 @@ private:
LLHandle<LLView> mPopupMenuHandle;
std::vector<LLChat> mMessageArchive;
+ bool mIsHostSet;
};
#endif
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index f3e17ea61b..7834f6d320 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -487,6 +487,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg,
if(chat_msg.mText.empty())
return;//don't process empty messages
+ LLFloaterReg::getInstance("im_container");
LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat");
// Build notification data
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 5dcd84b400..290a81f91c 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -109,7 +109,7 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
void LLScriptHandler::onDelete( LLNotificationPtr notification )
{
- if(notification->hasFormElements())
+ if(notification->hasFormElements() && !notification->canShowToast())
{
LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
}
@@ -128,10 +128,11 @@ void LLScriptHandler::onDeleteToast(LLToast* toast)
// in this case listener is a SysWellWindow and it will remove a corresponding item from its list
LLNotificationPtr notification = LLNotifications::getInstance()->find(toast->getNotificationID());
- if( notification && notification->hasFormElements())
+ if( notification && notification->hasFormElements() && !notification->canShowToast())
{
LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
}
+
}
diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp
index 096e714981..4a9a50d96a 100644
--- a/indra/newview/lloutputmonitorctrl.cpp
+++ b/indra/newview/lloutputmonitorctrl.cpp
@@ -74,7 +74,8 @@ LLOutputMonitorCtrl::LLOutputMonitorCtrl(const LLOutputMonitorCtrl::Params& p)
mSpeakerId(p.speaker_id),
mIsAgentControl(false),
mIsSwitchDirty(false),
- mShouldSwitchOn(false)
+ mShouldSwitchOn(false),
+ mShowParticipantsSpeaking(false)
{
//static LLUIColor output_monitor_muted_color = LLUIColorTable::instance().getColor("OutputMonitorMutedColor", LLColor4::orange);
//static LLUIColor output_monitor_overdriven_color = LLUIColorTable::instance().getColor("OutputMonitorOverdrivenColor", LLColor4::red);
@@ -157,6 +158,24 @@ void LLOutputMonitorCtrl::draw()
}
}
+ if ((mPower == 0.f && !mIsTalking) && mShowParticipantsSpeaking)
+ {
+ std::set<LLUUID> participant_uuids;
+ LLVoiceClient::instance().getParticipantList(participant_uuids);
+ std::set<LLUUID>::const_iterator part_it = participant_uuids.begin();
+
+ F32 power = 0;
+ for (; part_it != participant_uuids.end(); ++part_it)
+ {
+ power = LLVoiceClient::instance().getCurrentPower(*part_it);
+ if (power)
+ {
+ mPower = power;
+ break;
+ }
+ }
+ }
+
LLPointer<LLUIImage> icon;
if (mIsMuted)
{
@@ -245,15 +264,19 @@ void LLOutputMonitorCtrl::draw()
// virtual
BOOL LLOutputMonitorCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
{
- if (mSpeakerId != gAgentID)
+ if (mSpeakerId != gAgentID && !mShowParticipantsSpeaking)
{
LLFloaterReg::showInstance("floater_voice_volume", LLSD().with("avatar_id", mSpeakerId));
}
+ else if(mShowParticipantsSpeaking)
+ {
+ LLFloaterReg::showInstance("chat_voice", LLSD());
+ }
return TRUE;
}
-void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id/* = LLUUID::null*/)
+void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id/* = LLUUID::null*/, bool show_other_participants_speaking /* = false */)
{
if (speaker_id.isNull() && mSpeakerId.notNull())
{
@@ -268,6 +291,7 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& s
LLSpeakingIndicatorManager::unregisterSpeakingIndicator(mSpeakerId, this);
}
+ mShowParticipantsSpeaking = show_other_participants_speaking;
mSpeakerId = speaker_id;
LLSpeakingIndicatorManager::registerSpeakingIndicator(mSpeakerId, this, session_id);
diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h
index 7b02e84744..1fa6ef41f8 100644
--- a/indra/newview/lloutputmonitorctrl.h
+++ b/indra/newview/lloutputmonitorctrl.h
@@ -82,6 +82,8 @@ public:
void setIsTalking(bool val) { mIsTalking = val; }
+ void setShowParticipantsSpeaking(bool show) { mShowParticipantsSpeaking = show; }
+
/**
* Sets avatar UUID to interact with voice channel.
*
@@ -90,7 +92,7 @@ public:
* If this parameter is set registered indicator will be shown only in voice channel
* which has the same session id (EXT-5562).
*/
- void setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id = LLUUID::null);
+ void setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id = LLUUID::null, bool show_other_participants_speaking = false);
//called by mute list
virtual void onChange();
@@ -132,6 +134,7 @@ private:
bool mIsAgentControl;
bool mIsMuted;
bool mIsTalking;
+ bool mShowParticipantsSpeaking;
LLPointer<LLUIImage> mImageMute;
LLPointer<LLUIImage> mImageOff;
LLPointer<LLUIImage> mImageOn;
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index c9eebe24d3..899771f3b9 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -69,6 +69,7 @@ LLContextMenu* NearbyMenu::createMenu()
registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id));
registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id));
registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id));
+ registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id));
enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2));
enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2));
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 339cee3f95..90226e7fba 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -34,6 +34,7 @@
#include "llagent.h"
#include "llimview.h"
+#include "llimfloatercontainer.h"
#include "llpanelpeoplemenus.h"
#include "llnotificationsutil.h"
#include "llparticipantlist.h"
@@ -224,12 +225,14 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source,
mSpeakerRemoveListener = new SpeakerRemoveListener(*this);
mSpeakerClearListener = new SpeakerClearListener(*this);
mSpeakerModeratorListener = new SpeakerModeratorUpdateListener(*this);
+ mSpeakerUpdateListener = new SpeakerUpdateListener(*this);
mSpeakerMuteListener = new SpeakerMuteListener(*this);
mSpeakerMgr->addListener(mSpeakerAddListener, "add");
mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");
mSpeakerMgr->addListener(mSpeakerClearListener, "clear");
mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator");
+ mSpeakerMgr->addListener(mSpeakerUpdateListener, "update_speaker");
setSessionID(mSpeakerMgr->getSessionID());
@@ -584,6 +587,21 @@ bool LLParticipantList::onClearListEvent(LLPointer<LLOldEvents::LLEvent> event,
return true;
}
+bool LLParticipantList::onSpeakerUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
+{
+ const LLSD& evt_data = event->getValue();
+ if ( evt_data.has("id") )
+ {
+ LLUUID participant_id = evt_data["id"];
+ LLIMFloaterContainer* im_box = LLIMFloaterContainer::findInstance();
+ if (im_box)
+ {
+ im_box->setTimeNow(mUUID,participant_id);
+ }
+ }
+ return true;
+}
+
bool LLParticipantList::onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
{
const LLSD& evt_data = event->getValue();
@@ -660,8 +678,10 @@ void LLParticipantList::sort()
void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
{
+ // Do not add if already in there or excluded for some reason
if (mExcludeAgent && gAgent.getID() == avatar_id) return;
if (mAvatarList && mAvatarList->contains(avatar_id)) return;
+ if (findParticipant(avatar_id)) return;
bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(avatar_id);
@@ -746,6 +766,14 @@ bool LLParticipantList::SpeakerClearListener::handleEvent(LLPointer<LLOldEvents:
}
//
+// LLParticipantList::SpeakerUpdateListener
+//
+bool LLParticipantList::SpeakerUpdateListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
+{
+ return mParent.onSpeakerUpdateEvent(event, userdata);
+}
+
+//
// LLParticipantList::SpeakerModeratorListener
//
bool LLParticipantList::SpeakerModeratorUpdateListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index f8165aa292..acee68873c 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -95,6 +95,7 @@ protected:
bool onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
bool onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
bool onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ bool onSpeakerUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
bool onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
/**
@@ -136,6 +137,13 @@ protected:
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
};
+ class SpeakerUpdateListener : public BaseSpeakerListener
+ {
+ public:
+ SpeakerUpdateListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
+ /*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
+ };
+
class SpeakerModeratorUpdateListener : public BaseSpeakerListener
{
public:
@@ -264,6 +272,7 @@ private:
LLPointer<SpeakerAddListener> mSpeakerAddListener;
LLPointer<SpeakerRemoveListener> mSpeakerRemoveListener;
LLPointer<SpeakerClearListener> mSpeakerClearListener;
+ LLPointer<SpeakerUpdateListener> mSpeakerUpdateListener;
LLPointer<SpeakerModeratorUpdateListener> mSpeakerModeratorListener;
LLPointer<SpeakerMuteListener> mSpeakerMuteListener;
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 07d2f1ad6f..2d2b5202e0 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -84,6 +84,19 @@ bool LLSpeaker::isInVoiceChannel()
return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED;
}
+LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source)
+: LLEvent(source, "Speaker update speaker event"),
+ mSpeakerID (source->mID)
+{
+}
+
+LLSD LLSpeakerUpdateSpeakerEvent::getValue()
+{
+ LLSD ret;
+ ret["id"] = mSpeakerID;
+ return ret;
+}
+
LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source)
: LLEvent(source, "Speaker add moderator event"),
mSpeakerID (source->mID),
@@ -374,6 +387,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)
{
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
speakerp->mHasSpoken = TRUE;
+ fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker");
}
speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
// interpolate between active color and full speaking color based on power of speech output
@@ -548,6 +562,7 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
{
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
speakerp->mHasSpoken = TRUE;
+ fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker");
}
}
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 1c6f51e131..8ab08661d3 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -79,6 +79,15 @@ public:
BOOL mModeratorMutedText;
};
+class LLSpeakerUpdateSpeakerEvent : public LLOldEvents::LLEvent
+{
+public:
+ LLSpeakerUpdateSpeakerEvent(LLSpeaker* source);
+ /*virtual*/ LLSD getValue();
+private:
+ const LLUUID& mSpeakerID;
+};
+
class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent
{
public:
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 927ee8f380..c751550523 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -50,6 +50,7 @@
#include "llfloaterbump.h"
#include "llfloaterbvhpreview.h"
#include "llfloatercamera.h"
+#include "llfloaterchatvoicevolume.h"
#include "llfloaterconversationlog.h"
#include "llfloaterconversationpreview.h"
#include "llfloaterdeleteenvpreset.h"
@@ -192,7 +193,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>);
LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);
- LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>);
+ LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);
+ LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLNearbyChat::buildFloater);
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index a993d195b5..6da9296ea3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -3466,7 +3466,8 @@ class LLTogglePanelPeopleTab : public view_listener_t
if ( panel_name == "friends_panel"
|| panel_name == "groups_panel"
- || panel_name == "nearby_panel")
+ || panel_name == "nearby_panel"
+ || panel_name == "blocked_panel")
{
return togglePeoplePanel(panel_name, param);
}
@@ -5490,16 +5491,6 @@ void toggle_debug_menus(void*)
// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");
// }
//
-
-class LLCommunicateBlockList : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD());
- return true;
- }
-};
-
class LLWorldSetHomeLocation : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -8290,9 +8281,6 @@ void initialize_menus()
// Me > Movement
view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
- // Communicate
- view_listener_t::addMenu(new LLCommunicateBlockList(), "Communicate.BlockList");
-
// World menu
view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
diff --git a/indra/newview/skins/default/textures/icons/nearby_chat_icon.png b/indra/newview/skins/default/textures/icons/nearby_chat_icon.png
new file mode 100644
index 0000000000..7c3ad40381
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/nearby_chat_icon.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 47b0c12fa0..a124041565 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -363,6 +363,8 @@ with the same filename but different name
<texture name="NavBar_BG_NoFav_Bevel" file_name="navbar/NavBar_BG_NoFav_Bevel.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" />
<texture name="NavBar_BG_NoNav_Bevel" file_name="navbar/NavBar_BG_NoNav_Bevel.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0" />
+ <texture name="Nearby_chat_icon" file_name="icons/nearby_chat_icon.png" preload="false" />
+
<texture name="Notices_Unread" file_name="bottomtray/Notices_Unread.png" preload="true" />
<texture name="NoEntryLines" file_name="world/NoEntryLines.png" use_mips="true" preload="false" />
diff --git a/indra/newview/skins/default/xui/en/floater_conversation_log.xml b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
index 12d17e6b37..c9c52e5ce5 100644
--- a/indra/newview/skins/default/xui/en/floater_conversation_log.xml
+++ b/indra/newview/skins/default/xui/en/floater_conversation_log.xml
@@ -49,6 +49,7 @@
menu_filename="menu_conversation_log_view.xml"
menu_position="bottomleft"
name="conversation_view_btn"
+ tool_tip="View/sort options"
top="3"
width="31" />
<menu_button
@@ -61,6 +62,7 @@
layout="topleft"
left_pad="2"
name="conversations_gear_btn"
+ tool_tip="Actions on selected person or group"
top="3"
width="31" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml
index 413e66738d..590ce45c33 100644
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -11,6 +11,7 @@
save_rect="true"
save_visibility="true"
single_instance="true"
+ reuse_instance="true"
title="CONVERSATIONS"
width="680">
<string
@@ -62,6 +63,7 @@
layout="topleft"
left="10"
name="sort_btn"
+ tool_tip="View/sort options"
top="5"
width="31" />
<button
@@ -75,7 +77,7 @@
top="5"
left_pad="4"
name="add_btn"
- tool_tip="Add button on the left panel"
+ tool_tip="Start a new conversation"
width="31"/>
</layout_panel>
<layout_panel
@@ -94,6 +96,7 @@
top="5"
left="5"
name="expand_collapse_btn"
+ tool_tip="Collapse/Expand this list"
width="31" />
</layout_panel>
</layout_stack>
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index d6d48130ab..5c74f7f9bb 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -37,6 +37,12 @@
<floater.string
name="multiple_participants_added"
value="[NAME] were invited to the conversation."/>
+ <floater.string
+ name="tooltip_to_separate_window"
+ value="Move this conversation to a separate window"/>
+ <floater.string
+ name="tooltip_to_main_window"
+ value="Move this conversation back to main window"/>
<view
follows="all"
layout="topleft"
@@ -64,6 +70,7 @@
layout="topleft"
left="5"
name="view_options_btn"
+ tool_tip="View/sort options"
top="5"
width="31" />
<button
@@ -78,6 +85,7 @@
top="5"
left_pad="4"
name="add_btn"
+ tool_tip="Add someone to this conversation"
width="31"/>
<button
follows="top|left"
@@ -90,6 +98,7 @@
top="5"
left_pad="4"
name="voice_call_btn"
+ tool_tip="Open voice connection"
width="31"/>
<button
follows="right|top"
@@ -102,6 +111,7 @@
top="5"
left="283"
name="close_btn"
+ tool_tip="End this conversation"
width="31" />
<button
follows="right|top"
@@ -114,6 +124,7 @@
top="5"
left_pad="5"
name="expand_collapse_btn"
+ tool_tip="Collapse/Expand this pane"
width="31" />
<button
follows="right|top"
diff --git a/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
new file mode 100644
index 0000000000..5c71fd3bc6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+<floater
+ legacy_header_height="25"
+ bevel_style="in"
+ bg_opaque_image="Inspector_Background"
+ can_close="false"
+ can_minimize="false"
+ height="90"
+ layout="topleft"
+ name="floater_voice_volume"
+ single_instance="true"
+ sound_flags="0"
+ title="VOICE CHAT VOLUME"
+ visible="true"
+ width="245">
+ <slider
+ control_name="AudioLevelVoice"
+ disabled_control="MuteAudio"
+ follows="left|top"
+ height="16"
+ increment="0.025"
+ initial_value="0.5"
+ label="Voice Chat"
+ label_width="50"
+ layout="topleft"
+ left="15"
+ top="50"
+ name="chat_voice_volume"
+ show_text="false"
+ slider_label.halign="right"
+ volume="true"
+ width="200">
+ </slider>
+ <button
+ control_name="MuteVoice"
+ disabled_control="MuteAudio"
+ follows="top|left"
+ height="16"
+ image_selected="AudioMute_Off"
+ image_unselected="Audio_Off"
+ is_toggle="true"
+ layout="topleft"
+ left_pad="5"
+ name="mute_audio"
+ tab_stop="false"
+ width="16" />
+</floater> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
new file mode 100644
index 0000000000..912ff811d9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="menu_conversation_participant"
+ visible="false">
+ <menu_item_call
+ label="Close conversation"
+ layout="topleft"
+ name="close_conversation">
+ <on_click function="Avatar.DoToSelected" parameter="close_conversation"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Open voice conversation"
+ layout="topleft"
+ name="open_voice_conversation">
+ <on_click function="Avatar.DoToSelected" parameter="open_voice_conversation"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Disconnect from voice"
+ layout="topleft"
+ name="disconnect_from_voice">
+ <on_click function="Avatar.DoToSelected" parameter="disconnect_from_voice"/>
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_disconnect_from_voice"/>
+ <menu_item_call
+ label="View Profile"
+ layout="topleft"
+ name="view_profile">
+ <on_click function="Avatar.DoToSelected" parameter="view_profile"/>
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ layout="topleft"
+ name="im">
+ <on_click function="Avatar.DoToSelected" parameter="im"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Offer teleport"
+ layout="topleft"
+ name="offer_teleport">
+ <on_click function="Avatar.DoToSelected" parameter="offer_teleport"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_offer_teleport"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Voice call"
+ layout="topleft"
+ name="voice_call">
+ <on_click function="Avatar.DoToSelected" parameter="voice_call"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_call" />
+ </menu_item_call>
+ <menu_item_call
+ label="Chat history..."
+ layout="topleft"
+ name="chat_history">
+ <on_click function="Avatar.DoToSelected" parameter="chat_history"/>
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_chat_history"/>
+ <menu_item_call
+ label="Add friend"
+ layout="topleft"
+ name="add_friend">
+ <on_click function="Avatar.DoToSelected" parameter="add_friend"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove friend"
+ layout="topleft"
+ name="remove_friend">
+ <on_click function="Avatar.DoToSelected" parameter="remove_friend" />
+ <on_enable function="Avatar.EnableItem" parameter="can_delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Invite to group..."
+ layout="topleft"
+ name="invite_to_group">
+ <on_click function="Avatar.DoToSelected" parameter="invite_to_group" />
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_invite_to_group"/>
+ <menu_item_call
+ label="Map"
+ layout="topleft"
+ name="map">
+ <on_click function="Avatar.DoToSelected" parameter="map" />
+ <on_enable function="Avatar.EnableItem" parameter="can_show_on_map" />
+ </menu_item_call>
+ <menu_item_call
+ label="Share"
+ layout="topleft"
+ name="share">
+ <on_click function="Avatar.DoToSelected" parameter="share" />
+ </menu_item_call>
+ <menu_item_call
+ label="Pay"
+ layout="topleft"
+ name="pay">
+ <on_click function="Avatar.DoToSelected" parameter="pay" />
+ </menu_item_call>
+ <menu_item_check
+ label="Block / unblock"
+ layout="topleft"
+ name="block_unblock">
+ <on_click function="Avatar.DoToSelected" parameter="block_unblock" />
+ <on_check function="Avatar.CheckItem" parameter="is_blocked" />
+ <on_enable function="Avatar.EnableItem" parameter="can_block" />
+ </menu_item_check>
+ <menu_item_call
+ label="Group Profile"
+ layout="topleft"
+ name="group_profile">
+ <on_click function="Group.DoToSelected" parameter="group_profile"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Activate Group"
+ layout="topleft"
+ name="activate_group">
+ <on_click function="Group.DoToSelected" parameter="activate_group"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Leave Group"
+ layout="topleft"
+ name="leave_group">
+ <on_click function="Group.DoToSelected" parameter="leave_group"/>
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
index eab7b8c085..dde9432867 100644
--- a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
@@ -40,4 +40,12 @@
function="CheckControl"
parameter="FriendsListShowPermissions" />
</menu_item_check>
+ <menu_item_check name="view_conversation" label="View Conversation Log...">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="conversation" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="conversation" />
+ </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby.xml b/indra/newview/skins/default/xui/en/menu_people_nearby.xml
index b7c9ab1fe3..8014e81469 100644
--- a/indra/newview/skins/default/xui/en/menu_people_nearby.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby.xml
@@ -37,6 +37,14 @@
</menu_item_call>
<menu_item_separator />
<menu_item_call
+ label="View chat history..."
+ layout="topleft"
+ name="Chat history">
+ <menu_item_call.on_click
+ function="Avatar.Calllog" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
label="Add Friend"
layout="topleft"
name="Add Friend">
@@ -101,5 +109,5 @@
function="Avatar.EnableItem"
parameter="can_block" />
</menu_item_check>
-
+ <menu_item_separator />
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index aa131035ed..88b30c8272 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -244,16 +244,6 @@
parameter="speak" />
</menu_item_check>
<menu_item_check
- label="Voice settings..."
- name="Nearby Voice">
- <menu_item_check.on_check
- function="Floater.Visible"
- parameter="voice_controls" />
- <menu_item_check.on_click
- function="Floater.Toggle"
- parameter="voice_controls" />
- </menu_item_check>
- <menu_item_check
label="Voice morphing..."
name="ShowVoice"
visibility_control="VoiceMorphingEnabled">
@@ -304,7 +294,8 @@
label="Block List"
name="Block List">
<menu_item_call.on_click
- function="Communicate.BlockList" />
+ function="SideTray.PanelPeopleTab"
+ parameter="blocked_panel" />
</menu_item_call>
</menu>
<menu
diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
index 24f7d44cce..53d0252215 100644
--- a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
@@ -43,6 +43,7 @@
menu_filename="menu_people_blocked_gear.xml"
menu_position="bottomleft"
name="blocked_gear_btn"
+ tool_tip="Actions on selected person or object"
top="3"
width="31" />
<menu_button
@@ -57,6 +58,7 @@
menu_filename="menu_people_blocked_view.xml"
menu_position="bottomleft"
name="view_btn"
+ tool_tip="Sort options"
top_delta="0"
width="31" />
<menu_button
@@ -71,6 +73,7 @@
menu_filename="menu_people_blocked_plus.xml"
menu_position="bottomleft"
name="plus_btn"
+ tool_tip="Pick a Resident or an object to block"
top_delta="0"
width="31"/>
<button
@@ -83,6 +86,7 @@
left_pad="2"
layout="topleft"
name="unblock_btn"
+ tool_tip="Remove Resident or object from blocked list"
top_delta="0"
width="31"/>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
index 375ea79ebe..56056ed560 100644
--- a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
@@ -13,13 +13,33 @@
layout="topleft"
left="5"
top="2"
+ visible="false"
width="20" />
+ <group_icon
+ follows="top|left"
+ height="20"
+ default_icon_name="Generic_Group"
+ layout="topleft"
+ left="5"
+ top="2"
+ visible="false"
+ width="20" />
+ <icon
+ follows="top|left"
+ height="20"
+ image_name="Nearby_chat_icon"
+ layout="topleft"
+ left="5"
+ name="nearby_chat_icon"
+ top="2"
+ visible="false"
+ width="20"/>
<layout_stack
animate="false"
follows="all"
height="24"
layout="topleft"
- left_pad="5"
+ left="30"
mouse_opaque="false"
name="conversation_item_stack"
orientation="horizontal"
@@ -36,7 +56,7 @@
<icon
height="20"
follows="top|right|left"
- image_name="Conv_toolbar_hang_up"
+ image_name="Conv_toolbar_open_call"
layout="topleft"
left="0"
name="selected_icon"
@@ -70,7 +90,7 @@
layout="topleft"
left_pad="5"
mouse_opaque="true"
- name="speaking_indicator"
+ name="speaking_indicatorn"
visible="false"
width="20" />
</layout_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml b/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml
index 8a58eb1ca6..78d4c174d2 100644
--- a/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml
@@ -35,6 +35,7 @@
image_name="Conv_toolbar_open_call"
mouse_opaque="true"
name="voice_session_icon"
+ tool_tip="Included a voice conversation"
top="2"
visible="false"
width="20" />
@@ -46,6 +47,7 @@
image_name="Conv_log_inbox"
mouse_opaque="false"
name="unread_ims_icon"
+ tool_tip="Messages arrived while you were logged out"
top="2"
visible="false"
width="20" />
@@ -92,6 +94,7 @@
width="110"/>
<button
name="delete_btn"
+ tool_tip="Remove this entry"
layout="topleft"
follows="top|right"
image_unselected="Conv_toolbar_close"
diff --git a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml
index 203febbf18..c80e5b168a 100644
--- a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml
@@ -20,6 +20,13 @@
folder_indentation="8"
item_height="20"
item_top_pad="4"
- selection_image="Rounded_Square"/>
+ selection_image="Rounded_Square"
+ left_pad="5"
+ icon_pad="2"
+ icon_width="16"
+ text_pad="1"
+ text_pad_right="4"
+ arrow_size="12"
+ max_folder_item_overlap="2"/>
<item allow_open="false"/>
</inventory_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 09156b41b5..7433ad828d 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -116,6 +116,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="7"
name="gear_btn"
+ tool_tip="Actions on selected person"
top="3"
width="31" />
<menu_button
@@ -130,6 +131,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
menu_filename="menu_people_nearby_view.xml"
menu_position="bottomleft"
name="nearby_view_btn"
+ tool_tip="View/sort options"
top_delta="0"
width="31" />
<button
@@ -142,6 +144,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="2"
name="add_friend_btn"
+ tool_tip="Offer friendship to a resident"
top_delta="0"
width="31">
<commit_callback
@@ -158,6 +161,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left_pad="2"
layout="topleft"
name="nearby_del_btn"
+ tool_tip="Remove selected person as a friend"
top_delta="0"
width="31">
<commit_callback
@@ -264,6 +268,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="8"
name="gear_btn"
+ tool_tip="Actions on selected person"
top="3"
width="31" />
<menu_button
@@ -278,6 +283,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
menu_filename="menu_people_friends_view.xml"
menu_position="bottomleft"
name="friends_view_btn"
+ tool_tip="View/sort options"
top_delta="0"
width="31" />
<button
@@ -290,6 +296,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="2"
name="friends_add_btn"
+ tool_tip="Offer friendship to a resident"
top_delta="0"
width="31">
<commit_callback
@@ -305,6 +312,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left_pad="2"
layout="topleft"
name="friends_del_btn"
+ tool_tip="Remove selected person as a friend"
top_delta="0"
width="31">
<commit_callback
@@ -419,6 +427,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="8"
name="groups_gear_btn"
+ tool_tip="Actions on selected group"
top="3"
width="31" />
<menu_button
@@ -433,6 +442,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
menu_filename="menu_people_groups_view.xml"
menu_position="bottomleft"
name="groups_view_btn"
+ tool_tip="View/sort options"
top_delta="0"
width="31" />
<menu_button
@@ -447,6 +457,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
menu_filename="menu_group_plus.xml"
menu_position="bottomleft"
name="plus_btn"
+ tool_tip="Join group/Create new group"
top_delta="0"
width="31">
<validate_callback
@@ -462,6 +473,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left_pad="2"
layout="topleft"
name="minus_btn"
+ tool_tip="Leave selected group"
top_delta="0"
width="31">
<commit_callback
@@ -527,6 +539,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="8"
name="gear_btn"
+ tool_tip="Actions on selected person"
top="3"
width="31" />
<menu_button
@@ -541,6 +554,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
menu_filename="menu_people_recent_view.xml"
menu_position="bottomleft"
name="recent_view_btn"
+ tool_tip="View/sort options"
top_delta="0"
width="31" />
<button
@@ -553,6 +567,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
layout="topleft"
left_pad="2"
name="add_friend_btn"
+ tool_tip="Offer friendship to a resident"
top_delta="0"
width="31">
<commit_callback
@@ -569,6 +584,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left_pad="2"
layout="topleft"
name="recent_del_btn"
+ tool_tip="Remove selected person as a friend"
top_delta="0"
width="31">
<commit_callback
diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
index 7ddcfe3b03..0024decd4c 100755
--- a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
+++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
@@ -1,18 +1,27 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<conversation_view_participant
- folder_arrow_image="ForSale_Badge"
+ folder_arrow_image="Folder_Arrow"
folder_indentation="0"
item_height="24"
- item_top_pad="4"
+ item_top_pad="0"
selection_image="Rounded_Square"
mouse_opaque="true"
follows="left|top|right"
+ left_pad="0"
+ icon_pad="10"
+ icon_width="20"
+ text_pad="7"
+ text_pad_right="4"
+ arrow_size="12"
+ max_folder_item_overlap="2"
>
<avatar_icon
follows="left"
height="20"
default_icon_name="Generic_Person"
+ layout="topleft"
left="50"
+ top="2"
width="20" />
<info_button
follows="right"
diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_session.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_session.xml
index f44731ea3d..b8c39eec1d 100644
--- a/indra/newview/skins/default/xui/en/widgets/conversation_view_session.xml
+++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_session.xml
@@ -6,4 +6,11 @@
item_top_pad="4"
selection_image="Rounded_Square"
mouse_opaque="true"
- follows="left|top|right"/>
+ follows="left|top|right"
+ left_pad="5"
+ icon_pad="2"
+ icon_width="16"
+ text_pad="1"
+ text_pad_right="4"
+ arrow_size="12"
+ max_folder_item_overlap="2"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
index 6fa74f403d..bbd53ccb12 100644
--- a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
@@ -7,4 +7,10 @@
selection_image="Rounded_Square"
mouse_opaque="true"
follows="left|top|right"
- />
+ left_pad="5"
+ icon_pad="2"
+ icon_width="16"
+ text_pad="1"
+ text_pad_right="4"
+ arrow_size="12"
+ max_folder_item_overlap="2"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
index 77d8024cb2..590a4730a9 100644
--- a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
@@ -5,7 +5,13 @@
item_height="20"
item_top_pad="4"
selection_image="Rounded_Square"
- >
+ left_pad="5"
+ icon_pad="2"
+ icon_width="16"
+ text_pad="1"
+ text_pad_right="4"
+ arrow_size="12"
+ max_folder_item_overlap="2">
<new_badge
label="New"
label_offset_horiz="-1"