CHUI-127 FIXED (Make chat field auto resizable)

- Replaced LLLineEditor with newly created LLChatEntry
- Moved some functionality (such as setting label) to the LLTextBase as it can be useful to the other derived classes
master
Paul ProductEngine 2012-06-19 09:44:40 +03:00
parent 7edcbb1613
commit 18aabdfd3d
18 changed files with 529 additions and 61 deletions

View File

@ -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

View File

@ -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);
}

198
indra/llui/llchatentry.cpp Normal file
View File

@ -0,0 +1,198 @@
/**
* @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("text_editor");
LLChatEntry::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()
{
LLTextEditor::draw();
if(mIsExpandable)
{
expandText();
}
}
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())
{
setText(*mCurrentHistoryLine);
endOfDoc();
}
else if (!mLineHistory.empty() && mCurrentHistoryLine == mLineHistory.end())
{
std::string empty("");
setText(empty);
needsReflow();
endOfDoc();
}
else
{
LLUI::reportBadKeystroke();
}
handled = TRUE;
}
break;
default:
break;
}
return handled;
}

98
indra/llui/llchatentry.h Normal file
View File

@ -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_ */

View File

@ -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())
{
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
//

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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"
@ -64,6 +64,7 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)
mLastMessageIndex(-1),
mDialog(IM_NOTHING_SPECIAL),
mInputEditor(NULL),
mInputEditorTopPad(0),
mSavedTitle(),
mTypingStart(),
mShouldSendTypingState(false),
@ -190,7 +191,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
@ -287,26 +290,26 @@ 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));
mInputEditor->setTextExpandedCallback(boost::bind(&LLIMFloater::reshapeChatHistory, this));
mChatHistory = getChild<LLChatHistory>("chat_history");
mInputEditorTopPad = mChatHistory->getRect().mBottom - mInputEditor->getRect().mTop;
setDocked(true);
mTypingStart = LLTrans::getString("IM_typing_start_string");
@ -880,7 +883,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();
@ -1077,7 +1080,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)
{
@ -1158,6 +1161,17 @@ void LLIMFloater::removeTypingIndicator(const LLIMInfo* im_info)
}
}
void LLIMFloater::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);
}
// static
void LLIMFloater::closeHiddenIMToasts()
{

View File

@ -37,7 +37,9 @@
class LLAvatarName;
class LLButton;
class LLLineEditor;
class LLChatEntry;
class LLTextEditor;
class LLPanelChatControlPanel;
class LLChatHistory;
class LLInventoryItem;
class LLInventoryCategory;
@ -142,7 +144,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);
@ -161,6 +163,13 @@ private:
// Remove the "User is typing..." indicator.
void removeTypingIndicator(const LLIMInfo* im_info = NULL);
/**
* 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();
static void closeHiddenIMToasts();
static void confirmLeaveCallCallback(const LLSD& notification, const LLSD& response);
@ -171,9 +180,11 @@ private:
LLChatHistory* mChatHistory;
int mInputEditorTopPad; // padding between input field and chat history
EInstantMessage mDialog;
LLUUID mOtherParticipantUUID;
LLLineEditor* mInputEditor;
LLChatEntry* mInputEditor;
bool mPositioned;
std::string mSavedTitle;

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -242,18 +242,21 @@
bottom="-1"
follows="left|right|bottom"
tab_group="1">
<line_editor
<text_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"
tab_group="3"
width="220">
</line_editor>
width="240"
wrap="true">
</text_editor>
</panel>
</layout_panel>
</layout_stack>

View File

@ -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"