phoenix-firestorm/indra/llui/llchatentry.cpp

279 lines
6.7 KiB
C++
Executable File

/**
* @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 "llscrollcontainer.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),
mSingleLineMode(false),
mPrevExpandedLineCount(S32_MAX),
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
mCurrentInput("")
{
// Initialize current history line iterator
mCurrentHistoryLine = mLineHistory.begin();
mAutoIndent = false;
}
LLChatEntry::~LLChatEntry()
{
delete mTextExpandedSignal;
}
void LLChatEntry::draw()
{
if(mIsExpandable)
{
reflow();
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()
{
S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount;
// <FS:Ansariel> Store result of getVisibleLines - it calls reflow
//int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second);
std::pair<BOOL, BOOL> visible_lines = getVisibleLines(true);
int visible_lines_count = llabs(visible_lines.first - visible_lines.second);
// </FS:Ansariel>
bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ;
mPrevExpandedLineCount = line_count;
// true if pasted text has more lines than expand height limit and expand limit is not reached yet
bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count);
if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && 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 'expanded_line_count' lines height
lines_height = (mLineInfoList.end() - line_count)->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() );
}
needsReflow();
}
}
// 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();
}
}
void LLChatEntry::beforeValueChange()
{
if(this->getLength() == 0 && !mLabel.empty())
{
this->clearSegments();
}
}
void LLChatEntry::onValueChange(S32 start, S32 end)
{
//Internally resetLabel() must meet a condition before it can reset the label
resetLabel();
}
bool LLChatEntry::useLabel() const
{
return !getLength() && !mLabel.empty();
}
void LLChatEntry::onFocusReceived()
{
LLUICtrl::onFocusReceived();
updateAllowingLanguageInput();
}
void LLChatEntry::onFocusLost()
{
LLTextEditor::focusLostHelper();
LLUICtrl::onFocusLost();
}
BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
{
BOOL handled = FALSE;
// In the case of a chat entry, pressing RETURN when something is selected
// should NOT erase the selection (unlike a notecard, for example)
if (key == KEY_RETURN)
{
endOfDoc();
startSelection();
endSelection();
}
LLTextEditor::handleSpecialKey(key, mask);
switch(key)
{
case KEY_RETURN:
if (MASK_NONE == mask)
{
needsReflow();
}
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
mCurrentInput = "";
break;
case KEY_UP:
if (mHasHistory && MASK_CONTROL == mask)
{
if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin())
{
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
if (mCurrentHistoryLine == mLineHistory.end())
{
mCurrentInput = getText();
}
// </FS:Ansariel>
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++;
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
//std::string empty("");
//setText(empty);
setText(mCurrentInput);
// </FS:Ansariel>
needsReflow();
endOfDoc();
}
else
{
LLUI::reportBadKeystroke();
}
handled = TRUE;
}
break;
default:
break;
}
return handled;
}
void LLChatEntry::enableSingleLineMode(bool single_line_mode)
{
if (mScroller)
{
mScroller->setSize(single_line_mode ? 0 : -1);
}
mSingleLineMode = single_line_mode;
mPrevLinesCount = -1;
setWordWrap(!single_line_mode);
}