aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/lltexteditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llui/lltexteditor.cpp128
1 files changed, 63 insertions, 65 deletions
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index 90199f1..72d8f17 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -260,7 +260,7 @@ LLTextEditor::LLTextEditor(
260 mIsSelecting( FALSE ), 260 mIsSelecting( FALSE ),
261 mSelectionStart( 0 ), 261 mSelectionStart( 0 ),
262 mSelectionEnd( 0 ), 262 mSelectionEnd( 0 ),
263 mScrolledToBottom( FALSE ), 263 mScrolledToBottom( TRUE ),
264 mOnScrollEndCallback( NULL ), 264 mOnScrollEndCallback( NULL ),
265 mOnScrollEndData( NULL ), 265 mOnScrollEndData( NULL ),
266 mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ), 266 mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ),
@@ -277,14 +277,16 @@ LLTextEditor::LLTextEditor(
277 mCommitOnFocusLost( FALSE ), 277 mCommitOnFocusLost( FALSE ),
278 mHideScrollbarForShortDocs( FALSE ), 278 mHideScrollbarForShortDocs( FALSE ),
279 mTakesNonScrollClicks( TRUE ), 279 mTakesNonScrollClicks( TRUE ),
280 mTrackBottom( TRUE ), 280 mTrackBottom( FALSE ),
281 mAllowEmbeddedItems( allow_embedded_items ), 281 mAllowEmbeddedItems( allow_embedded_items ),
282 mAcceptCallingCardNames(FALSE), 282 mAcceptCallingCardNames(FALSE),
283 mHandleEditKeysDirectly( FALSE ), 283 mHandleEditKeysDirectly( FALSE ),
284 mMouseDownX(0), 284 mMouseDownX(0),
285 mMouseDownY(0), 285 mMouseDownY(0),
286 mLastSelectionX(-1), 286 mLastSelectionX(-1),
287 mLastSelectionY(-1) 287 mLastSelectionY(-1),
288 mReflowNeeded(FALSE),
289 mScrollNeeded(FALSE)
288{ 290{
289 mSourceID.generate(); 291 mSourceID.generate();
290 292
@@ -468,6 +470,13 @@ void LLTextEditor::updateLineStartList(S32 startpos)
468 mScrollbar->setVisible(!short_doc); 470 mScrollbar->setVisible(!short_doc);
469 } 471 }
470 472
473 // if scrolled to bottom, stay at bottom
474 // unless user is editing text
475 // do this after updating page size
476 if (mScrolledToBottom && mTrackBottom && !hasFocus())
477 {
478 endOfDoc();
479 }
471} 480}
472 481
473//////////////////////////////////////////////////////////// 482////////////////////////////////////////////////////////////
@@ -511,8 +520,7 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str)
511 setCursorPos(0); 520 setCursorPos(0);
512 deselect(); 521 deselect();
513 522
514 updateLineStartList(); 523 needsReflow();
515 updateScrollFromCursor();
516 524
517 resetDirty(); 525 resetDirty();
518} 526}
@@ -529,8 +537,7 @@ void LLTextEditor::setWText(const LLWString &wtext)
529 setCursorPos(0); 537 setCursorPos(0);
530 deselect(); 538 deselect();
531 539
532 updateLineStartList(); 540 needsReflow();
533 updateScrollFromCursor();
534 541
535 resetDirty(); 542 resetDirty();
536} 543}
@@ -568,8 +575,7 @@ void LLTextEditor::setWordWrap(BOOL b)
568 setCursorPos(0); 575 setCursorPos(0);
569 deselect(); 576 deselect();
570 577
571 updateLineStartList(); 578 needsReflow();
572 updateScrollFromCursor();
573} 579}
574 580
575 581
@@ -734,6 +740,7 @@ S32 LLTextEditor::getLineStart( S32 line ) const
734 { 740 {
735 return 0; 741 return 0;
736 } 742 }
743
737 line = llclamp(line, 0, num_lines-1); 744 line = llclamp(line, 0, num_lines-1);
738 S32 segidx = mLineStartList[line].mSegment; 745 S32 segidx = mLineStartList[line].mSegment;
739 S32 segoffset = mLineStartList[line].mOffset; 746 S32 segoffset = mLineStartList[line].mOffset;
@@ -781,14 +788,14 @@ void LLTextEditor::getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp
781 *offsetp = startpos - (*seg_iter)->getStart(); 788 *offsetp = startpos - (*seg_iter)->getStart();
782} 789}
783 790
784const LLTextSegment* LLTextEditor::getPreviousSegment() 791const LLTextSegment* LLTextEditor::getPreviousSegment() const
785{ 792{
786 // find segment index at character to left of cursor (or rightmost edge of selection) 793 // find segment index at character to left of cursor (or rightmost edge of selection)
787 S32 idx = llmax(0, getSegmentIdxAtOffset(mCursorPos) - 1); 794 S32 idx = llmax(0, getSegmentIdxAtOffset(mCursorPos) - 1);
788 return idx >= 0 ? mSegments[idx] : NULL; 795 return idx >= 0 ? mSegments[idx] : NULL;
789} 796}
790 797
791void LLTextEditor::getSelectedSegments(std::vector<const LLTextSegment*>& segments) 798void LLTextEditor::getSelectedSegments(std::vector<const LLTextSegment*>& segments) const
792{ 799{
793 S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; 800 S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos;
794 S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; 801 S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos;
@@ -875,13 +882,12 @@ void LLTextEditor::setCursor(S32 row, S32 column)
875 } 882 }
876 doc += column; 883 doc += column;
877 setCursorPos(doc - mWText.c_str()); 884 setCursorPos(doc - mWText.c_str());
878 updateScrollFromCursor();
879} 885}
880 886
881void LLTextEditor::setCursorPos(S32 offset) 887void LLTextEditor::setCursorPos(S32 offset)
882{ 888{
883 mCursorPos = llclamp(offset, 0, (S32)getLength()); 889 mCursorPos = llclamp(offset, 0, (S32)getLength());
884 updateScrollFromCursor(); 890 needsScroll();
885 // reset desired x cursor position 891 // reset desired x cursor position
886 mDesiredXPixel = -1; 892 mDesiredXPixel = -1;
887} 893}
@@ -925,7 +931,7 @@ BOOL LLTextEditor::selectionContainsLineBreaks()
925 if (hasSelection()) 931 if (hasSelection())
926 { 932 {
927 S32 left = llmin(mSelectionStart, mSelectionEnd); 933 S32 left = llmin(mSelectionStart, mSelectionEnd);
928 S32 right = left + abs(mSelectionStart - mSelectionEnd); 934 S32 right = left + llabs(mSelectionStart - mSelectionEnd);
929 935
930 const LLWString &wtext = mWText; 936 const LLWString &wtext = mWText;
931 for( S32 i = left; i < right; i++ ) 937 for( S32 i = left; i < right; i++ )
@@ -981,7 +987,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
981 { 987 {
982 const LLWString &text = mWText; 988 const LLWString &text = mWText;
983 S32 left = llmin( mSelectionStart, mSelectionEnd ); 989 S32 left = llmin( mSelectionStart, mSelectionEnd );
984 S32 right = left + abs( mSelectionStart - mSelectionEnd ); 990 S32 right = left + llabs( mSelectionStart - mSelectionEnd );
985 BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); 991 BOOL cursor_on_right = (mSelectionEnd > mSelectionStart);
986 S32 cur = left; 992 S32 cur = left;
987 993
@@ -1222,8 +1228,6 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
1222 1228
1223 setCursorAtLocalPos( x, y, TRUE ); 1229 setCursorAtLocalPos( x, y, TRUE );
1224 mSelectionEnd = mCursorPos; 1230 mSelectionEnd = mCursorPos;
1225
1226 updateScrollFromCursor();
1227 } 1231 }
1228 1232
1229 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; 1233 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
@@ -1812,7 +1816,7 @@ void LLTextEditor::deleteSelection(BOOL group_with_next_op )
1812 if( getEnabled() && hasSelection() ) 1816 if( getEnabled() && hasSelection() )
1813 { 1817 {
1814 S32 pos = llmin( mSelectionStart, mSelectionEnd ); 1818 S32 pos = llmin( mSelectionStart, mSelectionEnd );
1815 S32 length = abs( mSelectionStart - mSelectionEnd ); 1819 S32 length = llabs( mSelectionStart - mSelectionEnd );
1816 1820
1817 remove( pos, length, group_with_next_op ); 1821 remove( pos, length, group_with_next_op );
1818 1822
@@ -1835,12 +1839,11 @@ void LLTextEditor::cut()
1835 return; 1839 return;
1836 } 1840 }
1837 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1841 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
1838 S32 length = abs( mSelectionStart - mSelectionEnd ); 1842 S32 length = llabs( mSelectionStart - mSelectionEnd );
1839 gClipboard.copyFromSubstring( mWText, left_pos, length, mSourceID ); 1843 gClipboard.copyFromSubstring( mWText, left_pos, length, mSourceID );
1840 deleteSelection( FALSE ); 1844 deleteSelection( FALSE );
1841 1845
1842 updateLineStartList(); 1846 needsReflow();
1843 updateScrollFromCursor();
1844} 1847}
1845 1848
1846BOOL LLTextEditor::canCopy() const 1849BOOL LLTextEditor::canCopy() const
@@ -1856,7 +1859,7 @@ void LLTextEditor::copy()
1856 return; 1859 return;
1857 } 1860 }
1858 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1861 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
1859 S32 length = abs( mSelectionStart - mSelectionEnd ); 1862 S32 length = llabs( mSelectionStart - mSelectionEnd );
1860 gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); 1863 gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID);
1861} 1864}
1862 1865
@@ -1910,8 +1913,7 @@ void LLTextEditor::paste()
1910 setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE)); 1913 setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE));
1911 deselect(); 1914 deselect();
1912 1915
1913 updateLineStartList(); 1916 needsReflow();
1914 updateScrollFromCursor();
1915} 1917}
1916 1918
1917 1919
@@ -2235,9 +2237,9 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
2235 2237
2236 if(text_may_have_changed) 2238 if(text_may_have_changed)
2237 { 2239 {
2238 updateLineStartList(); 2240 needsReflow();
2239 } 2241 }
2240 updateScrollFromCursor(); 2242 needsScroll();
2241 } 2243 }
2242 } 2244 }
2243 2245
@@ -2280,8 +2282,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
2280 // Most keystrokes will make the selection box go away, but not all will. 2282 // Most keystrokes will make the selection box go away, but not all will.
2281 deselect(); 2283 deselect();
2282 2284
2283 updateLineStartList(); 2285 needsReflow();
2284 updateScrollFromCursor();
2285 } 2286 }
2286 } 2287 }
2287 2288
@@ -2339,8 +2340,7 @@ void LLTextEditor::doDelete()
2339 } 2340 }
2340 } 2341 }
2341 2342
2342 updateLineStartList(); 2343 needsReflow();
2343 updateScrollFromCursor();
2344} 2344}
2345 2345
2346//---------------------------------------------------------------------------- 2346//----------------------------------------------------------------------------
@@ -2383,8 +2383,7 @@ void LLTextEditor::undo()
2383 2383
2384 setCursorPos(pos); 2384 setCursorPos(pos);
2385 2385
2386 updateLineStartList(); 2386 needsReflow();
2387 updateScrollFromCursor();
2388} 2387}
2389 2388
2390BOOL LLTextEditor::canRedo() const 2389BOOL LLTextEditor::canRedo() const
@@ -2426,8 +2425,7 @@ void LLTextEditor::redo()
2426 2425
2427 setCursorPos(pos); 2426 setCursorPos(pos);
2428 2427
2429 updateLineStartList(); 2428 needsReflow();
2430 updateScrollFromCursor();
2431} 2429}
2432 2430
2433void LLTextEditor::onFocusReceived() 2431void LLTextEditor::onFocusReceived()
@@ -3100,6 +3098,20 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
3100 3098
3101void LLTextEditor::draw() 3099void LLTextEditor::draw()
3102{ 3100{
3101 // do on-demand reflow
3102 if (mReflowNeeded)
3103 {
3104 updateLineStartList();
3105 mReflowNeeded = FALSE;
3106 }
3107
3108 // then update scroll position, as cursor may have moved
3109 if (mScrollNeeded)
3110 {
3111 updateScrollFromCursor();
3112 mScrollNeeded = FALSE;
3113 }
3114
3103 { 3115 {
3104 LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); 3116 LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0));
3105 3117
@@ -3118,10 +3130,10 @@ void LLTextEditor::draw()
3118 mBorder->setKeyboardFocusHighlight( gFocusMgr.getKeyboardFocus() == this);// && !mReadOnly); 3130 mBorder->setKeyboardFocusHighlight( gFocusMgr.getKeyboardFocus() == this);// && !mReadOnly);
3119 } 3131 }
3120 3132
3133 LLView::draw(); // Draw children (scrollbar and border)
3134
3121 // remember if we are supposed to be at the bottom of the buffer 3135 // remember if we are supposed to be at the bottom of the buffer
3122 mScrolledToBottom = isScrolledToBottom(); 3136 mScrolledToBottom = isScrolledToBottom();
3123
3124 LLView::draw(); // Draw children (scrollbar and border)
3125} 3137}
3126 3138
3127 3139
@@ -3311,7 +3323,7 @@ void LLTextEditor::setCursorAndScrollToEnd()
3311{ 3323{
3312 deselect(); 3324 deselect();
3313 endOfDoc(); 3325 endOfDoc();
3314 updateScrollFromCursor(); 3326 needsScroll();
3315} 3327}
3316 3328
3317void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap ) 3329void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap )
@@ -3374,7 +3386,9 @@ void LLTextEditor::endOfLine()
3374 3386
3375void LLTextEditor::endOfDoc() 3387void LLTextEditor::endOfDoc()
3376{ 3388{
3377 mScrollbar->setDocPos( mScrollbar->getDocPosMax() ); 3389 mScrollbar->setDocPos(mScrollbar->getDocPosMax());
3390 mScrolledToBottom = true;
3391
3378 S32 len = getLength(); 3392 S32 len = getLength();
3379 if( len ) 3393 if( len )
3380 { 3394 {
@@ -3438,7 +3452,7 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
3438 // up-to-date mTextRect 3452 // up-to-date mTextRect
3439 updateTextRect(); 3453 updateTextRect();
3440 3454
3441 updateLineStartList(); 3455 needsReflow();
3442 3456
3443 // propagate shape information to scrollbar 3457 // propagate shape information to scrollbar
3444 mScrollbar->setDocSize( getLineCount() ); 3458 mScrollbar->setDocSize( getLineCount() );
@@ -3446,14 +3460,6 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
3446 S32 line_height = llround( mGLFont->getLineHeight() ); 3460 S32 line_height = llround( mGLFont->getLineHeight() );
3447 S32 page_lines = mTextRect.getHeight() / line_height; 3461 S32 page_lines = mTextRect.getHeight() / line_height;
3448 mScrollbar->setPageSize( page_lines ); 3462 mScrollbar->setPageSize( page_lines );
3449
3450 // if scrolled to bottom, stay at bottom
3451 // unless user is editing text
3452 // do this after updating page size
3453 if (mScrolledToBottom && mTrackBottom && !hasFocus())
3454 {
3455 endOfDoc();
3456 }
3457} 3463}
3458 3464
3459void LLTextEditor::autoIndent() 3465void LLTextEditor::autoIndent()
@@ -3500,8 +3506,7 @@ void LLTextEditor::insertText(const std::string &new_text)
3500 3506
3501 setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE )); 3507 setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE ));
3502 3508
3503 updateLineStartList(); 3509 needsReflow();
3504 updateScrollFromCursor();
3505 3510
3506 setEnabled( enabled ); 3511 setEnabled( enabled );
3507} 3512}
@@ -3600,7 +3605,7 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool
3600 mSegments.push_back(segment); 3605 mSegments.push_back(segment);
3601 } 3606 }
3602 3607
3603 updateLineStartList(old_length); 3608 needsReflow();
3604 3609
3605 // Set the cursor and scroll position 3610 // Set the cursor and scroll position
3606 // Maintain the scroll position unless the scroll was at the end of the doc (in which 3611 // Maintain the scroll position unless the scroll was at the end of the doc (in which
@@ -3639,14 +3644,6 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool
3639 { 3644 {
3640 blockUndo(); 3645 blockUndo();
3641 } 3646 }
3642
3643 // if scrolled to bottom, stay at bottom
3644 // unless user is editing text
3645 // do this after updating page size
3646 if (mScrolledToBottom && mTrackBottom && !hasFocus())
3647 {
3648 endOfDoc();
3649 }
3650} 3647}
3651 3648
3652void LLTextEditor::removeTextFromEnd(S32 num_chars) 3649void LLTextEditor::removeTextFromEnd(S32 num_chars)
@@ -3661,7 +3658,10 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars)
3661 mSelectionEnd = llclamp(mSelectionEnd, 0, len); 3658 mSelectionEnd = llclamp(mSelectionEnd, 0, len);
3662 3659
3663 pruneSegments(); 3660 pruneSegments();
3661
3662 // pruneSegments will invalidate mLineStartList.
3664 updateLineStartList(); 3663 updateLineStartList();
3664 needsScroll();
3665} 3665}
3666 3666
3667/////////////////////////////////////////////////////////////////// 3667///////////////////////////////////////////////////////////////////
@@ -3759,8 +3759,7 @@ BOOL LLTextEditor::tryToRevertToPristineState()
3759 } 3759 }
3760 } 3760 }
3761 3761
3762 updateLineStartList(); 3762 needsReflow();
3763 updateScrollFromCursor();
3764 } 3763 }
3765 3764
3766 return isPristine(); // TRUE => success 3765 return isPristine(); // TRUE => success
@@ -3808,6 +3807,7 @@ void LLTextEditor::updateSegments()
3808 { 3807 {
3809 findEmbeddedItemSegments(); 3808 findEmbeddedItemSegments();
3810 } 3809 }
3810
3811 // Make sure we have at least one segment 3811 // Make sure we have at least one segment
3812 if (mSegments.size() == 1 && mSegments[0]->getIsDefault()) 3812 if (mSegments.size() == 1 && mSegments[0]->getIsDefault())
3813 { 3813 {
@@ -3824,6 +3824,7 @@ void LLTextEditor::updateSegments()
3824} 3824}
3825 3825
3826// Only effective if text was removed from the end of the editor 3826// Only effective if text was removed from the end of the editor
3827// *NOTE: Using this will invalidate references to mSegments from mLineStartList.
3827void LLTextEditor::pruneSegments() 3828void LLTextEditor::pruneSegments()
3828{ 3829{
3829 S32 len = mWText.length(); 3830 S32 len = mWText.length();
@@ -4066,9 +4067,7 @@ BOOL LLTextEditor::importBuffer(const char* buffer, S32 length )
4066 setCursorPos(0); 4067 setCursorPos(0);
4067 deselect(); 4068 deselect();
4068 4069
4069 updateLineStartList(); 4070 needsReflow();
4070 updateScrollFromCursor();
4071
4072 return success; 4071 return success;
4073} 4072}
4074 4073
@@ -4496,9 +4495,8 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,
4496 4495
4497 mPreeditStandouts = preedit_standouts; 4496 mPreeditStandouts = preedit_standouts;
4498 4497
4499 updateLineStartList(); 4498 needsReflow();
4500 setCursorPos(insert_preedit_at + caret_position); 4499 setCursorPos(insert_preedit_at + caret_position);
4501 // updateScrollFromCursor();
4502 4500
4503 // Update of the preedit should be caused by some key strokes. 4501 // Update of the preedit should be caused by some key strokes.
4504 mKeystrokeTimer.reset(); 4502 mKeystrokeTimer.reset();