From a8a62201ba762e98dff92cf49033e577fc34d8d4 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:45:27 -0500 Subject: Second Life viewer sources 1.19.0.0 --- linden/indra/llui/lltexteditor.cpp | 539 ++++++++++++++++++++++++++++++++----- 1 file changed, 465 insertions(+), 74 deletions(-) (limited to 'linden/indra/llui/lltexteditor.cpp') diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp index b4d693b..ca9ea0a 100644 --- a/linden/indra/llui/lltexteditor.cpp +++ b/linden/indra/llui/lltexteditor.cpp @@ -12,12 +12,12 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -79,6 +79,15 @@ const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds const S32 CURSOR_THICKNESS = 2; const S32 SPACES_PER_TAB = 4; +const F32 PREEDIT_MARKER_BRIGHTNESS = 0.4f; +const S32 PREEDIT_MARKER_GAP = 1; +const S32 PREEDIT_MARKER_POSITION = 2; +const S32 PREEDIT_MARKER_THICKNESS = 1; +const F32 PREEDIT_STANDOUT_BRIGHTNESS = 0.6f; +const S32 PREEDIT_STANDOUT_GAP = 1; +const S32 PREEDIT_STANDOUT_POSITION = 2; +const S32 PREEDIT_STANDOUT_THICKNESS = 2; + LLColor4 LLTextEditor::mLinkColor = LLColor4::blue; void (* LLTextEditor::mURLcallback)(const char*) = NULL; bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; @@ -274,14 +283,14 @@ private: LLTextEditor::LLTextEditor( const LLString& name, const LLRect& rect, - S32 max_length, + S32 max_length, // In bytes const LLString &default_text, const LLFontGL* font, BOOL allow_embedded_items) : LLUICtrl( name, rect, TRUE, NULL, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ), mTextIsUpToDate(TRUE), - mMaxTextLength( max_length ), + mMaxTextByteLength( max_length ), mBaseDocIsPristine(TRUE), mPristineCmd( NULL ), mLastCmd( NULL ), @@ -293,6 +302,7 @@ LLTextEditor::LLTextEditor( mOnScrollEndData( NULL ), mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ), mFgColor( LLUI::sColorsGroup->getColor( "TextFgColor" ) ), + mDefaultColor( LLUI::sColorsGroup->getColor( "TextDefaultColor" ) ), mReadOnlyFgColor( LLUI::sColorsGroup->getColor( "TextFgReadOnlyColor" ) ), mWriteableBgColor( LLUI::sColorsGroup->getColor( "TextBgWriteableColor" ) ), mReadOnlyBgColor( LLUI::sColorsGroup->getColor( "TextBgReadOnlyColor" ) ), @@ -301,9 +311,9 @@ LLTextEditor::LLTextEditor( mWordWrap( FALSE ), mTabToNextField( TRUE ), mCommitOnFocusLost( FALSE ), - mTakesFocus( TRUE ), mHideScrollbarForShortDocs( FALSE ), mTakesNonScrollClicks( TRUE ), + mTrackBottom( TRUE ), mAllowEmbeddedItems( allow_embedded_items ), mAcceptCallingCardNames(FALSE), mHandleEditKeysDirectly( FALSE ), @@ -510,13 +520,27 @@ BOOL LLTextEditor::isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); } -void LLTextEditor::truncate() +BOOL LLTextEditor::truncate() { - if (mWText.size() > (size_t)mMaxTextLength) - { - LLWString::truncate(mWText, mMaxTextLength); - mTextIsUpToDate = FALSE; + BOOL did_truncate = FALSE; + + // First rough check - if we're less than 1/4th the size, we're OK + if (mWText.size() >= (size_t) (mMaxTextByteLength / 4)) + { + // Have to check actual byte size + S32 utf8_byte_size = wstring_utf8_length( mWText ); + if ( utf8_byte_size > mMaxTextByteLength ) + { + // Truncate safely in UTF-8 + std::string temp_utf8_text = wstring_to_utf8str( mWText ); + temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength ); + mWText = utf8str_to_wstring( temp_utf8_text ); + mTextIsUpToDate = FALSE; + did_truncate = TRUE; + } } + + return did_truncate; } void LLTextEditor::setText(const LLStringExplicit &utf8str) @@ -750,12 +774,12 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const return cursorPos; } -S32 LLTextEditor::getLineCount() +S32 LLTextEditor::getLineCount() const { return mLineStartList.size(); } -S32 LLTextEditor::getLineStart( S32 line ) +S32 LLTextEditor::getLineStart( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) @@ -1118,46 +1142,42 @@ void LLTextEditor::selectAll() BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) { - if (pointInView(x, y) && getVisible()) + for ( child_list_const_iter_t child_it = getChildList()->begin(); + child_it != getChildList()->end(); ++child_it) { - for ( child_list_const_iter_t child_it = getChildList()->begin(); - child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) ) - { - return TRUE; - } - } - - if( mSegments.empty() ) + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) ) { return TRUE; } + } - LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) - { - BOOL has_tool_tip = FALSE; - has_tool_tip = cur_segment->getToolTip( msg ); + if( mSegments.empty() ) + { + return TRUE; + } - if( has_tool_tip ) - { - // Just use a slop area around the cursor - // Convert rect local to screen coordinates - S32 SLOP = 8; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; - sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; - } + LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); + if( cur_segment ) + { + BOOL has_tool_tip = FALSE; + has_tool_tip = cur_segment->getToolTip( msg ); + + if( has_tool_tip ) + { + // Just use a slop area around the cursor + // Convert rect local to screen coordinates + S32 SLOP = 8; + localPointToScreen( + x - SLOP, y - SLOP, + &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); + sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; + sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; } - return TRUE; } - return FALSE; + return TRUE; } BOOL LLTextEditor::handleScrollWheel(S32 x, S32 y, S32 clicks) @@ -1240,7 +1260,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) handled = TRUE; } - if (mTakesFocus) + if (hasTabStop()) { setFocus( TRUE ); handled = TRUE; @@ -1413,11 +1433,6 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) if( !handled && mTakesNonScrollClicks) { - if (mTakesFocus) - { - setFocus( TRUE ); - } - setCursorAtLocalPos( x, y, FALSE ); deselect(); @@ -1604,7 +1619,7 @@ void LLTextEditor::removeChar() // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ((S32)mWText.length() == mMaxTextLength) + if ( (wstring_utf8_length( mWText ) + wchar_utf8_length( wc )) >= mMaxTextByteLength) { make_ui_sound("UISndBadKeystroke"); return 0; @@ -2490,11 +2505,16 @@ void LLTextEditor::redo() } } +void LLTextEditor::onFocusReceived() +{ + LLUICtrl::onFocusReceived(); + updateAllowingLanguageInput(); +} // virtual, from LLView void LLTextEditor::onFocusLost() { - getWindow()->allowLanguageTextInput(FALSE); + updateAllowingLanguageInput(); // Route menu back to the default if( gEditMenuHandler == this ) @@ -2521,6 +2541,7 @@ void LLTextEditor::setEnabled(BOOL enabled) { mReadOnly = read_only; updateSegments(); + updateAllowingLanguageInput(); } } @@ -2825,6 +2846,100 @@ void LLTextEditor::drawCursor() } } +void LLTextEditor::drawPreeditMarker() +{ + if (!hasPreeditString()) + { + return; + } + + const llwchar *text = mWText.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = mScrollbar->getDocPos(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = llround( mGLFont->getLineHeight() ); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mTextRect.mTop - line_height; + while((mTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + S32 preedit_left = mTextRect.mLeft; + if (left > line_start) + { + preedit_left += mGLFont->getWidth(text, line_start, left - line_start, mAllowEmbeddedItems); + } + S32 preedit_right = mTextRect.mLeft; + if (right < line_end) + { + preedit_right += mGLFont->getWidth(text, line_start, right - line_start, mAllowEmbeddedItems); + } + else + { + preedit_right += mGLFont->getWidth(text, line_start, line_end - line_start, mAllowEmbeddedItems); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + PREEDIT_STANDOUT_GAP, + line_y + PREEDIT_STANDOUT_POSITION, + preedit_right - PREEDIT_STANDOUT_GAP - 1, + line_y + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS, + (mCursorColor * PREEDIT_STANDOUT_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + PREEDIT_MARKER_GAP, + line_y + PREEDIT_MARKER_POSITION, + preedit_right - PREEDIT_MARKER_GAP - 1, + line_y + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS, + (mCursorColor * PREEDIT_MARKER_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } +} + void LLTextEditor::drawText() { @@ -3025,6 +3140,7 @@ void LLTextEditor::draw() drawBackground(); drawSelectionBackground(); + drawPreeditMarker(); drawText(); drawCursor(); @@ -3036,6 +3152,9 @@ void LLTextEditor::draw() } LLView::draw(); // Draw children (scrollbar and border) } + + // remember if we are supposed to be at the bottom of the buffer + mScrolledToBottom = isScrolledToBottom(); } void LLTextEditor::reportBadKeystroke() @@ -3067,10 +3186,10 @@ void LLTextEditor::setFocus( BOOL new_state ) // Don't change anything if the focus state didn't change if (new_state == old_state) return; - // Notify early if we are loosing focus. + // Notify early if we are losing focus. if (!new_state) { - getWindow()->allowLanguageTextInput(FALSE); + getWindow()->allowLanguageTextInput(this, FALSE); } LLUICtrl::setFocus( new_state ); @@ -3093,12 +3212,6 @@ void LLTextEditor::setFocus( BOOL new_state ) endSelection(); } - - // Notify late if we are gaining focus. - if (new_state && !mReadOnly) - { - getWindow()->allowLanguageTextInput(TRUE); - } } BOOL LLTextEditor::acceptsTextInput() const @@ -3210,6 +3323,17 @@ void LLTextEditor::changeLine( S32 delta ) unbindEmbeddedChars( mGLFont ); } +BOOL LLTextEditor::isScrolledToTop() +{ + return mScrollbar->isAtBeginning(); +} + +BOOL LLTextEditor::isScrolledToBottom() +{ + return mScrollbar->isAtEnd(); +} + + void LLTextEditor::startOfLine() { S32 line, offset; @@ -3330,6 +3454,13 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent) { LLView::reshape( width, height, called_from_parent ); + // if scrolled to bottom, stay at bottom + // unless user is editing text + if (mScrolledToBottom && mTrackBottom && !hasFocus()) + { + endOfDoc(); + } + updateTextRect(); S32 line_height = llround( mGLFont->getLineHeight() ); @@ -3540,22 +3671,20 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars) S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr) { - S32 len = mWText.length(); - S32 s_len = wstr.length(); - S32 new_len = len + s_len; - if( new_len > mMaxTextLength ) - { - new_len = mMaxTextLength; + S32 old_len = mWText.length(); // length() returns character length + S32 insert_len = wstr.length(); + + mWText.insert(pos, wstr); + mTextIsUpToDate = FALSE; + if ( truncate() ) + { // The user's not getting everything he's hoping for make_ui_sound("UISndBadKeystroke"); + insert_len = mWText.length() - old_len; } - mWText.insert(pos, wstr); - mTextIsUpToDate = FALSE; - truncate(); - - return new_len - len; + return insert_len; } S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length) @@ -3671,7 +3800,7 @@ void LLTextEditor::loadKeywords(const LLString& filename, mKeywords.addToken(LLKeywordToken::WORD, name.c_str(), color, tooltips.get(i) ); } - mKeywords.findSegments( &mSegments, mWText ); + mKeywords.findSegments( &mSegments, mWText, mDefaultColor ); llassert( mSegments.front()->getStart() == 0 ); llassert( mSegments.back()->getEnd() == getLength() ); @@ -3683,7 +3812,7 @@ void LLTextEditor::updateSegments() if (mKeywords.isLoaded()) { // HACK: No non-ascii keywords for now - mKeywords.findSegments(&mSegments, mWText); + mKeywords.findSegments(&mSegments, mWText, mDefaultColor); } else if (mAllowEmbeddedItems) { @@ -3920,7 +4049,7 @@ BOOL LLTextEditor::importBuffer(const LLString& buffer ) return FALSE; } - if( text_len > mMaxTextLength ) + if( text_len > mMaxTextByteLength ) { llwarns << "Invalid Linden text length: " << text_len << llendl; return FALSE; @@ -4064,6 +4193,7 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor"); addColorXML(node, mFgColor, "text_color", "TextFgColor"); + addColorXML(node, mDefaultColor, "text_default_color", "TextDefaultColor"); addColorXML(node, mReadOnlyFgColor, "text_readonly_color", "TextFgReadOnlyColor"); addColorXML(node, mReadOnlyBgColor, "bg_readonly_color", "TextBgReadOnlyColor"); addColorXML(node, mWriteableBgColor, "bg_writeable_color", "TextBgWriteableColor"); @@ -4118,6 +4248,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node) node->getAttributeBOOL("word_wrap", word_wrap); setWordWrap(word_wrap); + node->getAttributeBOOL("track_bottom", mTrackBottom); + LLColor4 color; if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color)) { @@ -4281,3 +4413,262 @@ BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) } return matched; } + + + +void LLTextEditor::updateAllowingLanguageInput() +{ + if (hasFocus() && !mReadOnly) + { + getWindow()->allowLanguageTextInput(this, TRUE); + } + else + { + getWindow()->allowLanguageTextInput(this, FALSE); + } +} + +// Preedit is managed off the undo/redo command stack. + +BOOL LLTextEditor::hasPreeditString() const +{ + return (mPreeditPositions.size() > 1); +} + +void LLTextEditor::resetPreedit() +{ + if (hasPreeditString()) + { + mCursorPos = mPreeditPositions.front(); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); + + updateLineStartList(); + setCursorPos(mCursorPos); + // updateScrollFromCursor(); + } +} + +void LLTextEditor::updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) +{ + // Just in case. + if (mReadOnly) + { + return; + } + + if (hasSelection()) + { + if (hasPreeditString()) + { + llwarns << "Preedit and selection!" << llendl; + deselect(); + } + else + { + deleteSelection(TRUE); + } + } + + getWindow()->hideCursorUntilMouseMove(); + + S32 insert_preedit_at = mCursorPos; + if (hasPreeditString()) + { + insert_preedit_at = mPreeditPositions.front(); + removeStringNoUndo(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at); + insertStringNoUndo(insert_preedit_at, mPreeditOverwrittenWString); + } + + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; + + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWSubString(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } + insertStringNoUndo(insert_preedit_at, mPreeditWString); + + mPreeditStandouts = preedit_standouts; + + updateLineStartList(); + setCursorPos(insert_preedit_at + caret_position); + // updateScrollFromCursor(); + + // Update of the preedit should be caused by some key strokes. + mKeystrokeTimer.reset(); +} + +BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const +{ + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mTextRect, &control_rect_screen); + LLUI::screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = mScrollbar->getDocPos(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } + + const llwchar * const text = mWText.c_str(); + const S32 line_height = llround(mGLFont->getLineHeight()); + + if (coord) + { + const S32 query_x = mTextRect.mLeft + mGLFont->getWidth(text, current_line_start, query - current_line_start, mAllowEmbeddedItems); + const S32 query_y = mTextRect.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); + LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mGLFont->getWidth(text, current_line_start, preedit_left_position - current_line_start, mAllowEmbeddedItems); + } + + S32 preedit_right = mTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mGLFont->getWidth(text, current_line_start, preedit_right_position - current_line_start, mAllowEmbeddedItems); + } + else + { + preedit_right += mGLFont->getWidth(text, current_line_start, current_line_end - current_line_start, mAllowEmbeddedItems); + } + + const S32 preedit_top = mTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; +} + +void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const +{ + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } +} + +void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const +{ + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } +} + +void LLTextEditor::markAsPreedit(S32 position, S32 length) +{ + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl; + } + mPreeditWString = LLWString( mWText, position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } +} + +S32 LLTextEditor::getPreeditFontSize() const +{ + return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); +} -- cgit v1.1