diff options
Diffstat (limited to 'indra')
73 files changed, 2316 insertions, 603 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 772f173f17..b50ed2342d 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -34,6 +34,7 @@ set(llui_SOURCE_FILES llbadgeholder.cpp llbadgeowner.cpp llbutton.cpp + llchatentry.cpp llcheckboxctrl.cpp llclipboard.cpp llcombobox.cpp @@ -133,6 +134,7 @@ set(llui_HEADER_FILES llbadgeowner.h llbutton.h llcallbackmap.h + llchatentry.h llcheckboxctrl.h llclipboard.h llcombobox.h diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index c025cd7939..43462bd244 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -184,7 +184,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string if (mHeaderTextbox) { std::string text = mHeaderTextbox->getText(); - mStyleParams.font(mHeaderTextbox->getDefaultFont()); + mStyleParams.font(mHeaderTextbox->getFont()); mStyleParams.font.style(style); mHeaderTextbox->setText(text, mStyleParams); } diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp new file mode 100644 index 0000000000..2a6ccc3dc9 --- /dev/null +++ b/indra/llui/llchatentry.cpp @@ -0,0 +1,199 @@ +/** + * @file llchatentry.cpp + * @brief LLChatEntry implementation + * + * $LicenseInfo:firstyear=2001&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 "linden_common.h" + +#include "llchatentry.h" + +static LLDefaultChildRegistry::Register<LLChatEntry> r("chat_editor"); + +LLChatEntry::Params::Params() +: has_history("has_history", true), + is_expandable("is_expandable", false), + expand_lines_count("expand_lines_count", 1) +{} + +LLChatEntry::LLChatEntry(const Params& p) +: LLTextEditor(p), + mTextExpandedSignal(NULL), + mHasHistory(p.has_history), + mIsExpandable(p.is_expandable), + mExpandLinesCount(p.expand_lines_count), + mPrevLinesCount(0) +{ + // Initialize current history line iterator + mCurrentHistoryLine = mLineHistory.begin(); + + mAutoIndent = false; +} + +LLChatEntry::~LLChatEntry() +{ + delete mTextExpandedSignal; +} + +void LLChatEntry::draw() +{ + if(mIsExpandable) + { + expandText(); + } + + LLTextEditor::draw(); +} + +void LLChatEntry::onCommit() +{ + updateHistory(); + LLTextEditor::onCommit(); +} + +boost::signals2::connection LLChatEntry::setTextExpandedCallback(const commit_signal_t::slot_type& cb) +{ + if (!mTextExpandedSignal) + { + mTextExpandedSignal = new commit_signal_t(); + } + return mTextExpandedSignal->connect(cb); +} + +void LLChatEntry::expandText() +{ + int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second); + bool can_expand = getLineCount() <= mExpandLinesCount; + + // true if pasted text has more lines than expand height limit and expand limit is not reached yet + bool text_pasted = (getLineCount() > mExpandLinesCount) && (visible_lines_count < mExpandLinesCount); + + if (mIsExpandable && (can_expand || text_pasted) && getLineCount() != mPrevLinesCount) + { + int lines_height = 0; + if (text_pasted) + { + // text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty, + // so lines_height is the sum of the last 'mExpandLinesCount' lines height + lines_height = (mLineInfoList.end() - mExpandLinesCount)->mRect.mTop - mLineInfoList.back().mRect.mBottom; + } + else + { + lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom; + } + + int height = mVPad * 2 + lines_height; + + LLRect doc_rect = getRect(); + doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height); + setShape(doc_rect); + + mPrevLinesCount = getLineCount(); + + if (mTextExpandedSignal) + { + (*mTextExpandedSignal)(this, LLSD() ); + } + } +} + +// line history support +void LLChatEntry::updateHistory() +{ + // On history enabled, remember committed line and + // reset current history line number. + // Be sure only to remember lines that are not empty and that are + // different from the last on the list. + if (mHasHistory && getLength()) + { + // Add text to history, ignoring duplicates + if (mLineHistory.empty() || getText() != mLineHistory.back()) + { + mLineHistory.push_back(getText()); + } + + mCurrentHistoryLine = mLineHistory.end(); + } +} + +BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) +{ + BOOL handled = FALSE; + + LLTextEditor::handleSpecialKey(key, mask); + + switch(key) + { + case KEY_RETURN: + if (MASK_NONE == mask) + { + needsReflow(); + } + break; + + case KEY_UP: + if (mHasHistory && MASK_CONTROL == mask) + { + if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin()) + { + setText(*(--mCurrentHistoryLine)); + endOfDoc(); + } + else + { + LLUI::reportBadKeystroke(); + } + handled = TRUE; + } + break; + + case KEY_DOWN: + if (mHasHistory && MASK_CONTROL == mask) + { + if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) ) + { + setText(*(++mCurrentHistoryLine)); + endOfDoc(); + } + else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) ) + { + mCurrentHistoryLine++; + std::string empty(""); + setText(empty); + needsReflow(); + endOfDoc(); + } + else + { + LLUI::reportBadKeystroke(); + } + handled = TRUE; + } + break; + + default: + break; + } + + return handled; +} diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h new file mode 100644 index 0000000000..10a4594e83 --- /dev/null +++ b/indra/llui/llchatentry.h @@ -0,0 +1,98 @@ +/** + * @file llchatentry.h + * @author Paul Guslisty + * @brief Text editor widget which is used for user input + * + * Features: + * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * Optional auto-resize behavior on input chat field + * + * $LicenseInfo:firstyear=2001&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 LLCHATENTRY_H_ +#define LLCHATENTRY_H_ + +#include "lltexteditor.h" + +class LLChatEntry : public LLTextEditor +{ +public: + + struct Params : public LLInitParam::Block<Params, LLTextEditor::Params> + { + Optional<bool> has_history, + is_expandable; + + Optional<int> expand_lines_count; + + Params(); + }; + + virtual ~LLChatEntry(); + +protected: + + friend class LLUICtrlFactory; + LLChatEntry(const Params& p); + +public: + + virtual void draw(); + virtual void onCommit(); + + boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb); + +private: + + /** + * Implements auto-resize behavior. + * When user's typing reaches the right edge of the chat field + * the chat field expands vertically by one line. The bottom of + * the chat field remains bottom-justified. The chat field does + * not expand beyond mExpandLinesCount. + */ + void expandText(); + + /** + * Implements line history so previous entries can be recalled by CTRL UP/DOWN + */ + void updateHistory(); + + BOOL handleSpecialKey(const KEY key, const MASK mask); + + + // Fired when text height expanded to mExpandLinesCount + commit_signal_t* mTextExpandedSignal; + + // line history support: + typedef std::vector<std::string> line_history_t; + line_history_t::iterator mCurrentHistoryLine; // currently browsed history line + line_history_t mLineHistory; // line history storage + bool mHasHistory; // flag for enabled/disabled line history + bool mIsExpandable; + + int mExpandLinesCount; + int mPrevLinesCount; +}; + +#endif /* LLCHATENTRY_H_ */ diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 540ac74aee..6f0e691f10 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -173,7 +173,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, else if (floaterp->getHost()) { // floaterp is hosted by somebody else and - // this is adding it, so remove it from it's old host + // this is adding it, so remove it from its old host floaterp->getHost()->removeFloater(floaterp); } else if (floaterp->getParent() == gFloaterView) diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index f299ae5dd3..44514a6246 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -45,8 +45,8 @@ public: virtual BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void draw(); - /*virtual*/ void setVisible(BOOL visible); + virtual void draw(); + virtual void setVisible(BOOL visible); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 7aeeae298f..3b3bc64c5b 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -144,6 +144,7 @@ LLTextBase::Params::Params() : cursor_color("cursor_color"), text_color("text_color"), text_readonly_color("text_readonly_color"), + text_tentative_color("text_tentative_color"), bg_visible("bg_visible", false), border_visible("border_visible", false), bg_readonly_color("bg_readonly_color"), @@ -177,7 +178,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) : LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)), mURLClickSignal(NULL), mMaxTextByteLength( p.max_text_length ), - mDefaultFont(p.font), + mFont(p.font), mFontShadow(p.font_shadow), mPopupMenu(NULL), mReadOnly(p.read_only), @@ -185,6 +186,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mFgColor(p.text_color), mBorderVisible( p.border_visible ), mReadOnlyFgColor(p.text_readonly_color), + mTentativeFgColor(p.text_tentative_color()), mWriteableBgColor(p.bg_writeable_color), mReadOnlyBgColor(p.bg_readonly_color), mFocusBgColor(p.bg_focus_color), @@ -297,21 +299,21 @@ bool LLTextBase::truncate() return did_truncate; } -const LLStyle::Params& LLTextBase::getDefaultStyleParams() +const LLStyle::Params& LLTextBase::getStyleParams() { //FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html //and eliminate color member values if (mStyleDirty) { - mDefaultStyle + mStyle .color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor .readonly_color(LLUIColor(&mReadOnlyFgColor)) .selected_color(LLUIColor(&mTextSelectedColor)) - .font(mDefaultFont) + .font(mFont) .drop_shadow(mFontShadow); mStyleDirty = false; } - return mDefaultStyle; + return mStyle; } void LLTextBase::onValueChange(S32 start, S32 end) @@ -500,11 +502,17 @@ void LLTextBase::drawCursor() void LLTextBase::drawText() { - const S32 text_len = getLength(); - if( text_len <= 0 ) + S32 text_len = getLength(); + + if (text_len <= 0 && mLabel.empty()) { return; } + else if (text_len <= 0 && !mLabel.empty() && !hasFocus()) + { + text_len = mLabel.length(); + } + S32 selection_left = -1; S32 selection_right = -1; // Draw selection even if we don't have keyboard focus for search/replace @@ -624,7 +632,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s else { // create default editable segment to hold new text - LLStyleConstSP sp(new LLStyle(getDefaultStyleParams())); + LLStyleConstSP sp(new LLStyle(getStyleParams())); default_segment = new LLNormalTextSegment( sp, pos, pos + insert_len, *this); } @@ -749,7 +757,7 @@ void LLTextBase::createDefaultSegment() // ensures that there is always at least one segment if (mSegments.empty()) { - LLStyleConstSP sp(new LLStyle(getDefaultStyleParams())); + LLStyleConstSP sp(new LLStyle(getStyleParams())); LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this); mSegments.insert(default_segment); default_segment->linkToDocument(this); @@ -1103,6 +1111,22 @@ void LLTextBase::deselect() mIsSelecting = FALSE; } +void LLTextBase::onFocusReceived() +{ + if (!getLength() && !mLabel.empty()) + { + // delete label which is LLLabelTextSegment + clearSegments(); + } +} + +void LLTextBase::onFocusLost() +{ + if (!getLength() && !mLabel.empty()) + { + resetLabel(); + } +} // Sets the scrollbar from the cursor position void LLTextBase::updateScrollFromCursor() @@ -1688,7 +1712,7 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) { LLStyle::Params style_params(input_params); - style_params.fillFrom(getDefaultStyleParams()); + style_params.fillFrom(getStyleParams()); S32 part = (S32)LLTextParser::WHOLE; if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). @@ -1770,6 +1794,39 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c appendTextImpl(new_text,input_params); } +void LLTextBase::setLabel(const LLStringExplicit& label) +{ + mLabel = label; + resetLabel(); +} + +BOOL LLTextBase::setLabelArg(const std::string& key, const LLStringExplicit& text ) +{ + mLabel.setArg(key, text); + return TRUE; +} + +void LLTextBase::resetLabel() +{ + if (!getLength() && !mLabel.empty() && !hasFocus()) + { + clearSegments(); + + LLStyle* style = new LLStyle(getStyleParams()); + style->setColor(mTentativeFgColor); + LLStyleConstSP sp(style); + + LLTextSegmentPtr label = new LLLabelTextSegment(sp, 0, getLabel().length() + 1, *this); + insertSegment(label); + } +} + +void LLTextBase::setFont(const LLFontGL* font) +{ + mFont = font; + mStyleDirty = true; +} + void LLTextBase::needsReflow(S32 index) { lldebugs << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << llendl; @@ -2160,7 +2217,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const { // return default height rect in upper left local_rect = content_window_rect; - local_rect.mBottom = local_rect.mTop - mDefaultFont->getLineHeight(); + local_rect.mBottom = local_rect.mTop - mFont->getLineHeight(); return local_rect; } @@ -2665,7 +2722,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele { F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha; - const LLWString &text = mEditor.getWText(); + const LLWString &text = getWText(); F32 right_x = rect.mLeft; if (!mStyle->isVisible()) @@ -2828,7 +2885,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt if (num_chars > 0) { height = mFontHeight; - const LLWString &text = mEditor.getWText(); + const LLWString &text = getWText(); // if last character is a newline, then return true, forcing line break width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); } @@ -2837,7 +2894,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { - const LLWString &text = mEditor.getWText(); + const LLWString &text = getWText(); return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset, (F32)segment_local_x_coord, F32_MAX, @@ -2847,7 +2904,7 @@ S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { - const LLWString &text = mEditor.getWText(); + const LLWString &text = getWText(); LLUIImagePtr image = mStyle->getImage(); if( image.notNull()) @@ -2883,7 +2940,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin S32 last_char_in_run = mStart + segment_offset + num_chars; // check length first to avoid indexing off end of string if (last_char_in_run < mEnd - && (last_char_in_run >= mEditor.getLength() )) + && (last_char_in_run >= getLength())) { num_chars++; } @@ -2901,6 +2958,39 @@ void LLNormalTextSegment::dump() const llendl; } +/*virtual*/ +const LLWString& LLNormalTextSegment::getWText() const +{ + return mEditor.getWText(); +} + +/*virtual*/ +const S32 LLNormalTextSegment::getLength() const +{ + return mEditor.getLength(); +} + +LLLabelTextSegment::LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ) +: LLNormalTextSegment(style, start, end, editor) +{ +} + +LLLabelTextSegment::LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) +: LLNormalTextSegment(color, start, end, editor, is_visible) +{ +} + +/*virtual*/ +const LLWString& LLLabelTextSegment::getWText() const +{ + return mEditor.getWlabel(); +} +/*virtual*/ +const S32 LLLabelTextSegment::getLength() const +{ + return mEditor.getLabel().length(); +} + // // LLOnHoverChangeableTextSegment // diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 0549141b72..412272b352 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -105,7 +105,7 @@ class LLNormalTextSegment : public LLTextSegment public: LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); - ~LLNormalTextSegment(); + virtual ~LLNormalTextSegment(); /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; @@ -130,6 +130,9 @@ public: protected: F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect); + virtual const LLWString& getWText() const; + virtual const S32 getLength() const; + protected: class LLTextBase& mEditor; LLStyleConstSP mStyle; @@ -139,6 +142,21 @@ protected: boost::signals2::connection mImageLoadedConnection; }; +// This text segment is the same as LLNormalTextSegment, the only difference +// is that LLNormalTextSegment draws value of LLTextBase (LLTextBase::getWText()), +// but LLLabelTextSegment draws label of the LLTextBase (LLTextBase::mLabel) +class LLLabelTextSegment : public LLNormalTextSegment +{ +public: + LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); + LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + +protected: + + /*virtual*/ const LLWString& getWText() const; + /*virtual*/ const S32 getLength() const; +}; + // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) class LLOnHoverChangeableTextSegment : public LLNormalTextSegment { @@ -249,6 +267,7 @@ public: Optional<LLUIColor> cursor_color, text_color, text_readonly_color, + text_tentative_color, bg_readonly_color, bg_writeable_color, bg_focus_color, @@ -311,6 +330,9 @@ public: /*virtual*/ BOOL canDeselect() const; /*virtual*/ void deselect(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + // used by LLTextSegment layout code bool getWordWrap() { return mWordWrap; } bool getUseEllipses() { return mUseEllipses; } @@ -330,6 +352,21 @@ public: const LLWString& getWText() const; void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); + + void setLabel(const LLStringExplicit& label); + virtual BOOL setLabelArg(const std::string& key, const LLStringExplicit& text ); + + const std::string& getLabel() { return mLabel.getString(); } + const LLWString& getWlabel() { return mLabel.getWString();} + + /** + * If label is set, draws text label (which is LLLabelTextSegment) + * that is visible when no user text provided and has no focus + */ + void resetLabel(); + + void setFont(const LLFontGL* font); + // force reflow of text void needsReflow(S32 index = 0); @@ -369,7 +406,7 @@ public: bool scrolledToStart(); bool scrolledToEnd(); - const LLFontGL* getDefaultFont() const { return mDefaultFont; } + const LLFontGL* getFont() const { return mFont; } virtual void appendLineBreakSegment(const LLStyle::Params& style_params); virtual void appendImageSegment(const LLStyle::Params& style_params); @@ -469,7 +506,7 @@ protected: void createDefaultSegment(); virtual void updateSegments(); void insertSegment(LLTextSegmentPtr segment_to_insert); - const LLStyle::Params& getDefaultStyleParams(); + const LLStyle::Params& getStyleParams(); // manage lines S32 getLineStart( S32 line ) const; @@ -514,15 +551,16 @@ protected: LLRect mTextBoundingRect; // default text style - LLStyle::Params mDefaultStyle; + LLStyle::Params mStyle; bool mStyleDirty; - const LLFontGL* const mDefaultFont; // font that is used when none specified, can only be set by constructor - const LLFontGL::ShadowType mFontShadow; // shadow style, can only be set by constructor + const LLFontGL* mFont; + const LLFontGL::ShadowType mFontShadow; // colors LLUIColor mCursorColor; LLUIColor mFgColor; LLUIColor mReadOnlyFgColor; + LLUIColor mTentativeFgColor; LLUIColor mWriteableBgColor; LLUIColor mReadOnlyBgColor; LLUIColor mFocusBgColor; @@ -558,6 +596,7 @@ protected: bool mClip; // clip text to widget rect bool mClipPartial; // false if we show lines that are partially inside bounding rect bool mPlainText; // didn't use Image or Icon segments + bool mAutoIndent; S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes // support widgets @@ -573,6 +612,7 @@ protected: // Fired when a URL link is clicked commit_signal_t* mURLClickSignal; + LLUIString mLabel; // text label that is visible when no user text provided }; #endif diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 9720dded6c..4fa6ea085e 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -235,6 +235,7 @@ LLTextEditor::Params::Params() embedded_items("embedded_items", false), ignore_tab("ignore_tab", true), show_line_numbers("show_line_numbers", false), + auto_indent("auto_indent", true), default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), show_context_menu("show_context_menu") @@ -249,6 +250,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mLastCmd( NULL ), mDefaultColor( p.default_color() ), mShowLineNumbers ( p.show_line_numbers ), + mAutoIndent(p.auto_indent), mCommitOnFocusLost( p.commit_on_focus_lost), mAllowEmbeddedItems( p.embedded_items ), mMouseDownX(0), @@ -256,7 +258,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mTabsToNextField(p.ignore_tab), mPrevalidateFunc(p.prevalidate_callback()), mContextMenu(NULL), - mShowContextMenu(p.show_context_menu) + mShowContextMenu(p.show_context_menu), + mPassDelete(FALSE) { mSourceID.generate(); @@ -1606,7 +1609,10 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) { deleteSelection(FALSE); } - autoIndent(); // TODO: make this optional + if (mAutoIndent) + { + autoIndent(); + } } else { @@ -1746,7 +1752,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( hasSelection() || (mCursorPos < getLength()) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() @@ -1984,7 +1990,7 @@ void LLTextEditor::drawPreeditMarker() return; } - const S32 line_height = mDefaultFont->getLineHeight(); + const S32 line_height = mFont->getLineHeight(); S32 line_start = getLineStart(cur_line); S32 line_y = mVisibleTextRect.mTop - line_height; @@ -2023,16 +2029,16 @@ void LLTextEditor::drawPreeditMarker() S32 preedit_left = mVisibleTextRect.mLeft; if (left > line_start) { - preedit_left += mDefaultFont->getWidth(text, line_start, left - line_start); + preedit_left += mFont->getWidth(text, line_start, left - line_start); } S32 preedit_right = mVisibleTextRect.mLeft; if (right < line_end) { - preedit_right += mDefaultFont->getWidth(text, line_start, right - line_start); + preedit_right += mFont->getWidth(text, line_start, right - line_start); } else { - preedit_right += mDefaultFont->getWidth(text, line_start, line_end - line_start); + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); } if (mPreeditStandouts[i]) @@ -2707,11 +2713,11 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect const LLWString textString(getWText()); const llwchar * const text = textString.c_str(); - const S32 line_height = mDefaultFont->getLineHeight(); + const S32 line_height = mFont->getLineHeight(); if (coord) { - const S32 query_x = mVisibleTextRect.mLeft + mDefaultFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; S32 query_screen_x, query_screen_y; localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); @@ -2723,17 +2729,17 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect S32 preedit_left = mVisibleTextRect.mLeft; if (preedit_left_position > current_line_start) { - preedit_left += mDefaultFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); } S32 preedit_right = mVisibleTextRect.mLeft; if (preedit_right_position < current_line_end) { - preedit_right += mDefaultFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); } else { - preedit_right += mDefaultFont->getWidth(text, current_line_start, current_line_end - current_line_start); + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); } const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; @@ -2810,7 +2816,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length) S32 LLTextEditor::getPreeditFontSize() const { - return llround((F32)mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); + return llround((F32)mFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); } BOOL LLTextEditor::isDirty() const diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 40821ae9fb..f8f636b876 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -64,7 +64,8 @@ public: ignore_tab, show_line_numbers, commit_on_focus_lost, - show_context_menu; + show_context_menu, + auto_indent; //colors Optional<LLUIColor> default_color; @@ -202,6 +203,8 @@ public: void setShowContextMenu(bool show) { mShowContextMenu = show; } bool getShowContextMenu() const { return mShowContextMenu; } + void setPassDelete(BOOL b) { mPassDelete = b; } + protected: void showContextMenu(S32 x, S32 y); void drawPreeditMarker(); @@ -214,8 +217,8 @@ protected: S32 indentLine( S32 pos, S32 spaces ); void unindentLineBeforeCloseBrace(); + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSpecialKey(const KEY key, const MASK mask); BOOL handleSelectionKey(const KEY key, const MASK mask); BOOL handleControlKey(const KEY key, const MASK mask); @@ -279,6 +282,7 @@ protected: LLUIColor mDefaultColor; BOOL mShowLineNumbers; + bool mAutoIndent; /*virtual*/ void updateSegments(); void updateLinkSegments(); @@ -321,6 +325,7 @@ private: BOOL mAllowEmbeddedItems; bool mShowContextMenu; bool mParseOnTheFly; + bool mPassDelete; LLUUID mSourceID; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dee37bd5e8..64bc70da58 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -103,6 +103,8 @@ set(viewer_SOURCE_FILES llavatarlist.cpp llavatarlistitem.cpp llavatarpropertiesprocessor.cpp + llblockedlistitem.cpp + llblocklist.cpp llbox.cpp llbreadcrumbview.cpp llbrowsernotification.cpp @@ -661,6 +663,8 @@ set(viewer_HEADER_FILES llavatarlist.h llavatarlistitem.h llavatarpropertiesprocessor.h + llblockedlistitem.h + llblocklist.h llbox.h llbreadcrumbview.h llbuycurrencyhtml.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 73df064ab2..51211a8ce5 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -46,11 +46,11 @@ available_in_toybox="true" icon="Command_Chat_Icon" label_ref="Command_Chat_Label" - tooltip_ref="Command_Chat_Tooltip" + tooltip_ref="Command_Conversations_Tooltip" execute_function="Floater.ToggleOrBringToFront" - execute_parameters="chat_bar" + execute_parameters="im_container" is_running_function="Floater.IsOpen" - is_running_parameters="chat_bar" + is_running_parameters="im_container" /> <command name="compass" available_in_toybox="false" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 46c29e32e2..4a586b02af 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1617,17 +1617,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>ChatWindow</key> - <map> - <key>Comment</key> - <string>Show chat in multiple windows(by default) or in one multi-tabbed window(requires restart)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>CheesyBeacon</key> <map> <key>Comment</key> @@ -9809,7 +9798,7 @@ <key>ShowScriptErrorsLocation</key> <map> <key>Comment</key> - <string>Show script error in chat or window</string> + <string>Show script error in chat (0) or window (1).</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -9993,6 +9982,17 @@ <key>Value</key> <integer>2</integer> </map> + <key>BlockPeopleSortOrder</key> + <map> + <key>Comment</key> + <string>Specifies sort order for recent people (0 = by name, 1 = by type)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>2</integer> + </map> <key>ShowPGSearchAll</key> <map> <key>Comment</key> diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index b154dd458c..fb32bcbd60 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -529,23 +529,6 @@ namespace action_give_inventory return acceptable; } - static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string) - { - llassert(avatar_names.size() > 0); - - const std::string& separator = LLTrans::getString("words_separator"); - for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; ) - { - LLAvatarName av_name = *it; - residents_string.append(av_name.mDisplayName); - if (++it == avatar_names.end()) - { - break; - } - residents_string.append(separator); - } - } - static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string) { llassert(inventory_selected_uuids.size() > 0); @@ -675,7 +658,7 @@ namespace action_give_inventory } std::string residents; - build_residents_string(avatar_names, residents); + LLAvatarActions::buildResidentsString(avatar_names, residents); std::string items; build_items_string(inventory_selected_uuids, items); @@ -706,7 +689,23 @@ namespace action_give_inventory } } +// static +void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string) +{ + llassert(avatar_names.size() > 0); + const std::string& separator = LLTrans::getString("words_separator"); + for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; ) + { + LLAvatarName av_name = *it; + residents_string.append(av_name.mDisplayName); + if (++it == avatar_names.end()) + { + break; + } + residents_string.append(separator); + } +} //static std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs() diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 0a69ad86a3..46830eb22c 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -34,6 +34,7 @@ #include <string> #include <vector> +class LLAvatarName; class LLInventoryPanel; class LLFloater; @@ -208,6 +209,14 @@ public: */ static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL); + /** + * Builds a string of residents' display names separated by "words_separator" string. + * + * @param avatar_names - a vector of given avatar names from which resulting string is built + * @param residents_string - the resulting string + */ + static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string); + static std::set<LLUUID> getInventorySelectedUUIDs(); private: diff --git a/indra/newview/llblockedlistitem.cpp b/indra/newview/llblockedlistitem.cpp new file mode 100644 index 0000000000..d9afd2b629 --- /dev/null +++ b/indra/newview/llblockedlistitem.cpp @@ -0,0 +1,114 @@ +/** + * @file llviewerobjectlistitem.cpp + * @brief viewer object list item implementation + * + * Class LLPanelInventoryListItemBase displays inventory item as an element + * of LLInventoryItemsList. + * + * $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 "llblockedlistitem.h" + +// llui +#include "lliconctrl.h" +#include "lltextbox.h" +#include "lltextutil.h" + +// newview +#include "llavatariconctrl.h" +#include "llgroupiconctrl.h" +#include "llinventoryicon.h" +#include "llviewerobject.h" + +LLBlockedListItem::LLBlockedListItem(const LLMute* item) +: LLPanel(), + mItemID(item->mID), + mItemName(item->mName), + mMuteType(item->mType) +{ + buildFromFile("panel_blocked_list_item.xml"); +} + +BOOL LLBlockedListItem::postBuild() +{ + mTitleCtrl = getChild<LLTextBox>("item_name"); + mTitleCtrl->setValue(mItemName); + + switch (mMuteType) + { + case LLMute::AGENT: + case LLMute::EXTERNAL: + { + LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon"); + avatar_icon->setVisible(TRUE); + avatar_icon->setValue(mItemID); + } + break; + case LLMute::GROUP: + { + LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon"); + group_icon->setVisible(TRUE); + group_icon->setValue(mItemID); + } + break; + case LLMute::OBJECT: + case LLMute::BY_NAME: + getChild<LLUICtrl>("object_icon")->setVisible(TRUE); + break; + + default: + break; + } + + return TRUE; +} + +void LLBlockedListItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + getChildView("hovered_icon")->setVisible(true); + LLPanel::onMouseEnter(x, y, mask); +} + +void LLBlockedListItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + getChildView("hovered_icon")->setVisible(false); + LLPanel::onMouseLeave(x, y, mask); +} + +void LLBlockedListItem::setValue(const LLSD& value) +{ + if (!value.isMap() || !value.has("selected")) + { + return; + } + + getChildView("selected_icon")->setVisible(value["selected"]); +} + +void LLBlockedListItem::highlightName(const std::string& highlited_text) +{ + LLStyle::Params params; + LLTextUtil::textboxSetHighlightedVal(mTitleCtrl, params, mItemName, highlited_text); +} diff --git a/indra/newview/llblockedlistitem.h b/indra/newview/llblockedlistitem.h new file mode 100644 index 0000000000..05409e8a3b --- /dev/null +++ b/indra/newview/llblockedlistitem.h @@ -0,0 +1,73 @@ +/** + * @file llviewerobjectlistitem.h + * @brief viewer object list item header file + * + * $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 LLVIEWEROBJECTLISTITEM_H_ +#define LLVIEWEROBJECTLISTITEM_H_ + +#include "llmutelist.h" +#include "llpanel.h" +#include "llstyle.h" +#include "lltextbox.h" +#include "lliconctrl.h" + +/** + * This class represents items of LLBlockList, which represents + * contents of LLMuteList. LLMuteList "consists" of LLMute items. + * Each LLMute represents either blocked avatar or object and + * stores info about mute type (avatar or object) + * + * Each item consists if object/avatar icon and object/avatar name + * + * To create a blocked list item just need to pass LLMute pointer + * and appropriate block list item will be created depending on + * LLMute type (LLMute::EType) and other LLMute's info + */ +class LLBlockedListItem : public LLPanel +{ +public: + + LLBlockedListItem(const LLMute* item); + virtual BOOL postBuild(); + + void onMouseEnter(S32 x, S32 y, MASK mask); + void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void setValue(const LLSD& value); + + void highlightName(const std::string& highlited_text); + const std::string& getName() const { return mItemName; } + const LLMute::EType& getType() const { return mMuteType; } + const LLUUID& getUUID() const { return mItemID; } + +private: + + LLTextBox* mTitleCtrl; + const LLUUID mItemID; + std::string mItemName; + LLMute::EType mMuteType; + +}; + +#endif /* LLVIEWEROBJECTLISTITEM_H_ */ diff --git a/indra/newview/llblocklist.cpp b/indra/newview/llblocklist.cpp new file mode 100644 index 0000000000..cb68f677eb --- /dev/null +++ b/indra/newview/llblocklist.cpp @@ -0,0 +1,276 @@ +/** + * @file llblocklist.cpp + * @brief List of the blocked avatars and objects. + * + * $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 "llblocklist.h" + +#include "llavataractions.h" +#include "llblockedlistitem.h" +#include "llfloatersidepanelcontainer.h" +#include "llviewermenu.h" + +static LLDefaultChildRegistry::Register<LLBlockList> r("block_list"); + +static const LLBlockListNameComparator NAME_COMPARATOR; +static const LLBlockListNameTypeComparator NAME_TYPE_COMPARATOR; + +LLBlockList::LLBlockList(const Params& p) +: LLFlatListViewEx(p), + mSelectedItem(NULL), + mDirty(true) +{ + + LLMuteList::getInstance()->addObserver(this); + + // Set up context menu. + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + + registrar.add ("Block.Action", boost::bind(&LLBlockList::onCustomAction, this, _2)); + enable_registrar.add("Block.Enable", boost::bind(&LLBlockList::isActionEnabled, this, _2)); + + LLToggleableMenu* context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( + "menu_people_blocked_gear.xml", + gMenuHolder, + LLViewerMenuHolderGL::child_registry_t::instance()); + if(context_menu) + { + mContextMenu = context_menu->getHandle(); + } +} + +LLBlockList::~LLBlockList() +{ + if (mContextMenu.get()) + { + mContextMenu.get()->die(); + } + + LLMuteList::getInstance()->removeObserver(this); +} + +BOOL LLBlockList::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask); + + LLToggleableMenu* context_menu = mContextMenu.get(); + if (context_menu && size()) + { + context_menu->buildDrawLabels(); + context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, context_menu, x, y); + } + + return handled; +} + +void LLBlockList::setNameFilter(const std::string& filter) +{ + std::string filter_upper = filter; + LLStringUtil::toUpper(filter_upper); + if (mNameFilter != filter_upper) + { + mNameFilter = filter_upper; + setDirty(); + } +} + +void LLBlockList::sortByName() +{ + setComparator(&NAME_COMPARATOR); + sort(); +} + +void LLBlockList::sortByType() +{ + setComparator(&NAME_TYPE_COMPARATOR); + sort(); +} + +void LLBlockList::draw() +{ + if (mDirty) + { + refresh(); + } + + LLFlatListView::draw(); +} + +void LLBlockList::addNewItem(const LLMute* mute) +{ + LLBlockedListItem* item = new LLBlockedListItem(mute); + if (!mNameFilter.empty()) + { + item->highlightName(mNameFilter); + } + addItem(item, item->getUUID(), ADD_BOTTOM); +} + +void LLBlockList::refresh() +{ + bool have_filter = !mNameFilter.empty(); + + // save selection to restore it after list rebuilt + LLUUID selected = getSelectedUUID(); + + // calling refresh may be initiated by removing currently selected item + // so select next item and save the selection to restore it after list rebuilt + if (!selectNextItemPair(false, true)) + { + selectNextItemPair(true, true); + } + LLUUID next_selected = getSelectedUUID(); + + clear(); + + std::vector<LLMute> mutes = LLMuteList::instance().getMutes(); + std::vector<LLMute>::const_iterator mute_it = mutes.begin(); + + for (; mute_it != mutes.end(); ++mute_it) + { + if (have_filter && !findInsensitive(mute_it->mName, mNameFilter)) + continue; + + addNewItem(&*mute_it); + } + + if (getItemPair(selected)) + { + // restore previously selected item + selectItemPair(getItemPair(selected), true); + } + else if (getItemPair(next_selected)) + { + // previously selected item was removed, so select next item + selectItemPair(getItemPair(next_selected), true); + } + + // Sort the list. + sort(); + + setDirty(false); +} + +bool LLBlockList::findInsensitive(std::string haystack, const std::string& needle_upper) +{ + LLStringUtil::toUpper(haystack); + return haystack.find(needle_upper) != std::string::npos; +} + +LLBlockedListItem* LLBlockList::getBlockedItem() const +{ + LLPanel* panel = LLFlatListView::getSelectedItem(); + LLBlockedListItem* item = dynamic_cast<LLBlockedListItem*>(panel); + return item; +} + +bool LLBlockList::isActionEnabled(const LLSD& userdata) +{ + bool action_enabled = true; + + const std::string command_name = userdata.asString(); + + if ("unblock_item" == command_name || "profile_item" == command_name) + { + action_enabled = getSelectedItem() != NULL; + } + + return action_enabled; +} + +void LLBlockList::onCustomAction(const LLSD& userdata) +{ + if (!isActionEnabled(userdata)) + { + return; + } + + LLBlockedListItem* item = getBlockedItem(); + const std::string command_name = userdata.asString(); + + if ("unblock_item" == command_name) + { + LLMute mute(item->getUUID(), item->getName()); + LLMuteList::getInstance()->remove(mute); + } + else if ("profile_item" == command_name) + { + switch(item->getType()) + { + + case LLMute::AGENT: + LLAvatarActions::showProfile(item->getUUID()); + break; + + case LLMute::OBJECT: + LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", item->getUUID())); + break; + + default: + break; + } + } +} + +bool LLBlockListItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const +{ + const LLBlockedListItem* blocked_item1 = dynamic_cast<const LLBlockedListItem*>(item1); + const LLBlockedListItem* blocked_item2 = dynamic_cast<const LLBlockedListItem*>(item2); + + if (!blocked_item1 || !blocked_item2) + { + llerror("blocked_item1 and blocked_item2 cannot be null", 0); + return true; + } + + return doCompare(blocked_item1, blocked_item2); +} + +bool LLBlockListNameComparator::doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const +{ + std::string name1 = blocked_item1->getName(); + std::string name2 = blocked_item2->getName(); + + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); + + return name1 < name2; +} + +bool LLBlockListNameTypeComparator::doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const +{ + LLMute::EType type1 = blocked_item1->getType(); + LLMute::EType type2 = blocked_item2->getType(); + + if (type1 != type2) + { + return type1 > type2; + } + + return NAME_COMPARATOR.compare(blocked_item1, blocked_item2); +} diff --git a/indra/newview/llblocklist.h b/indra/newview/llblocklist.h new file mode 100644 index 0000000000..1a215710f4 --- /dev/null +++ b/indra/newview/llblocklist.h @@ -0,0 +1,138 @@ +/** + * @file llblocklist.h + * @brief List of the blocked avatars and objects. + * + * $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 LLBLOCKLIST_H_ +#define LLBLOCKLIST_H_ + +#include "llflatlistview.h" +#include "lllistcontextmenu.h" +#include "llmutelist.h" +#include "lltoggleablemenu.h" + +class LLBlockedListItem; +class LLMute; + +/** + * List of blocked avatars and objects. + * This list represents contents of the LLMuteList. + * Each change in LLMuteList leads to rebuilding this list, so + * it's always in actual state. + */ +class LLBlockList: public LLFlatListViewEx, public LLMuteListObserver +{ + LOG_CLASS(LLBlockList); +public: + struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params> + { + Params(){}; + }; + + LLBlockList(const Params& p); + virtual ~LLBlockList(); + + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + LLToggleableMenu* getContextMenu() const { return mContextMenu.get(); } + LLBlockedListItem* getBlockedItem() const; + + virtual void onChange() { refresh(); } + virtual void draw(); + + void setNameFilter(const std::string& filter); + void sortByName(); + void sortByType(); + void refresh(); + +private: + + void addNewItem(const LLMute* mute); + void setDirty(bool dirty = true) { mDirty = dirty; } + bool findInsensitive(std::string haystack, const std::string& needle_upper); + + bool isActionEnabled(const LLSD& userdata); + void onCustomAction (const LLSD& userdata); + + + LLHandle<LLToggleableMenu> mContextMenu; + + LLBlockedListItem* mSelectedItem; + std::string mNameFilter; + bool mDirty; + +}; + + +/* + * Abstract comparator for blocked items + */ +class LLBlockListItemComparator : public LLFlatListView::ItemComparator +{ + LOG_CLASS(LLBlockListItemComparator); + +public: + LLBlockListItemComparator() {}; + virtual ~LLBlockListItemComparator() {}; + + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const; + +protected: + + virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const = 0; +}; + + +/* + * Compares items by name + */ +class LLBlockListNameComparator : public LLBlockListItemComparator +{ + LOG_CLASS(LLBlockListNameComparator); + +public: + LLBlockListNameComparator() {}; + virtual ~LLBlockListNameComparator() {}; + +protected: + + virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const; +}; + +/* + * Compares items by type and then by name within type + * Objects come first then avatars + */ +class LLBlockListNameTypeComparator : public LLBlockListItemComparator +{ + LOG_CLASS(LLBlockListNameTypeComparator); + +public: + LLBlockListNameTypeComparator() {}; + virtual ~LLBlockListNameTypeComparator() {}; + +protected: + + virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const; +}; + +#endif /* LLBLOCKLIST_H_ */ diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 477bdb3967..61772b4bb7 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -96,8 +96,15 @@ void LLNearbyChatToastPanel::reshape (S32 width, S32 height, BOOL called_from_p { LLPanel::reshape(width, height,called_from_parent); - LLUICtrl* msg_text = getChild<LLUICtrl>("msg_text", false); - LLUICtrl* icon = getChild<LLUICtrl>("avatar_icon", false); + // reshape() may be called from LLView::initFromParams() before the children are created. + // We call findChild() instead of getChild() here to avoid creating dummy controls. + LLUICtrl* msg_text = findChild<LLUICtrl>("msg_text", false); + LLUICtrl* icon = findChild<LLUICtrl>("avatar_icon", false); + + if (!msg_text || !icon) + { + return; + } LLRect msg_text_rect = msg_text->getRect(); LLRect avatar_rect = icon->getRect(); @@ -355,6 +362,8 @@ BOOL LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask) } void LLNearbyChatToastPanel::draw() { + LLPanel::draw(); + if(mIsDirty) { LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 3973b6547a..f51d7b622c 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -873,9 +873,10 @@ class LLIMWellChiclet : public LLSysWellChiclet, LLIMSessionObserver { friend class LLUICtrlFactory; public: - virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {} - virtual void sessionRemoved(const LLUUID& session_id) { messageCountChanged(LLSD()); } - virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {} + /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {} + /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {}; + /*virtual*/ void sessionRemoved(const LLUUID& session_id) { messageCountChanged(LLSD()); } + /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {} ~LLIMWellChiclet(); protected: diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp index 8701b602ce..39f5d0b8f6 100644 --- a/indra/newview/llchicletbar.cpp +++ b/indra/newview/llchicletbar.cpp @@ -57,19 +57,11 @@ LLChicletBar::LLChicletBar(const LLSD&) : mChicletPanel(NULL), mToolbarStack(NULL) { - // Firstly add our self to IMSession observers, so we catch session events - // before chiclets do that. - LLIMMgr::getInstance()->addSessionObserver(this); - buildFromFile("panel_chiclet_bar.xml"); } LLChicletBar::~LLChicletBar() { - if (!LLSingleton<LLIMMgr>::destroyed()) - { - LLIMMgr::getInstance()->removeSessionObserver(this); - } } LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id) @@ -102,6 +94,13 @@ void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& nam // no need to spawn chiclets for participants in P2P calls called through Avaline if (session->isP2P() && session->isOtherParticipantAvaline()) return; + // Do not spawn chiclet when using the new multitab conversation UI + if (LLIMConversation::isChatMultiTab()) + { + LLIMFloater::addToHost(session_id); + return; + } + if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return; LLIMChiclet* chiclet = createIMChiclet(session_id); @@ -109,7 +108,7 @@ void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& nam { chiclet->setIMSessionName(name); chiclet->setOtherParticipantId(other_participant_id); - + LLIMFloater::onIMChicletCreated(session_id); } diff --git a/indra/newview/llchicletbar.h b/indra/newview/llchicletbar.h index 1427bf95e0..7d0d904810 100644 --- a/indra/newview/llchicletbar.h +++ b/indra/newview/llchicletbar.h @@ -50,9 +50,10 @@ public: LLChicletPanel* getChicletPanel() { return mChicletPanel; } // LLIMSessionObserver observe triggers - virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); - virtual void sessionRemoved(const LLUUID& session_id); - void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); + /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {}; + /*virtual*/ void sessionRemoved(const LLUUID& session_id); + /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); S32 getTotalUnreadIMCount(); diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 935dcb74b0..a50184460b 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -150,7 +150,7 @@ void LLExpandableTextBox::LLTextBoxEx::showExpandText() std::pair<S32, S32> visible_lines = getVisibleLines(true); S32 last_line = visible_lines.second - 1; - LLStyle::Params expander_style(getDefaultStyleParams()); + LLStyle::Params expander_style(getStyleParams()); expander_style.font.style = "UNDERLINE"; expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this); @@ -166,7 +166,7 @@ void LLExpandableTextBox::LLTextBoxEx::hideExpandText() if (mExpanderVisible) { // this will overwrite the expander segment and all text styling with a single style - LLStyleConstSP sp(new LLStyle(getDefaultStyleParams())); + LLStyleConstSP sp(new LLStyle(getStyleParams())); LLNormalTextSegment* segmentp = new LLNormalTextSegment(sp, 0, getLength() + 1, *this); insertSegment(segmentp); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 18ab9dc264..996cf1e212 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -423,8 +423,6 @@ void LLFloaterPreference::saveAvatarProperties( void ) BOOL LLFloaterPreference::postBuild() { -// gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&LLIMConversation::processChatHistoryStyleUpdate)); - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLIMConversation::processChatHistoryStyleUpdate)); gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged)); @@ -542,8 +540,6 @@ void LLFloaterPreference::apply() // LLWString busy_response = utf8str_to_wstring(getChild<LLUICtrl>("busy_response")->getValue().asString()); // LLWStringUtil::replaceTabsWithSpaces(busy_response, 4); - - gSavedSettings.setBOOL("PlainTextChatHistory", getChild<LLUICtrl>("plain_text_chat_history")->getValue().asBoolean()); if (mGotPersonalInfo) { @@ -1412,8 +1408,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im getChild<LLUICtrl>("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); getChildView("send_im_to_email")->setEnabled(TRUE); getChild<LLUICtrl>("send_im_to_email")->setValue(im_via_email); - getChildView("plain_text_chat_history")->setEnabled(TRUE); - getChild<LLUICtrl>("plain_text_chat_history")->setValue(gSavedSettings.getBOOL("PlainTextChatHistory")); getChildView("log_instant_messages")->setEnabled(TRUE); // getChildView("log_chat")->setEnabled(TRUE); // getChildView("busy_response")->setEnabled(TRUE); diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index ac389c9189..80893c3037 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -218,7 +218,7 @@ BOOL LLFolderViewItem::passedFilter(S32 filter_generation) } void LLFolderViewItem::refresh() -{ +{ LLFolderViewModelItem& vmi = *getViewModelItem(); mLabel = vmi.getDisplayName(); @@ -422,12 +422,12 @@ void LLFolderViewItem::rename(const std::string& new_name) { getViewModelItem()->renameItem(new_name); - if(mParentFolder) - { - mParentFolder->requestSort(); + if(mParentFolder) + { + mParentFolder->requestSort(); + } } } -} const std::string& LLFolderViewItem::getName( void ) const { @@ -539,7 +539,10 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) } else { + if (getRoot()) + { getRoot()->setShowSelectionContext(FALSE); + } gViewerWindow->setCursor(UI_CURSOR_ARROW); // let parent handle this then... return FALSE; @@ -582,7 +585,10 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) if( hasMouseCapture() ) { + if (getRoot()) + { getRoot()->setShowSelectionContext(FALSE); + } gFocusMgr.setMouseCapture( NULL ); } return TRUE; @@ -601,16 +607,16 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, { BOOL handled = FALSE; BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg); - handled = accepted; - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } + handled = accepted; + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } if(mParentFolder && !handled) { // store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event. @@ -628,17 +634,17 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, 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 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 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 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); - static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); + static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>(); const S32 TOP_PAD = default_params.item_top_pad; @@ -662,8 +668,8 @@ void LLFolderViewItem::draw() //--------------------------------------------------------------------------------// // Draw highlight for selected items // - const BOOL show_context = getRoot()->getShowSelectionContext(); - const BOOL filled = show_context || (getRoot()->getParentPanel()->hasFocus()); // If we have keyboard focus, draw selection filled + 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); @@ -674,8 +680,8 @@ void LLFolderViewItem::draw() if (!mIsCurSelection) { // do time-based fade of extra objects - F32 fade_time = getRoot()->getSelectionFadeElapsedTime(); - if (getRoot()->getShowSingleSelection()) + 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); @@ -777,7 +783,7 @@ void LLFolderViewItem::draw() //TODO RN: implement this in terms of getColor() //if (highlight_link) color = sLinkColor; //if (gInventory.isObjectDescendentOf(getViewModelItem()->getUUID(), gInventory.getLibraryRootFolderID())) color = sLibraryColor; - + 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); @@ -828,12 +834,12 @@ void LLFolderViewItem::draw() } const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const -{ + { return getRoot()->getFolderViewModel(); } LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) -{ + { return getRoot()->getFolderViewModel(); } @@ -864,7 +870,7 @@ LLFolderViewFolder::~LLFolderViewFolder( void ) // addToFolder() returns TRUE if it succeeds. FALSE otherwise BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder) -{ + { return folder->addFolder(this); } @@ -1450,29 +1456,29 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) BOOL LLFolderViewFolder::isMovable() { if( !(getViewModelItem()->isItemMovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isMovable()) { return FALSE; } - } - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isMovable()) + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) { - return FALSE; + items_t::iterator iit = iter++; + if(!(*iit)->isMovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isMovable()) + { + return FALSE; + } } - } return TRUE; } @@ -1480,29 +1486,29 @@ BOOL LLFolderViewFolder::isMovable() BOOL LLFolderViewFolder::isRemovable() { if( !(getViewModelItem()->isItemRemovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isRemovable()) { return FALSE; } - } - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isRemovable()) + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) { - return FALSE; + items_t::iterator iit = iter++; + if(!(*iit)->isRemovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isRemovable()) + { + return FALSE; + } } - } return TRUE; } @@ -1595,12 +1601,12 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r { BOOL was_open = isOpen(); mIsOpen = openitem; - if(!was_open && openitem) - { + if(!was_open && openitem) + { getViewModelItem()->openItem(); - } - else if(was_open && !openitem) - { + } + else if(was_open && !openitem) + { getViewModelItem()->closeItem(); } diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 2de891565c..aba3d74d87 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -406,7 +406,7 @@ void LLGroupListItem::setActive(bool active) // *BUG: setName() overrides the style params. // Active group should be bold. - LLFontDescriptor new_desc(mGroupNameBox->getDefaultFont()->getFontDesc()); + LLFontDescriptor new_desc(mGroupNameBox->getFont()->getFontDesc()); // *NOTE dzaporozhan // On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 6c8f4406ab..e96a720886 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -48,6 +48,10 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener { LOG_CLASS(LLGroupList); public: + struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params> + { + Params(){}; + }; LLGroupList(const Params& p); virtual ~LLGroupList(); diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp index b45fc63825..acdd7ba46a 100644 --- a/indra/newview/llimconversation.cpp +++ b/indra/newview/llimconversation.cpp @@ -29,25 +29,29 @@ #include "llimconversation.h" +#include "llchatentry.h" +#include "llchathistory.h" #include "lldraghandle.h" #include "llfloaterreg.h" #include "llimfloater.h" #include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container #include "lllayoutstack.h" #include "llnearbychat.h" -#include "llnearbychat.h" const F32 REFRESH_INTERVAL = 0.2f; LLIMConversation::LLIMConversation(const LLUUID& session_id) : LLTransientDockableFloater(NULL, true, session_id) - , LLEventTimer(REFRESH_INTERVAL) , mIsP2PChat(false) , mExpandCollapseBtn(NULL) , mTearOffBtn(NULL) , mCloseBtn(NULL) , mSessionID(session_id) , mParticipantList(NULL) + , mChatHistory(NULL) + , mInputEditor(NULL) + , mInputEditorTopPad(0) + , mRefreshTimer(new LLTimer()) { mCommitCallbackRegistrar.add("IMSession.Menu.Action", boost::bind(&LLIMConversation::onIMSessionMenuItemClicked, this, _2)); @@ -63,6 +67,10 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id) boost::bind(&LLIMConversation::onIMShowModesMenuItemCheck, this, _2)); mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.Enable", boost::bind(&LLIMConversation::onIMShowModesMenuItemEnable, this, _2)); + + // Zero expiry time is set only once to allow initial update. + mRefreshTimer->setTimerExpirySec(0); + mRefreshTimer->start(); } LLIMConversation::~LLIMConversation() @@ -72,6 +80,8 @@ LLIMConversation::~LLIMConversation() delete mParticipantList; mParticipantList = NULL; } + + delete mRefreshTimer; } BOOL LLIMConversation::postBuild() @@ -84,25 +94,29 @@ BOOL LLIMConversation::postBuild() mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel"); - // Show the participants list in torn off floaters only. -// mParticipantListPanel->setVisible(gSavedSettings.getBOOL("IMShowControlPanel") -// && !mIsNearbyChat); // *TODO: temporarily disabled for Nearby chat -// mExpandCollapseBtn->setImageOverlay( -// getString(mParticipantListPanel->getVisible() ? "collapse_icon" : "expand_icon")); -// mExpandCollapseBtn->setEnabled(!mIsP2PChat); - mTearOffBtn = getChild<LLButton>("tear_off_btn"); mTearOffBtn->setCommitCallback(boost::bind(&LLIMConversation::onTearOffClicked, this)); + mChatHistory = getChild<LLChatHistory>("chat_history"); + mInputEditor = getChild<LLChatEntry>("chat_editor"); + + mInputEditor->setTextExpandedCallback(boost::bind(&LLIMConversation::reshapeChatHistory, this)); + mInputEditorTopPad = mChatHistory->getRect().mBottom - mInputEditor->getRect().mTop; + if (!getTornOff()) { setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE); } buildParticipantList(); + updateHeaderAndToolbar(); if (isChatMultiTab()) { + if (mIsNearbyChat) + { + setCanClose(FALSE); + } return LLFloater::postBuild(); } else @@ -112,31 +126,38 @@ BOOL LLIMConversation::postBuild() } -BOOL LLIMConversation::tick() +void LLIMConversation::draw() { - // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater - // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy(). - if (isDead()) return false; + LLTransientDockableFloater::draw(); - // Need to resort the participant list if it's in sort by recent speaker order. - if (mParticipantList) + if (mRefreshTimer->hasExpired()) { - mParticipantList->update(); - } + if (mParticipantList) + { + mParticipantList->update(); + } - return false; + refresh(); + + // Restart the refresh timer + mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL); + } } void LLIMConversation::buildParticipantList() -{ if (mIsNearbyChat) +{ + if (mIsNearbyChat) { + LLLocalSpeakerMgr* speaker_manager = LLLocalSpeakerMgr::getInstance(); + mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false); } else { + LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID); // for group and ad-hoc chat we need to include agent into list - if(!mIsP2PChat && !mParticipantList && mSessionID.notNull()) + if(!mIsP2PChat && mSessionID.notNull() && speaker_manager) { - LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + delete mParticipantList; // remove the old list and create a new one if the session id has changed mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false); } } @@ -144,9 +165,11 @@ void LLIMConversation::buildParticipantList() void LLIMConversation::onSortMenuItemClicked(const LLSD& userdata) { - // TODO: Check this code when when sort order menu will be added. (EM) - if (true || !mParticipantList) + // TODO: Check this code when sort order menu will be added. (EM) + if (!mParticipantList) + { return; + } std::string chosen_item = userdata.asString(); @@ -218,8 +241,7 @@ void LLIMConversation::updateHeaderAndToolbar() bool is_participant_list_visible = !is_hosted && gSavedSettings.getBOOL("IMShowControlPanel") - && !mIsP2PChat - && !mIsNearbyChat; // *TODO: temporarily disabled for Nearby chat + && !mIsP2PChat; mParticipantListPanel->setVisible(is_participant_list_visible); @@ -228,20 +250,40 @@ void LLIMConversation::updateHeaderAndToolbar() bool is_expanded = is_hosted || is_participant_list_visible; mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon")); - // The button (>>) should be disabled for torn off P2P conversations. - mExpandCollapseBtn->setEnabled(is_hosted || !mIsP2PChat && !mIsNearbyChat); - + // toggle floater's drag handle and title visibility if (mDragHandle) { - // toggle floater's drag handle and title visibility - mDragHandle->setVisible(!is_hosted); + mDragHandle->setTitleVisible(!is_hosted); + setCanDrag(!is_hosted); } + setCanResize(!is_hosted); + + // The button (>>) should be disabled for torn off P2P conversations. + mExpandCollapseBtn->setEnabled(is_hosted || !mIsP2PChat); mTearOffBtn->setImageOverlay(getString(is_hosted ? "tear_off_icon" : "return_icon")); - mCloseBtn->setVisible(is_hosted); + mCloseBtn->setVisible(is_hosted && !mIsNearbyChat); enableDisableCallBtn(); + + showTranslationCheckbox(); +} + +void LLIMConversation::reshapeChatHistory() +{ + LLRect chat_rect = mChatHistory->getRect(); + LLRect input_rect = mInputEditor->getRect(); + + int delta_height = chat_rect.mBottom - (input_rect.mTop + mInputEditorTopPad); + + chat_rect.setLeftTopAndSize(chat_rect.mLeft, chat_rect.mTop, chat_rect.getWidth(), chat_rect.getHeight() + delta_height); + mChatHistory->setShape(chat_rect); +} + +void LLIMConversation::showTranslationCheckbox(BOOL show) +{ + getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(mIsNearbyChat? show : FALSE); } // static @@ -307,9 +349,25 @@ void LLIMConversation::onOpen(const LLSD& key) host_floater->collapseMessagesPane(false); } + setCanResize(TRUE); + updateHeaderAndToolbar(); } +// virtual +void LLIMConversation::onClose(bool app_quitting) +{ + // Always suppress the IM from the conversations list on close if present for any reason + if (LLIMConversation::isChatMultiTab()) + { + LLIMFloaterContainer* im_box = LLIMFloaterContainer::findInstance(); + if (im_box) + { + im_box->removeConversationListItem(this); + } + } +} + void LLIMConversation::onTearOffClicked() { onClickTearOff(this); @@ -320,6 +378,5 @@ void LLIMConversation::onTearOffClicked() bool LLIMConversation::isChatMultiTab() { // Restart is required in order to change chat window type. - static bool is_single_window = gSavedSettings.getS32("ChatWindow") == 1; - return is_single_window; + return true; } diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h index d31ae0808a..50663137ac 100644 --- a/indra/newview/llimconversation.h +++ b/indra/newview/llimconversation.h @@ -35,10 +35,11 @@ #include "lleventtimer.h" class LLPanelChatControlPanel; +class LLChatEntry; +class LLChatHistory; class LLIMConversation : public LLTransientDockableFloater - , public LLEventTimer { public: @@ -56,9 +57,14 @@ public: */ static bool isChatMultiTab(); + // show/hide the translation check box + void showTranslationCheckbox(const BOOL visible = FALSE); + // LLFloater overrides /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); protected: @@ -83,8 +89,6 @@ protected: void buildParticipantList(); void onSortMenuItemClicked(const LLSD& userdata); - /*virtual*/ BOOL tick(); - bool mIsNearbyChat; bool mIsP2PChat; @@ -97,8 +101,24 @@ protected: LLButton* mCloseBtn; private: + /// Refreshes the floater at a constant rate. + virtual void refresh() = 0; + /// Update floater header and toolbar buttons when hosted/torn off state is toggled. void updateHeaderAndToolbar(); + + /** + * Adjusts chat history height to fit vertically with input chat field + * and avoid overlapping, since input chat field can be vertically expanded. + * Implementation: chat history bottom "follows" top+top_pad of input chat field + */ + void reshapeChatHistory(); + + LLChatHistory* mChatHistory; + LLChatEntry* mInputEditor; + int mInputEditorTopPad; // padding between input field and chat history + + LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called. }; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 7c6de01c96..9d3c0f98ce 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -44,7 +44,7 @@ #include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container #include "llinventoryfunctions.h" //#include "lllayoutstack.h" -#include "lllineeditor.h" +#include "llchatentry.h" #include "lllogchat.h" #include "llscreenchannel.h" #include "llsyswellwindow.h" @@ -106,39 +106,16 @@ void LLIMFloater::onFocusReceived() } // virtual -void LLIMFloater::onClose(bool app_quitting) +void LLIMFloater::refresh() { - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( - mSessionID); - - if (session == NULL) + if (mMeTyping) { - llwarns << "Empty session." << llendl; - return; - } - - bool is_call_with_chat = session->isGroupSessionType() - || session->isAdHocSessionType() || session->isP2PSessionType(); - - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); - - if (is_call_with_chat && voice_channel != NULL - && voice_channel->isActive()) - { - LLSD payload; - payload["session_id"] = mSessionID; - LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback); - return; + // Time out if user hasn't typed for a while. + if (mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS) + { + setTyping(false); + } } - - setTyping(false); - - // The source of much argument and design thrashing - // Should the window hide or the session close when the X is clicked? - // - // Last change: - // EXT-3516 X Button should end IM session, _ button should hide - gIMMgr->leaveSession(mSessionID); } /* static */ @@ -190,7 +167,9 @@ void LLIMFloater::sendMsg() { if (mInputEditor) { - LLWString text = mInputEditor->getConvertedText(); + LLWString text = mInputEditor->getWText(); + LLWStringUtil::trim(text); + LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. if(!text.empty()) { // Truncate and convert to UTF8 for transport @@ -221,6 +200,7 @@ void LLIMFloater::sendMsg() LLIMFloater::~LLIMFloater() { + mParticipantsListRefreshConnection.disconnect(); mVoiceChannelStateChangeConnection.disconnect(); if(LLVoiceClient::instanceExists()) { @@ -258,6 +238,8 @@ void LLIMFloater::initIMFloater() boundVoiceChannel(); + mTypingStart = LLTrans::getString("IM_typing_start_string"); + // Show control panel in torn off floaters only. mParticipantListPanel->setVisible(!getHost() && gSavedSettings.getBOOL("IMShowControlPanel")); @@ -279,6 +261,20 @@ void LLIMFloater::initIMFloater() { std::string session_name(LLIMModel::instance().getName(mSessionID)); updateSessionName(session_name, session_name); + + // For ad hoc conferences we should update the title with participants names. + if ((IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID)) + || mDialog == IM_SESSION_CONFERENCE_START) + { + if (mParticipantsListRefreshConnection.connected()) + { + mParticipantsListRefreshConnection.disconnect(); + } + + LLAvatarList* avatar_list = getChild<LLAvatarList>("speakers_list"); + mParticipantsListRefreshConnection = avatar_list->setRefreshCompleteCallback( + boost::bind(&LLIMFloater::onParticipantsListChanged, this, _1)); + } } } @@ -287,30 +283,25 @@ BOOL LLIMFloater::postBuild() { LLIMConversation::postBuild(); - mInputEditor = getChild<LLLineEditor>("chat_editor"); + mInputEditor = getChild<LLChatEntry>("chat_editor"); mInputEditor->setMaxTextLength(1023); // enable line history support for instant message bar - mInputEditor->setEnableLineHistory(TRUE); LLFontGL* font = LLViewerChat::getChatFont(); mInputEditor->setFont(font); mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this) ); - mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); + mInputEditor->setKeystrokeCallback( boost::bind(onInputEditorKeystroke, _1, this) ); mInputEditor->setCommitOnFocusLost( FALSE ); - mInputEditor->setRevertOnEsc( FALSE ); - mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); mInputEditor->setPassDelete( TRUE ); - childSetCommitCallback("chat_editor", onSendMsg, this); + mInputEditor->setCommitCallback(boost::bind(onSendMsg, _1, this)); mChatHistory = getChild<LLChatHistory>("chat_history"); setDocked(true); - mTypingStart = LLTrans::getString("IM_typing_start_string"); - LLButton* add_btn = getChild<LLButton>("add_btn"); // Allow to add chat participants depending on the session type @@ -377,7 +368,9 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids) for (uuid_vec_t::const_iterator id = uuids.begin(); id != uuids.end(); ++id) { - if (*id == mOtherParticipantUUID) + // Skip this check for ad hoc conferences, + // conference participants should be listed in mSession->mInitialTargetIDs. + if (mIsP2PChat && *id == mOtherParticipantUUID) { return false; } @@ -447,11 +440,6 @@ void LLIMFloater::onCallButtonClicked() } } -/*void LLIMFloater::onOpenVoiceControlsClicked() -{ - LLFloaterReg::showInstance("voice_controls"); -}*/ - void LLIMFloater::onChange(EStatusType status, const std::string &channelURI, bool proximal) { if(status != STATUS_JOINING && status != STATUS_LEFT_CHANNEL) @@ -484,25 +472,59 @@ void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id, mTypingStart.setArg("[NAME]", ui_title); } -// virtual -BOOL LLIMFloater::tick() +void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl) { - // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater - // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy(). - if (isDead()) return false; + LLAvatarList* avatar_list = dynamic_cast<LLAvatarList*>(ctrl); + if (!avatar_list) + { + return; + } - BOOL parents_retcode = LLIMConversation::tick(); + bool all_names_resolved = true; + std::vector<LLSD> participants_uuids; - if ( mMeTyping ) + avatar_list->getValues(participants_uuids); + + // Check whether we have all participants names in LLAvatarNameCache + for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it) { - // Time out if user hasn't typed for a while. - if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS ) + const LLUUID& id = it->asUUID(); + LLAvatarName av_name; + if (!LLAvatarNameCache::get(id, &av_name)) { - setTyping(false); + all_names_resolved = false; + + // If a name is not found in cache, request it and continue the process recursively + // until all ids are resolved into names. + LLAvatarNameCache::get(id, + boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list)); + break; } } - return parents_retcode; + if (all_names_resolved) + { + std::vector<LLAvatarName> avatar_names; + std::vector<LLSD>::const_iterator it = participants_uuids.begin(); + for (; it != participants_uuids.end(); ++it) + { + const LLUUID& id = it->asUUID(); + LLAvatarName av_name; + if (LLAvatarNameCache::get(id, &av_name)) + { + avatar_names.push_back(av_name); + } + } + + // We should check whether the vector is not empty to pass the assertion + // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString. + if (!avatar_names.empty()) + { + std::string ui_title; + LLAvatarActions::buildResidentsString(avatar_names, ui_title); + updateSessionName(ui_title, ui_title); + } + } } //static @@ -528,8 +550,10 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id) } } + // Test the existence of the floater before we try to create it bool exist = findInstance(session_id); + // Get the floater: this will create the instance if it didn't exist LLIMFloater* floater = getInstance(session_id); if (!floater) return NULL; @@ -538,18 +562,21 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id) { LLIMFloaterContainer* floater_container = LLIMFloaterContainer::getInstance(); - // do not add existed floaters to avoid adding torn off instances + // Do not add again existing floaters if (!exist) { // LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; // TODO: mantipov: use LLTabContainer::RIGHT_OF_CURRENT if it exists LLTabContainer::eInsertionPoint i_pt = LLTabContainer::END; - if (floater_container) { floater_container->addFloater(floater, TRUE, i_pt); } } + + // Add a conversation list item in the left pane: nothing will be done if already in there + // but relevant clean up will be done to ensure consistency of the conversation list + floater_container->addConversationListItem(floater->getTitle(), session_id, floater); floater->openFloater(floater->getKey()); } @@ -599,6 +626,44 @@ LLIMFloater* LLIMFloater::getInstance(const LLUUID& session_id) return conversation; } +void LLIMFloater::onClose(bool app_quitting) +{ + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( + mSessionID); + + if (session == NULL) + { + llwarns << "Empty session." << llendl; + return; + } + + bool is_call_with_chat = session->isGroupSessionType() + || session->isAdHocSessionType() || session->isP2PSessionType(); + + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); + + if (is_call_with_chat && voice_channel != NULL + && voice_channel->isActive()) + { + LLSD payload; + payload["session_id"] = mSessionID; + LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback); + return; + } + + setTyping(false); + + // The source of much argument and design thrashing + // Should the window hide or the session close when the X is clicked? + // + // Last change: + // EXT-3516 X Button should end IM session, _ button should hide + gIMMgr->leaveSession(mSessionID); + + // Clean up the conversation *after* the session has been ended + LLIMConversation::onClose(app_quitting); +} + void LLIMFloater::setDocked(bool docked, bool pop_on_undock) { // update notification channel state @@ -726,8 +791,6 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id) { initIMSession(im_session_id); - boundVoiceChannel(); - buildParticipantList(); } @@ -877,7 +940,7 @@ void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userd } // static -void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata) +void LLIMFloater::onInputEditorKeystroke(LLTextEditor* caller, void* userdata) { LLIMFloater* self = (LLIMFloater*) userdata; std::string text = self->mInputEditor->getText(); @@ -1013,6 +1076,12 @@ BOOL LLIMFloater::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, *accept = ACCEPT_NO; } } + else if (mDialog == IM_NOTHING_SPECIAL) + { + LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionID, drop, + cargo_type, cargo_data, accept); + } + return TRUE; } @@ -1074,7 +1143,7 @@ private: BOOL LLIMFloater::inviteToSession(const uuid_vec_t& ids) { LLViewerRegion* region = gAgent.getRegion(); - bool is_region_exist = !!region; + bool is_region_exist = region != NULL; if (is_region_exist) { diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index d74b13b88d..23f9e75e21 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -37,7 +37,9 @@ class LLAvatarName; class LLButton; -class LLLineEditor; +class LLChatEntry; +class LLTextEditor; +class LLPanelChatControlPanel; class LLChatHistory; class LLInventoryItem; class LLInventoryCategory; @@ -64,15 +66,11 @@ public: /*virtual*/ void setVisible(BOOL visible); /*virtual*/ BOOL getVisible(); // Check typing timeout timer. - /*virtual*/ BOOL tick(); static LLIMFloater* findInstance(const LLUUID& session_id); static LLIMFloater* getInstance(const LLUUID& session_id); static void addToHost(const LLUUID& session_id); - static void* createPanelGroupControl(void* userdata); - static void* createPanelAdHocControl(void* userdata); - // LLFloater overrides /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); @@ -132,12 +130,18 @@ private: /* virtual */ void onFocusLost(); /* virtual */ void onFocusReceived(); + /*virtual*/ void refresh(); + // Update the window title, input field help text, etc. void updateSessionName(const std::string& ui_title, const std::string& ui_label); // For display name lookups for IM window titles void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + /// Updates the list of ad hoc conference participants + /// in an IM floater title. + void onParticipantsListChanged(LLUICtrl* ctrl); + bool dropPerson(LLUUID* person_id, bool drop); BOOL isInviteAllowed() const; @@ -145,7 +149,7 @@ private: void appendMessage(const LLChat& chat, const LLSD &args = 0); static void onInputEditorFocusReceived( LLFocusableElement* caller,void* userdata ); static void onInputEditorFocusLost(LLFocusableElement* caller, void* userdata); - static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); + static void onInputEditorKeystroke(LLTextEditor* caller, void* userdata); void setTyping(bool typing); void onAddButtonClicked(); void onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names); @@ -176,7 +180,7 @@ private: EInstantMessage mDialog; LLUUID mOtherParticipantUUID; - LLLineEditor* mInputEditor; + LLChatEntry* mInputEditor; bool mPositioned; std::string mSavedTitle; @@ -194,6 +198,8 @@ private: // connection to voice channel state change signal boost::signals2::connection mVoiceChannelStateChangeConnection; + + boost::signals2::connection mParticipantsListRefreshConnection; }; #endif // LL_IMFLOATER_H diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 71b69dfbc8..261b5f33a2 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" +#include "llimfloater.h" #include "llimfloatercontainer.h" #include "llfloaterreg.h" @@ -49,6 +50,9 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) : LLMultiFloater(seed) ,mExpandCollapseBtn(NULL) { + // Firstly add our self to IMSession observers, so we catch session events + LLIMMgr::getInstance()->addSessionObserver(this); + mAutoResize = FALSE; LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this); } @@ -60,8 +64,18 @@ LLIMFloaterContainer::~LLIMFloaterContainer() gSavedPerAccountSettings.setBOOL("ConversationsListPaneCollapsed", mConversationsPane->isCollapsed()); gSavedPerAccountSettings.setBOOL("ConversationsMessagePaneCollapsed", mMessagesPane->isCollapsed()); + + if (!LLSingleton<LLIMMgr>::destroyed()) + { + LLIMMgr::getInstance()->removeSessionObserver(this); + } } +void LLIMFloaterContainer::sessionVoiceOrIMStarted(const LLUUID& session_id) +{ + LLIMFloater::show(session_id); +}; + BOOL LLIMFloaterContainer::postBuild() { mNewMessageConnection = LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1)); @@ -73,6 +87,8 @@ BOOL LLIMFloaterContainer::postBuild() mConversationsStack = getChild<LLLayoutStack>("conversations_stack"); mConversationsPane = getChild<LLLayoutPanel>("conversations_layout_panel"); mMessagesPane = getChild<LLLayoutPanel>("messages_layout_panel"); + + mConversationsListPanel = getChild<LLPanel>("conversations_list_panel"); mExpandCollapseBtn = getChild<LLButton>("expand_collapse_btn"); mExpandCollapseBtn->setClickedCallback(boost::bind(&LLIMFloaterContainer::onExpandCollapseButtonClicked, this)); @@ -88,16 +104,6 @@ BOOL LLIMFloaterContainer::postBuild() void LLIMFloaterContainer::onOpen(const LLSD& key) { LLMultiFloater::onOpen(key); -/* - if (key.isDefined()) - { - LLIMFloater* im_floater = LLIMFloater::findInstance(key.asUUID()); - if (im_floater) - { - im_floater->openFloater(); - } - } -*/ } // virtual @@ -113,17 +119,24 @@ void LLIMFloaterContainer::addFloater(LLFloater* floaterp, openFloater(floaterp->getKey()); return; } + + // Make sure the message panel is open when adding a floater or it stays mysteriously hidden + collapseMessagesPane(false); + // Add the floater LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point); + LLUUID session_id = floaterp->getKey(); + + // Add a conversation list item in the left pane + addConversationListItem(floaterp->getTitle(), session_id, floaterp); + LLView* floater_contents = floaterp->getChild<LLView>("contents_view"); // we don't show the header when the floater is hosted, // so reshape floater contents to occupy the header space floater_contents->setShape(floaterp->getRect()); - LLUUID session_id = floaterp->getKey(); - LLIconCtrl* icon = 0; if(gAgent.isInGroup(session_id, TRUE)) @@ -254,6 +267,58 @@ void LLIMFloaterContainer::setMinimized(BOOL b) } } +void LLIMFloaterContainer::draw() +{ + if (mTabContainer->getTabCount() == 0) + { + // Do not close the container when every conversation is torn off because the user + // still needs the conversation list. Simply collapse the message pane in that case. + collapseMessagesPane(true); + } + LLFloater::draw(); +} + +void LLIMFloaterContainer::tabClose() +{ + if (mTabContainer->getTabCount() == 0) + { + // Do not close the container when every conversation is torn off because the user + // still needs the conversation list. Simply collapse the message pane in that case. + collapseMessagesPane(true); + } +} + +void LLIMFloaterContainer::setVisible(BOOL visible) +{ + if (visible) + { + // Make sure we have the Nearby Chat present when showing the conversation container + LLUUID nearbychat_uuid = LLUUID::null; // Hacky but true: the session id for nearby chat is always null + LLFloater* floaterp = findConversationItem(nearbychat_uuid); + if (floaterp == NULL) + { + // If not found, force the creation of the nearby chat conversation panel + // *TODO: find a way to move this to XML as a default panel or something like that + LLSD name("chat_bar"); + LLFloaterReg::toggleInstanceOrBringToFront(name); + } + } + + // 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. + conversations_items_map::iterator item_it = mConversationsItems.begin(); + for (;item_it != mConversationsItems.end(); ++item_it) + { + LLConversationItem* item = item_it->second; + item->setVisibleIfDetached(visible); + } + + // Now, do the normal multifloater show/hide + LLMultiFloater::setVisible(visible); + +} + void LLIMFloaterContainer::collapseMessagesPane(bool collapse) { if (mMessagesPane->isCollapsed() == collapse) @@ -339,4 +404,178 @@ void LLIMFloaterContainer::onAvatarPicked(const uuid_vec_t& ids) } } +// CHUI-137 : Temporary implementation of conversations list +void LLIMFloaterContainer::addConversationListItem(std::string name, const LLUUID& uuid, LLFloater* floaterp) +{ + // Check if the item is not already in the list, exit if it is and has the same name and uuid (nothing to do) + // Note: this happens often, when reattaching a torn off conversation for instance + conversations_items_map::iterator item_it = mConversationsItems.find(floaterp); + if (item_it != mConversationsItems.end()) + { + LLConversationItem* item = item_it->second; + // Check if the item has changed + if (item->hasSameValues(name,uuid)) + { + // If it hasn't changed, nothing to do -> exit + return; + } + } + + // Remove the conversation item that might exist already: it'll be recreated anew further down anyway + // and nothing wrong will happen removing it if it doesn't exist + removeConversationListItem(floaterp,false); + + // Create a conversation item + LLConversationItem* item = new LLConversationItem(name, uuid, floaterp, this); + mConversationsItems[floaterp] = item; + + // Create a widget from it + LLFolderViewItem* widget = createConversationItemWidget(item); + mConversationsWidgets[floaterp] = widget; + + // Add it to the UI + widget->setVisible(TRUE); + mConversationsListPanel->addChild(widget); + LLRect panel_rect = mConversationsListPanel->getRect(); + S32 item_height = 16; + S32 index = mConversationsWidgets.size() - 1; + widget->setRect(LLRect(0, + panel_rect.getHeight() - item_height*index, + panel_rect.getWidth(), + panel_rect.getHeight() - item_height*(index+1))); + return; +} + +void LLIMFloaterContainer::removeConversationListItem(LLFloater* floaterp, bool change_focus) +{ + // Delete the widget and the associated conversation item + // Note : since the mConversationsItems is also the listener to the widget, deleting + // the widget will also delete its listener + conversations_widgets_map::iterator widget_it = mConversationsWidgets.find(floaterp); + if (widget_it != mConversationsWidgets.end()) + { + LLFolderViewItem* widget = widget_it->second; + delete widget; + } + + // Suppress the conversation items and widgets from their respective maps + mConversationsItems.erase(floaterp); + mConversationsWidgets.erase(floaterp); + + // Reposition the leftover conversation items + LLRect panel_rect = mConversationsListPanel->getRect(); + S32 item_height = 16; + int index = 0; + for (widget_it = mConversationsWidgets.begin(); widget_it != mConversationsWidgets.end(); ++widget_it, ++index) + { + LLFolderViewItem* widget = widget_it->second; + widget->setRect(LLRect(0, + panel_rect.getHeight() - item_height*index, + panel_rect.getWidth(), + panel_rect.getHeight() - item_height*(index+1))); + } + + // Don't let the focus fall IW, select and refocus on the first conversation in the list + if (change_focus) + { + setFocus(TRUE); + conversations_items_map::iterator item_it = mConversationsItems.begin(); + if (item_it != mConversationsItems.end()) + { + LLConversationItem* item = item_it->second; + item->selectItem(); + } + } + return; +} + +LLFloater* LLIMFloaterContainer::findConversationItem(LLUUID& uuid) +{ + LLFloater* floaterp = NULL; + for (conversations_items_map::iterator item_it = mConversationsItems.begin(); item_it != mConversationsItems.end(); ++item_it) + { + LLConversationItem* item = item_it->second; + if (item->hasSameValue(uuid)) + { + floaterp = item_it->first; + break; + } + } + return floaterp; +} + +LLFolderViewItem* LLIMFloaterContainer::createConversationItemWidget(LLConversationItem* item) +{ + LLFolderViewItem::Params params; + + params.name = item->getDisplayName(); + //params.icon = bridge->getIcon(); + //params.icon_open = bridge->getOpenIcon(); + //params.creation_date = bridge->getCreationDate(); + //params.root = mFolderRoot; + params.listener = item; + params.rect = LLRect (0, 0, 0, 0); + params.tool_tip = params.name; + + return LLUICtrlFactory::create<LLFolderViewItem>(params); +} + +// Conversation items +LLConversationItem::LLConversationItem(std::string name, const LLUUID& uuid, LLFloater* floaterp, LLIMFloaterContainer* containerp) : + mName(name), + mUUID(uuid), + mFloater(floaterp), + mContainer(containerp) +{ + // Hack: the nearby chat has no name so we catch that case and impose one + // Of course, we won't be doing this in the final code + if (name == "") + mName = "Nearby Chat"; +} + +// Virtual action callbacks +void LLConversationItem::selectItem(void) +{ + LLMultiFloater* host_floater = mFloater->getHost(); + if (host_floater == mContainer) + { + // Always expand the message pane if the panel is hosted by the container + mContainer->collapseMessagesPane(false); + // Switch to the conversation floater that is being selected + mContainer->selectFloater(mFloater); + } + // Set the focus on the selected floater + mFloater->setFocus(TRUE); +} + +void LLConversationItem::setVisibleIfDetached(BOOL visible) +{ + // Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized + // Note: minimized dockable floaters are brought to front hence unminimized when made visible and we don't want that here + if (!mFloater->getHost() && !mFloater->isMinimized()) + { + mFloater->setVisible(visible); + } +} + +void LLConversationItem::performAction(LLInventoryModel* model, std::string action) +{ +} + +void LLConversationItem::openItem( void ) +{ +} + +void LLConversationItem::closeItem( void ) +{ +} + +void LLConversationItem::previewItem( void ) +{ +} + +void LLConversationItem::showProperties(void) +{ +} + // EOF diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index 7b395fb18f..2bbd371e8f 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -30,17 +30,102 @@ #include <map> #include <vector> +#include "llimview.h" #include "llfloater.h" #include "llmultifloater.h" #include "llavatarpropertiesprocessor.h" #include "llgroupmgr.h" +#include "llfolderviewitem.h" +#include "llfoldervieweventlistener.h" + class LLButton; class LLLayoutPanel; class LLLayoutStack; class LLTabContainer; +class LLIMFloaterContainer; + +// CHUI-137 : Temporary implementation of conversations list +class LLConversationItem; + +typedef std::map<LLFloater*, LLConversationItem*> conversations_items_map; +typedef std::map<LLFloater*, LLFolderViewItem*> conversations_widgets_map; -class LLIMFloaterContainer : public LLMultiFloater +// Conversation items: we hold a list of those and create an LLFolderViewItem widget for each +// that we tuck into the mConversationsListPanel. +class LLConversationItem : public LLFolderViewEventListener +{ +public: + LLConversationItem(std::string name, const LLUUID& uuid, LLFloater* floaterp, LLIMFloaterContainer* containerp); + virtual ~LLConversationItem() {} + + // Stub those things we won't really be using in this conversation context + virtual const std::string& getName() const { return mName; } + virtual const std::string& getDisplayName() const { return mName; } + virtual const LLUUID& getUUID() const { return mUUID; } + virtual time_t getCreationDate() const { return 0; } + virtual PermissionMask getPermissionMask() const { return PERM_ALL; } + virtual LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; } + virtual LLPointer<LLUIImage> getIcon() const { return NULL; } + virtual LLPointer<LLUIImage> getOpenIcon() const { return getIcon(); } + virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } + virtual std::string getLabelSuffix() const { return LLStringUtil::null; } + virtual BOOL isItemRenameable() const { return FALSE; } + virtual BOOL renameItem(const std::string& new_name) { return FALSE; } + virtual BOOL isItemMovable( void ) const { return FALSE; } + virtual BOOL isItemRemovable( void ) const { return FALSE; } + virtual BOOL isItemInTrash( void) const { return FALSE; } + virtual BOOL removeItem() { return FALSE; } + virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) { } + virtual void move( LLFolderViewEventListener* parent_listener ) { } + virtual BOOL isItemCopyable() const { return FALSE; } + virtual BOOL copyToClipboard() const { return FALSE; } + virtual BOOL cutToClipboard() const { return FALSE; } + virtual BOOL isClipboardPasteable() const { return FALSE; } + virtual void pasteFromClipboard() { } + virtual void pasteLinkFromClipboard() { } + virtual void buildContextMenu(LLMenuGL& menu, U32 flags) { } + virtual BOOL isUpToDate() const { return TRUE; } + virtual BOOL hasChildren() const { return FALSE; } + virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } + virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } + + // The action callbacks + virtual void performAction(LLInventoryModel* model, std::string action); + virtual void openItem( void ); + virtual void closeItem( void ); + virtual void previewItem( void ); + virtual void selectItem(void); + virtual void showProperties(void); + + void setVisibleIfDetached(BOOL visible); + + // This method should be called when a drag begins. + // Returns TRUE if the drag can begin, FALSE otherwise. + virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) 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 + // requested. + // Returns TRUE if a drop is possible/happened, FALSE otherwise. + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + std::string& tooltip_msg) { return FALSE; } + + bool hasSameValues(std::string name, const LLUUID& uuid) { return ((name == mName) && (uuid == mUUID)); } + bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); } +private: + std::string mName; + const LLUUID mUUID; + LLFloater* mFloater; + LLIMFloaterContainer* mContainer; +}; +// CHUI-137 : End + +class LLIMFloaterContainer + : public LLMultiFloater + , public LLIMSessionObserver { public: LLIMFloaterContainer(const LLSD& seed); @@ -48,6 +133,8 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void draw(); + /*virtual*/ void setVisible(BOOL visible); void onCloseFloater(LLUUID& id); /*virtual*/ void addFloater(LLFloater* floaterp, @@ -55,6 +142,8 @@ public: LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); /*virtual*/ void removeFloater(LLFloater* floaterp); + /*virtual*/ void tabClose(); + static LLFloater* getCurrentVoiceFloater(); static LLIMFloaterContainer* findInstance(); @@ -64,6 +153,13 @@ public: virtual void setMinimized(BOOL b); void collapseMessagesPane(bool collapse); + + + // LLIMSessionObserver observe triggers + /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}; + /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id); + /*virtual*/ void sessionRemoved(const LLUUID& session_id) {}; + /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {}; private: typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t; @@ -87,6 +183,18 @@ private: LLLayoutPanel* mMessagesPane; LLLayoutPanel* mConversationsPane; LLLayoutStack* mConversationsStack; + + // CHUI-137 : Temporary implementation of conversations list +public: + void removeConversationListItem(LLFloater* floaterp, bool change_focus = true); + void addConversationListItem(std::string name, const LLUUID& uuid, LLFloater* floaterp); + LLFloater* findConversationItem(LLUUID& uuid); +private: + LLFolderViewItem* createConversationItemWidget(LLConversationItem* item); + // Conversation list data + LLPanel* mConversationsListPanel; // This is the widget we add items to (i.e. clickable title for each conversation) + conversations_items_map mConversationsItems; + conversations_widgets_map mConversationsWidgets; }; #endif // LL_LLIMFLOATERCONTAINER_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0d2b1f06b5..79018ec366 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -2582,7 +2582,9 @@ LLUUID LLIMMgr::addSession( { LLDynamicArray<LLUUID> ids; ids.put(other_participant_id); - return addSession(name, dialog, other_participant_id, ids, voice); + LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice); + notifyObserverSessionVoiceOrIMStarted(session_id); + return session_id; } // Adds a session using the given session_id. If the session already exists @@ -2610,6 +2612,7 @@ LLUUID LLIMMgr::addSession( if (floater_id.notNull()) { LLIMFloater* im_floater = LLIMFloater::findInstance(floater_id); + if (im_floater && im_floater->getStartConferenceInSameFloater()) { // The IM floater should be initialized with a new session_id @@ -2936,6 +2939,14 @@ void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::st } } +void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionVoiceOrIMStarted(session_id); + } +} + void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) { for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 58a2ac5162..80bf315aa8 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -298,6 +298,7 @@ class LLIMSessionObserver public: virtual ~LLIMSessionObserver() {} virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0; + virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0; virtual void sessionRemoved(const LLUUID& session_id) = 0; virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0; }; @@ -462,6 +463,7 @@ private: static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group); void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id); void notifyObserverSessionRemoved(const LLUUID& session_id); void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index cd181ce865..a81d6b4025 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -30,6 +30,7 @@ #include "lliconctrl.h" #include "llappviewer.h" +#include "llchatentry.h" #include "llfloaterreg.h" #include "lltrans.h" #include "llimfloatercontainer.h" @@ -130,6 +131,8 @@ LLNearbyChat::LLNearbyChat(const LLSD& key) mSpeakerMgr(NULL), mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT) { + setIsChrome(TRUE); + mKey = LLSD(); mIsNearbyChat = true; mSpeakerMgr = LLLocalSpeakerMgr::getInstance(); } @@ -137,19 +140,14 @@ LLNearbyChat::LLNearbyChat(const LLSD& key) //virtual BOOL LLNearbyChat::postBuild() { - mChatBox = getChild<LLLineEditor>("chat_editor"); + mChatBox = getChild<LLChatEntry>("chat_editor"); mChatBox->setCommitCallback(boost::bind(&LLNearbyChat::onChatBoxCommit, this)); - mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this); + mChatBox->setKeystrokeCallback(boost::bind(&onChatBoxKeystroke, _1, this)); mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this)); mChatBox->setFocusReceivedCallback(boost::bind(&LLNearbyChat::onChatBoxFocusReceived, this)); - mChatBox->setIgnoreArrowKeys( FALSE ); mChatBox->setCommitOnFocusLost( FALSE ); - mChatBox->setRevertOnEsc( FALSE ); - mChatBox->setIgnoreTab(TRUE); mChatBox->setPassDelete(TRUE); - mChatBox->setReplaceNewlinesWithSpaces(FALSE); - mChatBox->setEnableLineHistory(TRUE); mChatBox->setFont(LLViewerChat::getChatFont()); // mOutputMonitor = getChild<LLOutputMonitorCtrl>("chat_zone_indicator"); @@ -189,6 +187,21 @@ BOOL LLNearbyChat::postBuild() return LLIMConversation::postBuild(); } +// virtual +void LLNearbyChat::refresh() +{ + displaySpeakingIndicator(); + updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState()); + + // *HACK: Update transparency type depending on whether our children have focus. + // This is needed because this floater is chrome and thus cannot accept focus, so + // the transparency type setting code from LLFloater::setFocus() isn't reached. + if (getTransparencyType() != TT_DEFAULT) + { + setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE); + } +} + void LLNearbyChat::onNearbySpeakers() { LLSD param; @@ -382,11 +395,14 @@ LLNearbyChat* LLNearbyChat::getInstance() return LLFloaterReg::getTypedInstance<LLNearbyChat>("chat_bar"); } -//static -//LLNearbyChat* LLNearbyChat::findInstance() -//{ -// return LLFloaterReg::findTypedInstance<LLNearbyChat>("chat_bar"); -//} +void LLNearbyChat::show() +{ + if (isChatMultiTab()) + { + openFloater(getKey()); + } + setVisible(TRUE); +} void LLNearbyChat::showHistory() { @@ -397,33 +413,6 @@ void LLNearbyChat::showHistory() storeRectControl(); } -void LLNearbyChat::showTranslationCheckbox(BOOL show) -{ - getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(show); -} - -BOOL LLNearbyChat::tick() -{ - // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater - // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy(). - if (isDead()) return false; - - BOOL parents_retcode = LLIMConversation::tick(); - - displaySpeakingIndicator(); - updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState()); - - // *HACK: Update transparency type depending on whether our children have focus. - // This is needed because this floater is chrome and thus cannot accept focus, so - // the transparency type setting code from LLFloater::setFocus() isn't reached. - if (getTransparencyType() != TT_DEFAULT) - { - setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE); - } - - return parents_retcode; -} - std::string LLNearbyChat::getCurrentChat() { return mChatBox ? mChatBox->getText() : LLStringUtil::null; @@ -469,7 +458,7 @@ BOOL LLNearbyChat::matchChatTypeTrigger(const std::string& in_str, std::string* return string_was_found; } -void LLNearbyChat::onChatBoxKeystroke(LLLineEditor* caller, void* userdata) +void LLNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userdata) { LLFirstUse::otherAvatarChatFirst(false); @@ -523,17 +512,16 @@ void LLNearbyChat::onChatBoxKeystroke(LLLineEditor* caller, void* userdata) { std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size()); self->mChatBox->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part - S32 outlength = self->mChatBox->getLength(); // in characters // Select to end of line, starting from the character // after the last one the user typed. - self->mChatBox->setSelection(length, outlength); + self->mChatBox->selectNext(rest_of_match, false); } else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str)) { std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size()); self->mChatBox->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part - self->mChatBox->setCursorToEnd(); + self->mChatBox->endOfDoc(); } //llinfos << "GESTUREDEBUG " << trigger @@ -591,11 +579,11 @@ void LLNearbyChat::sendChat( EChatType type ) { if (mChatBox) { - LLWString text = mChatBox->getConvertedText(); + LLWString text = mChatBox->getWText(); + LLWStringUtil::trim(text); + LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. if (!text.empty()) { - // store sent line in history, duplicates will get filtered - mChatBox->updateHistory(); // Check if this is destined for another channel S32 channel = 0; stripChannelNumber(text, &channel); @@ -794,6 +782,7 @@ void LLNearbyChat::startChat(const char* line) if (cb ) { + cb->show(); cb->setVisible(TRUE); cb->setFocus(TRUE); cb->mChatBox->setFocus(TRUE); @@ -804,7 +793,7 @@ void LLNearbyChat::startChat(const char* line) cb->mChatBox->setText(line_string); } - cb->mChatBox->setCursorToEnd(); + cb->mChatBox->endOfDoc(); } } diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index bc0e54de15..61404df942 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -65,15 +65,14 @@ public: static LLNearbyChat* getInstance(); void addToHost(); + void show(); /** @param archive true - to save a message to the chat history log */ void addMessage (const LLChat& message,bool archive = true, const LLSD &args = LLSD()); void onNearbyChatContextMenuItemClicked(const LLSD& userdata); bool onNearbyChatCheckContextMenuItem(const LLSD& userdata); - LLLineEditor* getChatBox() { return mChatBox; } - - //virtual void draw(); + LLChatEntry* getChatBox() { return mChatBox; } std::string getCurrentChat(); @@ -87,11 +86,10 @@ public: static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate); void showHistory(); - void showTranslationCheckbox(BOOL show); protected: static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str); - static void onChatBoxKeystroke(LLLineEditor* caller, void* userdata); + static void onChatBoxKeystroke(LLTextEditor* caller, void* userdata); static void onChatBoxFocusLost(LLFocusableElement* caller, void* userdata); void onChatBoxFocusReceived(); @@ -114,14 +112,12 @@ protected: // Which non-zero channel did we last chat on? static S32 sLastSpecialChatChannel; - LLLineEditor* mChatBox; + LLChatEntry* mChatBox; LLOutputMonitorCtrl* mOutputMonitor; LLLocalSpeakerMgr* mSpeakerMgr; S32 mExpandedHeight; - /*virtual*/ BOOL tick(); - private: void getAllowedRect (LLRect& rect); @@ -129,6 +125,8 @@ private: void appendMessage(const LLChat& chat, const LLSD &args = 0); void onNearbySpeakers (); + /*virtual*/ void refresh(); + LLHandle<LLView> mPopupMenuHandle; std::vector<LLChat> mMessageArchive; LLChatHistory* mChatHistory; diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index e91a3fc334..c97e3585e1 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -555,7 +555,6 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, // Send event on to LLEventStream sChatWatcher->post(chat); - if( nearby_chat->isInVisibleChain() || ( chat_msg.mSourceType == CHAT_SOURCE_AGENT && gSavedSettings.getBOOL("UseChatBubbles") ) diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp index d2dff63948..35cda14f8d 100644 --- a/indra/newview/llpanelblockedlist.cpp +++ b/indra/newview/llpanelblockedlist.cpp @@ -30,15 +30,23 @@ // library include #include "llavatarname.h" +#include "llfiltereditor.h" #include "llfloater.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" #include "llscrolllistctrl.h" +#include "llmenubutton.h" // project include +#include "llavatarlistitem.h" +#include "llblocklist.h" +#include "llblockedlistitem.h" #include "llfloateravatarpicker.h" #include "llfloatersidepanelcontainer.h" +#include "llinventorylistitem.h" +#include "llinventorymodel.h" #include "llsidetraypanelcontainer.h" +#include "llviewercontrol.h" static LLRegisterPanelClassWrapper<LLPanelBlockedList> t_panel_blocked_list("panel_block_list_sidetray"); @@ -54,24 +62,35 @@ const std::string BLOCKED_PARAM_NAME = "blocked_to_select"; LLPanelBlockedList::LLPanelBlockedList() : LLPanel() { - mCommitCallbackRegistrar.add("Block.ClickPick", boost::bind(&LLPanelBlockedList::onPickBtnClick, this)); - mCommitCallbackRegistrar.add("Block.ClickBlockByName", boost::bind(&LLPanelBlockedList::onBlockByNameClick, this)); - mCommitCallbackRegistrar.add("Block.ClickRemove", boost::bind(&LLPanelBlockedList::onRemoveBtnClick, this)); -} - -LLPanelBlockedList::~LLPanelBlockedList() -{ - LLMuteList::getInstance()->removeObserver(this); + mCommitCallbackRegistrar.add("Block.Action", boost::bind(&LLPanelBlockedList::onCustomAction, this, _2)); + mEnableCallbackRegistrar.add("Block.Check", boost::bind(&LLPanelBlockedList::isActionChecked, this, _2)); } BOOL LLPanelBlockedList::postBuild() { - mBlockedList = getChild<LLScrollListCtrl>("blocked"); + mBlockedList = getChild<LLBlockList>("blocked"); mBlockedList->setCommitOnSelectionChange(TRUE); - LLMuteList::getInstance()->addObserver(this); - - refreshBlockedList(); + switch (gSavedSettings.getU32("BlockPeopleSortOrder")) + { + case E_SORT_BY_NAME: + mBlockedList->sortByName(); + break; + + case E_SORT_BY_TYPE: + mBlockedList->sortByType(); + break; + } + + // Use the context menu of the Block list for the Block tab gear menu. + LLToggleableMenu* blocked_gear_menu = mBlockedList->getContextMenu(); + if (blocked_gear_menu) + { + getChild<LLMenuButton>("blocked_gear_btn")->setMenu(blocked_gear_menu, LLMenuButton::MP_BOTTOM_LEFT); + } + + getChild<LLButton>("unblock_btn")->setCommitCallback(boost::bind(&LLPanelBlockedList::unblockItem, this)); + getChild<LLFilterEditor>("blocked_filter_input")->setCommitCallback(boost::bind(&LLPanelBlockedList::onFilterEdit, this, _2)); return LLPanel::postBuild(); } @@ -92,7 +111,7 @@ void LLPanelBlockedList::onOpen(const LLSD& key) void LLPanelBlockedList::selectBlocked(const LLUUID& mute_id) { - mBlockedList->selectByID(mute_id); + mBlockedList->selectItemByUUID(mute_id); } void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect) @@ -105,55 +124,64 @@ void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect) ////////////////////////////////////////////////////////////////////////// // Private Section ////////////////////////////////////////////////////////////////////////// -void LLPanelBlockedList::refreshBlockedList() +void LLPanelBlockedList::updateButtons() { - mBlockedList->deleteAllItems(); + bool hasSelected = NULL != mBlockedList->getSelectedItem(); + getChildView("unblock_btn")->setEnabled(hasSelected); +} - std::vector<LLMute> mutes = LLMuteList::getInstance()->getMutes(); - std::vector<LLMute>::iterator it; - for (it = mutes.begin(); it != mutes.end(); ++it) +void LLPanelBlockedList::unblockItem() +{ + LLBlockedListItem* item = mBlockedList->getBlockedItem(); + if (item) { - LLScrollListItem::Params item_p; - item_p.enabled(TRUE); - item_p.value(it->mID); // link UUID of blocked item with ScrollListItem - item_p.columns.add().column("item_name").value(it->mName);//.type("text"); - item_p.columns.add().column("item_type").value(it->getDisplayType());//.type("text").width(111); - - mBlockedList->addRow(item_p, ADD_BOTTOM); + LLMute mute(item->getUUID(), item->getName()); + LLMuteList::instance().remove(mute); } } -void LLPanelBlockedList::updateButtons() +void LLPanelBlockedList::onCustomAction(const LLSD& userdata) { - bool hasSelected = NULL != mBlockedList->getFirstSelected(); - getChildView("Unblock")->setEnabled(hasSelected); + const std::string command_name = userdata.asString(); + + if ("block_obj_by_name" == command_name) + { + blockObjectByName(); + } + else if ("block_res_by_name" == command_name) + { + blockResidentByName(); + } + else if ("sort_by_name" == command_name) + { + mBlockedList->sortByName(); + gSavedSettings.setU32("BlockPeopleSortOrder", E_SORT_BY_NAME); + } + else if ("sort_by_type" == command_name) + { + mBlockedList->sortByType(); + gSavedSettings.setU32("BlockPeopleSortOrder", E_SORT_BY_TYPE); + } } -void LLPanelBlockedList::onRemoveBtnClick() +BOOL LLPanelBlockedList::isActionChecked(const LLSD& userdata) { - std::string name = mBlockedList->getSelectedItemLabel(); - LLUUID id = mBlockedList->getStringUUIDSelectedItem(); - LLMute mute(id, name); - - S32 last_selected = mBlockedList->getFirstSelectedIndex(); - if (LLMuteList::getInstance()->remove(mute)) + std::string item = userdata.asString(); + U32 sort_order = gSavedSettings.getU32("BlockPeopleSortOrder"); + + if ("sort_by_name" == item) + { + return E_SORT_BY_NAME == sort_order; + } + else if ("sort_by_type" == item) { - // Above removals may rebuild this dialog. - - if (last_selected == mBlockedList->getItemCount()) - { - // we were on the last item, so select the last item again - mBlockedList->selectNthItem(last_selected - 1); - } - else - { - // else select the item after the last item previously selected - mBlockedList->selectNthItem(last_selected); - } + return E_SORT_BY_TYPE == sort_order; } + + return false; } -void LLPanelBlockedList::onPickBtnClick() +void LLPanelBlockedList::blockResidentByName() { const BOOL allow_multiple = FALSE; const BOOL close_on_select = TRUE; @@ -164,11 +192,19 @@ void LLPanelBlockedList::onPickBtnClick() // addDependentFloater(picker); } -void LLPanelBlockedList::onBlockByNameClick() +void LLPanelBlockedList::blockObjectByName() { LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName); } +void LLPanelBlockedList::onFilterEdit(const std::string& search_string) +{ + std::string filter = search_string; + LLStringUtil::trimHead(filter); + + mBlockedList->setNameFilter(filter); +} + void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names) { if (names.empty() || ids.empty()) return; diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h index 97236ecdbf..332349dfc0 100644 --- a/indra/newview/llpanelblockedlist.h +++ b/indra/newview/llpanelblockedlist.h @@ -30,21 +30,15 @@ #include "llpanel.h" #include "llmutelist.h" #include "llfloater.h" -// #include <vector> -// class LLButton; -// class LLLineEditor; -// class LLMessageSystem; -// class LLUUID; class LLAvatarName; -class LLScrollListCtrl; +class LLBlockList; -class LLPanelBlockedList - : public LLPanel, public LLMuteListObserver +class LLPanelBlockedList : public LLPanel { public: LLPanelBlockedList(); - ~LLPanelBlockedList(); + ~LLPanelBlockedList(){}; virtual BOOL postBuild(); virtual void draw(); @@ -59,24 +53,31 @@ public: * If it is LLUUID::null, nothing will be selected. */ static void showPanelAndSelect(const LLUUID& idToSelect); - - // LLMuteListObserver callback interface implementation. - /* virtual */ void onChange() { refreshBlockedList();} private: - void refreshBlockedList(); + + typedef enum e_sort_oder{ + E_SORT_BY_NAME = 0, + E_SORT_BY_TYPE = 1, + } ESortOrder; + void updateButtons(); // UI callbacks - void onRemoveBtnClick(); - void onPickBtnClick(); - void onBlockByNameClick(); + void unblockItem(); + void blockResidentByName(); + void blockObjectByName(); + void onFilterEdit(const std::string& search_string); + + // List commnads + void onCustomAction(const LLSD& userdata); + BOOL isActionChecked(const LLSD& userdata); void callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names); static void callbackBlockByName(const std::string& text); private: - LLScrollListCtrl* mBlockedList; + LLBlockList* mBlockedList; }; //----------------------------------------------------------------------------- diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 280cc11179..854deb00d0 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -230,7 +230,7 @@ void LLPanelTopInfoBar::buildLocationString(std::string& loc_str, bool show_coor void LLPanelTopInfoBar::setParcelInfoText(const std::string& new_text) { LLRect old_rect = getRect(); - const LLFontGL* font = mParcelInfoText->getDefaultFont(); + const LLFontGL* font = mParcelInfoText->getFont(); S32 new_text_width = font->getWidth(new_text); mParcelInfoText->setText(new_text); diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 59d26edff2..47518a365f 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -475,6 +475,7 @@ void LLParticipantList::update() { mSpeakerMgr->update(true); + // Need to resort the participant list if it's in sort by recent speaker order. if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder() && !isHovered()) { // Resort avatar list diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index f497f546aa..8758c8c4e5 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -169,6 +169,7 @@ public: // LLIMSessionObserver observe triggers /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {}; /*virtual*/ void sessionRemoved(const LLUUID& session_id); /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 707d2d9765..ed350ea144 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -112,7 +112,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi style.font = date_font; pMessageText->appendText(timeStr + "\n", TRUE, style); - style.font = pMessageText->getDefaultFont(); + style.font = pMessageText->getFont(); pMessageText->appendText(message, TRUE, style); //attachment diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index e20d516392..09f8dcf83c 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -68,7 +68,7 @@ void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount) if (message->getVisible()) { S32 heightDelta = 0; - S32 maxTextHeight = message->getDefaultFont()->getLineHeight() * maxLineCount; + S32 maxTextHeight = message->getFont()->getLineHeight() * maxLineCount; LLRect messageRect = message->getRect(); S32 oldTextHeight = messageRect.getHeight(); diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp index 2529ec865a..45fbabad59 100644 --- a/indra/newview/lltoastscripttextbox.cpp +++ b/indra/newview/lltoastscripttextbox.cpp @@ -65,7 +65,7 @@ LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification pMessageText->clear(); LLStyle::Params style; - style.font = pMessageText->getDefaultFont(); + style.font = pMessageText->getFont(); pMessageText->appendText(message, TRUE, style); //submit button diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index df1962f5fe..bf12b08321 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -186,6 +186,7 @@ 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("chat_bar", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>); LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>); LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); @@ -208,7 +209,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>); LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); - LLFloaterReg::add("chat_bar", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>); LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 7f14e021fd..258bc5b698 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -56,6 +56,7 @@ // linden library includes #include "llaudioengine.h" // mute on minimize +#include "llchatentry.h" #include "indra_constants.h" #include "llassetstorage.h" #include "llerrorcontrol.h" @@ -2492,7 +2493,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) if (nearby_chat) { - LLLineEditor* chat_editor = nearby_chat->getChatBox(); + LLChatEntry* chat_editor = nearby_chat->getChatBox(); // arrow keys move avatar while chatting hack if (chat_editor && chat_editor->hasFocus()) @@ -2555,7 +2556,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) { - LLLineEditor* chat_editor = LLFloaterReg::getTypedInstance<LLNearbyChat>("chat_bar")->getChatBox(); + LLChatEntry* chat_editor = LLNearbyChat::getInstance()->getChatBox(); if (chat_editor) { // passing NULL here, character will be added later when it is handled by character handler. diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png Binary files differnew file mode 100755 index 0000000000..f024c733f3 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png Binary files differnew file mode 100755 index 0000000000..a19e720d42 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png Binary files differnew file mode 100755 index 0000000000..7f3f42639d --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png Binary files differnew file mode 100755 index 0000000000..2880eb766a --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png Binary files differnew file mode 100755 index 0000000000..25a939d7f5 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png Binary files differnew file mode 100755 index 0000000000..82baabde47 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png Binary files differnew file mode 100755 index 0000000000..7d64abb042 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png Binary files differnew file mode 100755 index 0000000000..f0da962c2d --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png Binary files differnew file mode 100755 index 0000000000..0db001dcdb --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png Binary files differnew file mode 100755 index 0000000000..0cf7edc2d4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png Binary files differnew file mode 100755 index 0000000000..a0c15a6d3e --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index eabcc68916..ce9474d5e5 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -160,7 +160,21 @@ with the same filename but different name <texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> + <texture name="Container" file_name="containers/Container.png" preload="false" /> + + <texture name="Conv_toolbar_add_person" file_name="icons/Conv_toolbar_add_person.png" preload="false" /> + <texture name="Conv_toolbar_arrow_ne" file_name="icons/Conv_toolbar_arrow_ne.png" preload="false" /> + <texture name="Conv_toolbar_arrow_sw" file_name="icons/Conv_toolbar_arrow_sw.png" preload="false" /> + <texture name="Conv_toolbar_call_log" file_name="icons/Conv_toolbar_call_log.png" preload="false" /> + <texture name="Conv_toolbar_close" file_name="icons/Conv_toolbar_close.png" preload="false" /> + <texture name="Conv_toolbar_collapse" file_name="icons/Conv_toolbar_collapse.png" preload="false" /> + <texture name="Conv_toolbar_expand" file_name="icons/Conv_toolbar_expand.png" preload="false" /> + <texture name="Conv_toolbar_hang_up" file_name="icons/Conv_toolbar_hang_up.png" preload="false" /> + <texture name="Conv_toolbar_open_call" file_name="icons/Conv_toolbar_open_call.png" preload="false" /> + <texture name="Conv_toolbar_plus" file_name="icons/Conv_toolbar_plus.png" preload="false" /> + <texture name="Conv_toolbar_sort" file_name="icons/Conv_toolbar_sort.png" preload="false" /> + <texture name="Copy" file_name="icons/Copy.png" preload="false" /> <texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" /> 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 ce40f44a64..8e434b5848 100644 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -15,10 +15,10 @@ width="680"> <string name="collapse_icon" - value="TabIcon_Open_Off"/> + value="Conv_toolbar_collapse"/> <string name="expand_icon" - value="TabIcon_Close_Off"/> + value="Conv_toolbar_expand"/> <layout_stack animate="true" follows="all" @@ -53,7 +53,7 @@ follows="top|left" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="OptionsMenu_Off" + image_overlay="Conv_toolbar_sort" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -65,7 +65,7 @@ follows="top|left" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" + image_overlay="Conv_toolbar_plus" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -84,7 +84,7 @@ follows="right|top" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="TabIcon_Open_Off" + image_overlay="Conv_toolbar_collapse" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" 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 a4695b8c09..32eb4ebdae 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -18,20 +18,20 @@ <floater.string name="NearbyChatTitle" value="Nearby Chat"/> - <floater.string name="call_btn_start">VoicePTT_Off</floater.string> - <floater.string name="call_btn_stop">VoicePTT_On</floater.string> + <floater.string name="call_btn_start">Conv_toolbar_open_call</floater.string> + <floater.string name="call_btn_stop">Conv_toolbar_hang_up</floater.string> <floater.string name="collapse_icon" - value="TabIcon_Open_Off"/> + value="Conv_toolbar_collapse"/> <floater.string name="expand_icon" - value="TabIcon_Close_Off"/> + value="Conv_toolbar_expand"/> <floater.string name="tear_off_icon" - value="tearoffbox.tga"/> + value="Conv_toolbar_arrow_ne"/> <floater.string name="return_icon" - value="Icon_Dock_Foreground"/> + value="Conv_toolbar_arrow_sw"/> <view follows="all" layout="topleft" @@ -52,10 +52,10 @@ menu_filename="menu_im_session_showmodes.xml" follows="top|left" height="25" - image_hover_unselected="Toolbar_Left_Over" - image_overlay="OptionsMenu_Off" - image_selected="Toolbar_Left_Selected" - image_unselected="Toolbar_Left_Off" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Conv_toolbar_sort" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" layout="topleft" left="5" name="view_options_btn" @@ -66,7 +66,7 @@ follows="top|left" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" + image_overlay="Conv_toolbar_add_person" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -77,10 +77,10 @@ <button follows="top|left" height="25" - image_hover_unselected="Toolbar_Right_Over" - image_overlay="VoicePTT_Off" - image_selected="Toolbar_Right_Selected" - image_unselected="Toolbar_Right_Off" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Conv_toolbar_open_call" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" left_pad="4" @@ -90,7 +90,7 @@ follows="right|top" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Icon_Close_Foreground" + image_overlay="Conv_toolbar_close" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -102,7 +102,7 @@ follows="right|top" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="TabIcon_Open_Off" + image_overlay="Conv_toolbar_collapse" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -114,7 +114,7 @@ follows="right|top" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="tearoffbox.tga" + image_overlay="Conv_toolbar_arrow_ne" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -235,26 +235,22 @@ </layout_panel> </layout_stack> </panel> - <panel width="225" - height="31" - left="4" - name="bottom_panel" - bottom="-1" - follows="left|right|bottom" - tab_group="1"> - <line_editor - bottom="0" - follows="left|right|bottom" - font="SansSerifSmall" - visible="true" - height="20" - label="To" - layout="bottomleft" - name="chat_editor" - tab_group="3" - width="220"> - </line_editor> - </panel> + <chat_editor + bottom="0" + expand_lines_count="5" + follows="left|right|bottom" + font="SansSerifSmall" + visible="true" + height="20" + is_expandable="true" + label="To" + layout="bottomleft" + name="chat_editor" + max_length="1023" + tab_group="3" + width="240" + wrap="true"> + </chat_editor> </layout_panel> </layout_stack> </view> diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml new file mode 100644 index 0000000000..63295ea27b --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + name="menu_blocked_gear" + left="0" bottom="0" visible="false" + mouse_opaque="false"> + <menu_item_call + label="Unblock" + name="unblock"> + <on_click + function="Block.Action" + parameter="unblock_item" /> + <on_enable + function="Block.Enable" + parameter="unblock_item" /> + </menu_item_call> + <menu_item_call + label="Profile..." + name="profile"> + <on_click + function="Block.Action" + parameter="profile_item"/> + <on_enable + function="Block.Enable" + parameter="profile_item" /> + </menu_item_call> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml new file mode 100644 index 0000000000..0c7155667e --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + name="menu_blocked_plus" + left="0" bottom="0" visible="false" + mouse_opaque="false"> + <menu_item_call + label="Block Resident by name..." + name="block_resident_by_name"> + <on_click + function="Block.Action" + parameter="block_res_by_name"/> + </menu_item_call> + <menu_item_call + label="Block object by name" + name="block_object_by_name"> + <on_click + function="Block.Action" + parameter="block_obj_by_name"/> + </menu_item_call> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml new file mode 100644 index 0000000000..2efb70ee37 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + name="menu_blocked_view" + left="0" bottom="0" visible="false" + mouse_opaque="false"> + <menu_item_check + label="Sort by name" + name="sort_by_name"> + <on_click + function="Block.Action" + parameter="sort_by_name"/> + <on_check + function="Block.Check" + parameter="sort_by_name"/> + </menu_item_check> + <menu_item_check + label="Sort by type" + name="sort_by_type"> + <on_click + function="Block.Action" + parameter="sort_by_type" /> + <on_check + function="Block.Check" + parameter="sort_by_type" /> + </menu_item_check> +</toggleable_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 3577d2f457..24f7d44cce 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 @@ -5,90 +5,94 @@ height="305" layout="topleft" left="0" - right="-1" name="block_list_panel" help_topic="blocked_list" min_height="350" min_width="240" - width="280"> - <button - follows="top|left" - height="24" - image_hover_unselected="BackButton_Over" - image_pressed="BackButton_Press" - image_unselected="BackButton_Off" - layout="topleft" - name="back" - left="4" - tab_stop="false" - top="1" - width="30"/> - <text - follows="top|left|right" - font="SansSerifLargeBold" - height="20" - layout="topleft" - left_pad="10" - name="title_text" - text_color="white" - top="5" - width="250"> - Block List - </text> - <scroll_list + width="323"> + <panel + follows="left|top|right" + height="27" + label="bottom_panel" + layout="topleft" + left="0" + name="blocked_buttons_panel" + right="-1" + top="0"> + <filter_editor + follows="left|top|right" + height="23" + layout="topleft" + left="6" + label="Filter" + max_length_chars="300" + name="blocked_filter_input" + text_color="Black" + text_pad_left="10" + top="4" + width="177" /> + <menu_button + follows="right" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="OptionsMenu_Off" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + layout="topleft" + left_pad="8" + menu_filename="menu_people_blocked_gear.xml" + menu_position="bottomleft" + name="blocked_gear_btn" + top="3" + width="31" /> + <menu_button + follows="right" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="Conv_toolbar_sort" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + layout="topleft" + left_pad="2" + menu_filename="menu_people_blocked_view.xml" + menu_position="bottomleft" + name="view_btn" + top_delta="0" + width="31" /> + <menu_button + follows="right" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="AddItem_Off" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + layout="topleft" + left_pad="2" + menu_filename="menu_people_blocked_plus.xml" + menu_position="bottomleft" + name="plus_btn" + top_delta="0" + width="31"/> + <button + follows="right" + height="25" + image_hover_unselected="Toolbar_Middle_Over" + image_overlay="TrashItem_Off" + image_selected="Toolbar_Middle_Selected" + image_unselected="Toolbar_Middle_Off" + left_pad="2" + layout="topleft" + name="unblock_btn" + top_delta="0" + width="31"/> + </panel> + <block_list follows="all" - height="190" + height="273" layout="topleft" - left="5" + left="3" name="blocked" tool_tip="List of currently blocked Residents" - top="30" - right="-1" - width="270"> - <scroll_list.columns - name="item_name" /> - <scroll_list.columns - name="item_type" - width="96" /> - </scroll_list> - <button - follows="left|bottom" - height="23" - label="Block person" - layout="topleft" - left_delta="0" - name="Block resident..." - tool_tip="Pick a Resident to block" - top_pad="4" - width="210"> - <button.commit_callback - function="Block.ClickPick" /> - </button> - <button - follows="left|bottom" - height="23" - label="Block object by name" - layout="topleft" - left_delta="0" - name="Block object by name..." - tool_tip="Pick an object to block by name" - top_pad="4" - width="210" > - <button.commit_callback - function="Block.ClickBlockByName" /> - </button> - <button - enabled="false" - follows="left|bottom" - height="23" - label="Unblock" - layout="topleft" - left_delta="0" - name="Unblock" - tool_tip="Remove Resident or object from blocked list" - top_pad="4" - width="210" > - <button.commit_callback - function="Block.ClickRemove" /> - </button> + top="31" + right="-1"/> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml new file mode 100644 index 0000000000..84e7e467b1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + follows="top|right|left" + height="23" + layout="topleft" + left="0" + name="blocked_list_item" + top="0" + width="380"> + <icon + height="24" + follows="top|right|left" + image_name="ListItem_Select" + layout="topleft" + left="0" + name="selected_icon" + top="0" + visible="false" + width="380" /> + <icon + follows="top|right|left" + height="24" + image_name="ListItem_Over" + layout="topleft" + left="0" + name="hovered_icon" + top="0" + visible="false" + width="380" /> + <avatar_icon + default_icon_name="Generic_Person" + follows="top|left" + height="20" + layout="topleft" + left="5" + mouse_opaque="true" + top="2" + visible="false" + width="20" /> + <group_icon + default_icon_name="Generic_Group" + follows="top|left" + height="20" + layout="topleft" + left="5" + mouse_opaque="true" + top="2" + visible="false" + width="20" /> + <icon + follows="top|left" + height="16" + image_name="Inv_Object" + layout="topleft" + left="7" + name="object_icon" + top="4" + visible="false" + width="16" /> + <text + follows="left|right" + font="SansSerifSmall" + font.color="DkGray" + height="15" + layout="topleft" + left_pad="5" + name="item_name" + parse_urls="false" + top="6" + use_ellipses="true" + width="180" /> +</panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index ceb03d03a9..09156b41b5 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -122,7 +122,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M follows="right" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Inv_Underpants" + image_overlay="Conv_toolbar_sort" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -270,7 +270,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M follows="right" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Inv_Underpants" + image_overlay="Conv_toolbar_sort" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -425,7 +425,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M follows="right" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Inv_Underpants" + image_overlay="Conv_toolbar_sort" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -533,7 +533,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M follows="right" height="25" image_hover_unselected="Toolbar_Middle_Over" - image_overlay="Inv_Underpants" + image_overlay="Conv_toolbar_sort" image_selected="Toolbar_Middle_Selected" image_unselected="Toolbar_Middle_Off" layout="topleft" @@ -611,6 +611,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M filename="panel_block_list_sidetray.xml" follows="all" label="Blocked Residents & Objects" + layout="topleft" left="0" font="SansSerifBold" top="0" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index caf7fc85f5..d7a7f7d735 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -76,15 +76,6 @@ top_pad="5" width="400" /> <check_box - enabled="false" - height="16" - label="Enable plain text IM and chat history" - layout="topleft" - left_delta="0" - name="plain_text_chat_history" - top_pad="5" - width="400" /> - <check_box control_name="UseChatBubbles" follows="left|top" height="16" @@ -95,55 +86,6 @@ name="bubble_text_chat" width="150" /> <text - name="show_ims_in_label" - follows="left|top" - layout="topleft" - left="30" - height="20" - width="170" - top_pad="15"> - Show IMs in: - </text> - <text - name="requires_restart_label" - follows="left|top" - layout="topleft" - top_delta="0" - left="170" - height="20" - width="130" - text_color="White_25"> - (requires restart) - </text> - <radio_group - follows="left|top" - height="30" - left="40" - control_name="ChatWindow" - name="chat_window" - top_pad="0" - tool_tip="Show your Instant Messages in separate floaters, or in one floater with many tabs (Requires restart)" - width="150"> - <radio_item - height="16" - label="Separate Windows" - layout="topleft" - left="0" - name="radio" - value="0" - top="0" - width="150" /> - <radio_item - height="16" - label="Tabs" - layout="topleft" - left_delta="0" - name="radio2" - value="1" - top_pad="5" - width="150" /> - </radio_group> - <text name="disable_toast_label" follows="left|top" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 0a2fc13aff..7790a382d9 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3692,6 +3692,7 @@ Try enclosing path to the editor with double quotes. <string name="Command_Avatar_Label">Avatar</string> <string name="Command_Build_Label">Build</string> <string name="Command_Chat_Label">Chat</string> + <string name="Command_Conversations_Label">Conversations</string> <string name="Command_Compass_Label">Compass</string> <string name="Command_Destinations_Label">Destinations</string> <string name="Command_Gestures_Label">Gestures</string> @@ -3718,6 +3719,7 @@ Try enclosing path to the editor with double quotes. <string name="Command_Avatar_Tooltip">Choose a complete avatar</string> <string name="Command_Build_Tooltip">Building objects and reshaping terrain</string> <string name="Command_Chat_Tooltip">Chat with people nearby using text</string> + <string name="Command_Conversations_Tooltip">Converse with everyone</string> <string name="Command_Compass_Tooltip">Compass</string> <string name="Command_Destinations_Tooltip">Destinations of interest</string> <string name="Command_Gestures_Tooltip">Gestures for your avatar</string> diff --git a/indra/newview/skins/default/xui/en/widgets/chat_editor.xml b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml new file mode 100644 index 0000000000..f9facb593a --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<chat_editor + name="chat_editor" + show_context_menu="true"/> diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml index 134f2d7522..2102074674 100644 --- a/indra/newview/skins/default/xui/en/widgets/text.xml +++ b/indra/newview/skins/default/xui/en/widgets/text.xml @@ -9,6 +9,7 @@ h_pad="0" allow_scroll="false" text_readonly_color="LabelTextColor" + text_tentative_color="TextFgTentativeColor" bg_writeable_color="FloaterDefaultBackgroundColor" use_ellipses="false" bg_visible="false" |