diff options
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.pngBinary files differ new file mode 100644 index 0000000000..7c3ad40381 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/nearby_chat_icon.png 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" | 
