diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/llui/lltexteditor.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2 meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz |
Second Life viewer sources 1.19.1.0
Diffstat (limited to 'linden/indra/llui/lltexteditor.cpp')
-rw-r--r-- | linden/indra/llui/lltexteditor.cpp | 828 |
1 files changed, 362 insertions, 466 deletions
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp index 9061ca3..545fddb 100644 --- a/linden/indra/llui/lltexteditor.cpp +++ b/linden/indra/llui/lltexteditor.cpp | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | #include "llfontgl.h" | 38 | #include "llfontgl.h" |
39 | #include "llgl.h" | 39 | #include "llgl.h" |
40 | #include "llglimmediate.h" | ||
40 | #include "llui.h" | 41 | #include "llui.h" |
41 | #include "lluictrlfactory.h" | 42 | #include "lluictrlfactory.h" |
42 | #include "llrect.h" | 43 | #include "llrect.h" |
@@ -63,15 +64,12 @@ | |||
63 | // | 64 | // |
64 | // Globals | 65 | // Globals |
65 | // | 66 | // |
66 | |||
67 | BOOL gDebugTextEditorTips = FALSE; | 67 | BOOL gDebugTextEditorTips = FALSE; |
68 | 68 | ||
69 | // | 69 | // |
70 | // Constants | 70 | // Constants |
71 | // | 71 | // |
72 | |||
73 | const S32 UI_TEXTEDITOR_BUFFER_BLOCK_SIZE = 512; | 72 | const S32 UI_TEXTEDITOR_BUFFER_BLOCK_SIZE = 512; |
74 | |||
75 | const S32 UI_TEXTEDITOR_BORDER = 1; | 73 | const S32 UI_TEXTEDITOR_BORDER = 1; |
76 | const S32 UI_TEXTEDITOR_H_PAD = 4; | 74 | const S32 UI_TEXTEDITOR_H_PAD = 4; |
77 | const S32 UI_TEXTEDITOR_V_PAD_TOP = 4; | 75 | const S32 UI_TEXTEDITOR_V_PAD_TOP = 4; |
@@ -93,67 +91,33 @@ void (* LLTextEditor::mURLcallback)(const char*) = NULL; | |||
93 | bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; | 91 | bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; |
94 | bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; | 92 | bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; |
95 | 93 | ||
96 | /////////////////////////////////////////////////////////////////// | ||
97 | //virtuals | ||
98 | BOOL LLTextCmd::canExtend(S32 pos) | ||
99 | { | ||
100 | return FALSE; | ||
101 | } | ||
102 | |||
103 | void LLTextCmd::blockExtensions() | ||
104 | { | ||
105 | } | ||
106 | |||
107 | BOOL LLTextCmd::extendAndExecute( LLTextEditor* editor, S32 pos, llwchar c, S32* delta ) | ||
108 | { | ||
109 | llassert(0); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | BOOL LLTextCmd::hasExtCharValue( llwchar value ) | ||
114 | { | ||
115 | return FALSE; | ||
116 | } | ||
117 | |||
118 | // Utility funcs | ||
119 | S32 LLTextCmd::insert(LLTextEditor* editor, S32 pos, const LLWString &wstr) | ||
120 | { | ||
121 | return editor->insertStringNoUndo( pos, wstr ); | ||
122 | } | ||
123 | S32 LLTextCmd::remove(LLTextEditor* editor, S32 pos, S32 length) | ||
124 | { | ||
125 | return editor->removeStringNoUndo( pos, length ); | ||
126 | } | ||
127 | S32 LLTextCmd::overwrite(LLTextEditor* editor, S32 pos, llwchar wc) | ||
128 | { | ||
129 | return editor->overwriteCharNoUndo(pos, wc); | ||
130 | } | ||
131 | 94 | ||
132 | /////////////////////////////////////////////////////////////////// | 95 | /////////////////////////////////////////////////////////////////// |
133 | 96 | ||
134 | class LLTextCmdInsert : public LLTextCmd | 97 | class LLTextEditor::LLTextCmdInsert : public LLTextEditor::LLTextCmd |
135 | { | 98 | { |
136 | public: | 99 | public: |
137 | LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws) | 100 | LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws) |
138 | : LLTextCmd(pos, group_with_next), mWString(ws) | 101 | : LLTextCmd(pos, group_with_next), mWString(ws) |
139 | { | 102 | { |
140 | } | 103 | } |
104 | virtual ~LLTextCmdInsert() {} | ||
141 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) | 105 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) |
142 | { | 106 | { |
143 | *delta = insert(editor, mPos, mWString ); | 107 | *delta = insert(editor, getPosition(), mWString ); |
144 | LLWString::truncate(mWString, *delta); | 108 | LLWString::truncate(mWString, *delta); |
145 | //mWString = wstring_truncate(mWString, *delta); | 109 | //mWString = wstring_truncate(mWString, *delta); |
146 | return (*delta != 0); | 110 | return (*delta != 0); |
147 | } | 111 | } |
148 | virtual S32 undo( LLTextEditor* editor ) | 112 | virtual S32 undo( LLTextEditor* editor ) |
149 | { | 113 | { |
150 | remove(editor, mPos, mWString.length() ); | 114 | remove(editor, getPosition(), mWString.length() ); |
151 | return mPos; | 115 | return getPosition(); |
152 | } | 116 | } |
153 | virtual S32 redo( LLTextEditor* editor ) | 117 | virtual S32 redo( LLTextEditor* editor ) |
154 | { | 118 | { |
155 | insert(editor, mPos, mWString ); | 119 | insert(editor, getPosition(), mWString ); |
156 | return mPos + mWString.length(); | 120 | return getPosition() + mWString.length(); |
157 | } | 121 | } |
158 | 122 | ||
159 | private: | 123 | private: |
@@ -161,8 +125,7 @@ private: | |||
161 | }; | 125 | }; |
162 | 126 | ||
163 | /////////////////////////////////////////////////////////////////// | 127 | /////////////////////////////////////////////////////////////////// |
164 | 128 | class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd | |
165 | class LLTextCmdAddChar : public LLTextCmd | ||
166 | { | 129 | { |
167 | public: | 130 | public: |
168 | LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc) | 131 | LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc) |
@@ -173,13 +136,13 @@ public: | |||
173 | { | 136 | { |
174 | mBlockExtensions = TRUE; | 137 | mBlockExtensions = TRUE; |
175 | } | 138 | } |
176 | virtual BOOL canExtend(S32 pos) | 139 | virtual BOOL canExtend(S32 pos) const |
177 | { | 140 | { |
178 | return !mBlockExtensions && (pos == mPos + (S32)mWString.length()); | 141 | return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); |
179 | } | 142 | } |
180 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) | 143 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) |
181 | { | 144 | { |
182 | *delta = insert(editor, mPos, mWString); | 145 | *delta = insert(editor, getPosition(), mWString); |
183 | LLWString::truncate(mWString, *delta); | 146 | LLWString::truncate(mWString, *delta); |
184 | //mWString = wstring_truncate(mWString, *delta); | 147 | //mWString = wstring_truncate(mWString, *delta); |
185 | return (*delta != 0); | 148 | return (*delta != 0); |
@@ -198,13 +161,13 @@ public: | |||
198 | } | 161 | } |
199 | virtual S32 undo( LLTextEditor* editor ) | 162 | virtual S32 undo( LLTextEditor* editor ) |
200 | { | 163 | { |
201 | remove(editor, mPos, mWString.length() ); | 164 | remove(editor, getPosition(), mWString.length() ); |
202 | return mPos; | 165 | return getPosition(); |
203 | } | 166 | } |
204 | virtual S32 redo( LLTextEditor* editor ) | 167 | virtual S32 redo( LLTextEditor* editor ) |
205 | { | 168 | { |
206 | insert(editor, mPos, mWString ); | 169 | insert(editor, getPosition(), mWString ); |
207 | return mPos + mWString.length(); | 170 | return getPosition() + mWString.length(); |
208 | } | 171 | } |
209 | 172 | ||
210 | private: | 173 | private: |
@@ -215,7 +178,7 @@ private: | |||
215 | 178 | ||
216 | /////////////////////////////////////////////////////////////////// | 179 | /////////////////////////////////////////////////////////////////// |
217 | 180 | ||
218 | class LLTextCmdOverwriteChar : public LLTextCmd | 181 | class LLTextEditor::LLTextCmdOverwriteChar : public LLTextEditor::LLTextCmd |
219 | { | 182 | { |
220 | public: | 183 | public: |
221 | LLTextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) | 184 | LLTextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) |
@@ -223,20 +186,20 @@ public: | |||
223 | 186 | ||
224 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) | 187 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) |
225 | { | 188 | { |
226 | mOldChar = editor->getWChar(mPos); | 189 | mOldChar = editor->getWChar(getPosition()); |
227 | overwrite(editor, mPos, mChar); | 190 | overwrite(editor, getPosition(), mChar); |
228 | *delta = 0; | 191 | *delta = 0; |
229 | return TRUE; | 192 | return TRUE; |
230 | } | 193 | } |
231 | virtual S32 undo( LLTextEditor* editor ) | 194 | virtual S32 undo( LLTextEditor* editor ) |
232 | { | 195 | { |
233 | overwrite(editor, mPos, mOldChar); | 196 | overwrite(editor, getPosition(), mOldChar); |
234 | return mPos; | 197 | return getPosition(); |
235 | } | 198 | } |
236 | virtual S32 redo( LLTextEditor* editor ) | 199 | virtual S32 redo( LLTextEditor* editor ) |
237 | { | 200 | { |
238 | overwrite(editor, mPos, mChar); | 201 | overwrite(editor, getPosition(), mChar); |
239 | return mPos+1; | 202 | return getPosition()+1; |
240 | } | 203 | } |
241 | 204 | ||
242 | private: | 205 | private: |
@@ -246,7 +209,7 @@ private: | |||
246 | 209 | ||
247 | /////////////////////////////////////////////////////////////////// | 210 | /////////////////////////////////////////////////////////////////// |
248 | 211 | ||
249 | class LLTextCmdRemove : public LLTextCmd | 212 | class LLTextEditor::LLTextCmdRemove : public LLTextEditor::LLTextCmd |
250 | { | 213 | { |
251 | public: | 214 | public: |
252 | LLTextCmdRemove( S32 pos, BOOL group_with_next, S32 len ) : | 215 | LLTextCmdRemove( S32 pos, BOOL group_with_next, S32 len ) : |
@@ -255,30 +218,27 @@ public: | |||
255 | } | 218 | } |
256 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) | 219 | virtual BOOL execute( LLTextEditor* editor, S32* delta ) |
257 | { | 220 | { |
258 | mWString = editor->getWSubString(mPos, mLen); | 221 | mWString = editor->getWSubString(getPosition(), mLen); |
259 | *delta = remove(editor, mPos, mLen ); | 222 | *delta = remove(editor, getPosition(), mLen ); |
260 | return (*delta != 0); | 223 | return (*delta != 0); |
261 | } | 224 | } |
262 | virtual S32 undo( LLTextEditor* editor ) | 225 | virtual S32 undo( LLTextEditor* editor ) |
263 | { | 226 | { |
264 | insert(editor, mPos, mWString ); | 227 | insert(editor, getPosition(), mWString ); |
265 | return mPos + mWString.length(); | 228 | return getPosition() + mWString.length(); |
266 | } | 229 | } |
267 | virtual S32 redo( LLTextEditor* editor ) | 230 | virtual S32 redo( LLTextEditor* editor ) |
268 | { | 231 | { |
269 | remove(editor, mPos, mLen ); | 232 | remove(editor, getPosition(), mLen ); |
270 | return mPos; | 233 | return getPosition(); |
271 | } | 234 | } |
272 | private: | 235 | private: |
273 | LLWString mWString; | 236 | LLWString mWString; |
274 | S32 mLen; | 237 | S32 mLen; |
275 | }; | 238 | }; |
276 | 239 | ||
277 | /////////////////////////////////////////////////////////////////// | ||
278 | 240 | ||
279 | // | 241 | /////////////////////////////////////////////////////////////////// |
280 | // Member functions | ||
281 | // | ||
282 | 242 | ||
283 | LLTextEditor::LLTextEditor( | 243 | LLTextEditor::LLTextEditor( |
284 | const LLString& name, | 244 | const LLString& name, |
@@ -309,7 +269,7 @@ LLTextEditor::LLTextEditor( | |||
309 | mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ), | 269 | mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ), |
310 | mReadOnly(FALSE), | 270 | mReadOnly(FALSE), |
311 | mWordWrap( FALSE ), | 271 | mWordWrap( FALSE ), |
312 | mTabToNextField( TRUE ), | 272 | mTabsToNextField( TRUE ), |
313 | mCommitOnFocusLost( FALSE ), | 273 | mCommitOnFocusLost( FALSE ), |
314 | mHideScrollbarForShortDocs( FALSE ), | 274 | mHideScrollbarForShortDocs( FALSE ), |
315 | mTakesNonScrollClicks( TRUE ), | 275 | mTakesNonScrollClicks( TRUE ), |
@@ -344,10 +304,10 @@ LLTextEditor::LLTextEditor( | |||
344 | // Init the scrollbar | 304 | // Init the scrollbar |
345 | LLRect scroll_rect; | 305 | LLRect scroll_rect; |
346 | scroll_rect.setOriginAndSize( | 306 | scroll_rect.setOriginAndSize( |
347 | mRect.getWidth() - UI_TEXTEDITOR_BORDER - SCROLLBAR_SIZE, | 307 | getRect().getWidth() - UI_TEXTEDITOR_BORDER - SCROLLBAR_SIZE, |
348 | UI_TEXTEDITOR_BORDER, | 308 | UI_TEXTEDITOR_BORDER, |
349 | SCROLLBAR_SIZE, | 309 | SCROLLBAR_SIZE, |
350 | mRect.getHeight() - 2 * UI_TEXTEDITOR_BORDER ); | 310 | getRect().getHeight() - 2 * UI_TEXTEDITOR_BORDER ); |
351 | S32 lines_in_doc = getLineCount(); | 311 | S32 lines_in_doc = getLineCount(); |
352 | mScrollbar = new LLScrollbar( "Scrollbar", scroll_rect, | 312 | mScrollbar = new LLScrollbar( "Scrollbar", scroll_rect, |
353 | LLScrollbar::VERTICAL, | 313 | LLScrollbar::VERTICAL, |
@@ -363,7 +323,7 @@ LLTextEditor::LLTextEditor( | |||
363 | mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData); | 323 | mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData); |
364 | addChild(mScrollbar); | 324 | addChild(mScrollbar); |
365 | 325 | ||
366 | mBorder = new LLViewBorder( "text ed border", LLRect(0, mRect.getHeight(), mRect.getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); | 326 | mBorder = new LLViewBorder( "text ed border", LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); |
367 | addChild( mBorder ); | 327 | addChild( mBorder ); |
368 | 328 | ||
369 | appendText(default_text, FALSE, FALSE); | 329 | appendText(default_text, FALSE, FALSE); |
@@ -392,12 +352,6 @@ LLTextEditor::~LLTextEditor() | |||
392 | std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); | 352 | std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); |
393 | } | 353 | } |
394 | 354 | ||
395 | //virtual | ||
396 | LLString LLTextEditor::getWidgetTag() const | ||
397 | { | ||
398 | return LL_TEXT_EDITOR_TAG; | ||
399 | } | ||
400 | |||
401 | void LLTextEditor::setTrackColor( const LLColor4& color ) | 355 | void LLTextEditor::setTrackColor( const LLColor4& color ) |
402 | { | 356 | { |
403 | mScrollbar->setTrackColor(color); | 357 | mScrollbar->setTrackColor(color); |
@@ -422,7 +376,7 @@ void LLTextEditor::updateLineStartList(S32 startpos) | |||
422 | { | 376 | { |
423 | updateSegments(); | 377 | updateSegments(); |
424 | 378 | ||
425 | bindEmbeddedChars( mGLFont ); | 379 | bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
426 | 380 | ||
427 | S32 seg_num = mSegments.size(); | 381 | S32 seg_num = mSegments.size(); |
428 | S32 seg_idx = 0; | 382 | S32 seg_idx = 0; |
@@ -471,7 +425,7 @@ void LLTextEditor::updateLineStartList(S32 startpos) | |||
471 | else | 425 | else |
472 | { | 426 | { |
473 | const llwchar* str = mWText.c_str() + start_idx; | 427 | const llwchar* str = mWText.c_str() + start_idx; |
474 | S32 drawn = mGLFont->maxDrawableChars(str, (F32)mTextRect.getWidth() - line_width, | 428 | S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width, |
475 | end_idx - start_idx, mWordWrap, mAllowEmbeddedItems ); | 429 | end_idx - start_idx, mWordWrap, mAllowEmbeddedItems ); |
476 | if( 0 == drawn && line_width == 0) | 430 | if( 0 == drawn && line_width == 0) |
477 | { | 431 | { |
@@ -499,7 +453,7 @@ void LLTextEditor::updateLineStartList(S32 startpos) | |||
499 | } | 453 | } |
500 | } | 454 | } |
501 | 455 | ||
502 | unbindEmbeddedChars(mGLFont); | 456 | unbindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); |
503 | 457 | ||
504 | mScrollbar->setDocSize( getLineCount() ); | 458 | mScrollbar->setDocSize( getLineCount() ); |
505 | 459 | ||
@@ -515,11 +469,6 @@ void LLTextEditor::updateLineStartList(S32 startpos) | |||
515 | // LLTextEditor | 469 | // LLTextEditor |
516 | // Public methods | 470 | // Public methods |
517 | 471 | ||
518 | //static | ||
519 | BOOL LLTextEditor::isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); } | ||
520 | |||
521 | |||
522 | |||
523 | BOOL LLTextEditor::truncate() | 472 | BOOL LLTextEditor::truncate() |
524 | { | 473 | { |
525 | BOOL did_truncate = FALSE; | 474 | BOOL did_truncate = FALSE; |
@@ -581,6 +530,7 @@ void LLTextEditor::setWText(const LLWString &wtext) | |||
581 | resetDirty(); | 530 | resetDirty(); |
582 | } | 531 | } |
583 | 532 | ||
533 | // virtual | ||
584 | void LLTextEditor::setValue(const LLSD& value) | 534 | void LLTextEditor::setValue(const LLSD& value) |
585 | { | 535 | { |
586 | setText(value.asString()); | 536 | setText(value.asString()); |
@@ -600,6 +550,7 @@ const LLString& LLTextEditor::getText() const | |||
600 | return mUTF8Text; | 550 | return mUTF8Text; |
601 | } | 551 | } |
602 | 552 | ||
553 | // virtual | ||
603 | LLSD LLTextEditor::getValue() const | 554 | LLSD LLTextEditor::getValue() const |
604 | { | 555 | { |
605 | return LLSD(getText()); | 556 | return LLSD(getText()); |
@@ -622,7 +573,10 @@ void LLTextEditor::setBorderVisible(BOOL b) | |||
622 | mBorder->setVisible(b); | 573 | mBorder->setVisible(b); |
623 | } | 574 | } |
624 | 575 | ||
625 | 576 | BOOL LLTextEditor::isBorderVisible() const | |
577 | { | ||
578 | return mBorder->getVisible(); | ||
579 | } | ||
626 | 580 | ||
627 | void LLTextEditor::setHideScrollbarForShortDocs(BOOL b) | 581 | void LLTextEditor::setHideScrollbarForShortDocs(BOOL b) |
628 | { | 582 | { |
@@ -734,12 +688,6 @@ void LLTextEditor::replaceTextAll(const LLString& search_text, const LLString& r | |||
734 | mScrollbar->setDocPos(cur_pos); | 688 | mScrollbar->setDocPos(cur_pos); |
735 | } | 689 | } |
736 | 690 | ||
737 | void LLTextEditor::setTakesNonScrollClicks(BOOL b) | ||
738 | { | ||
739 | mTakesNonScrollClicks = b; | ||
740 | } | ||
741 | |||
742 | |||
743 | // Picks a new cursor position based on the screen size of text being drawn. | 691 | // Picks a new cursor position based on the screen size of text being drawn. |
744 | void LLTextEditor::setCursorAtLocalPos( S32 local_x, S32 local_y, BOOL round ) | 692 | void LLTextEditor::setCursorAtLocalPos( S32 local_x, S32 local_y, BOOL round ) |
745 | { | 693 | { |
@@ -774,11 +722,6 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const | |||
774 | return cursorPos; | 722 | return cursorPos; |
775 | } | 723 | } |
776 | 724 | ||
777 | S32 LLTextEditor::getLineCount() const | ||
778 | { | ||
779 | return mLineStartList.size(); | ||
780 | } | ||
781 | |||
782 | S32 LLTextEditor::getLineStart( S32 line ) const | 725 | S32 LLTextEditor::getLineStart( S32 line ) const |
783 | { | 726 | { |
784 | S32 num_lines = getLineCount(); | 727 | S32 num_lines = getLineCount(); |
@@ -796,7 +739,7 @@ S32 LLTextEditor::getLineStart( S32 line ) const | |||
796 | } | 739 | } |
797 | 740 | ||
798 | // Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line. | 741 | // Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line. |
799 | void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp ) | 742 | void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp ) const |
800 | { | 743 | { |
801 | if (mLineStartList.empty()) | 744 | if (mLineStartList.empty()) |
802 | { | 745 | { |
@@ -809,7 +752,7 @@ void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp ) | |||
809 | getSegmentAndOffset( startpos, &seg_idx, &seg_offset ); | 752 | getSegmentAndOffset( startpos, &seg_idx, &seg_offset ); |
810 | 753 | ||
811 | line_info tline(seg_idx, seg_offset); | 754 | line_info tline(seg_idx, seg_offset); |
812 | line_list_t::iterator iter = std::upper_bound(mLineStartList.begin(), mLineStartList.end(), tline, line_info_compare()); | 755 | line_list_t::const_iterator iter = std::upper_bound(mLineStartList.begin(), mLineStartList.end(), tline, line_info_compare()); |
813 | if (iter != mLineStartList.begin()) --iter; | 756 | if (iter != mLineStartList.begin()) --iter; |
814 | *linep = iter - mLineStartList.begin(); | 757 | *linep = iter - mLineStartList.begin(); |
815 | S32 line_start = mSegments[iter->mSegment]->getStart() + iter->mOffset; | 758 | S32 line_start = mSegments[iter->mSegment]->getStart() + iter->mOffset; |
@@ -817,7 +760,7 @@ void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp ) | |||
817 | } | 760 | } |
818 | } | 761 | } |
819 | 762 | ||
820 | void LLTextEditor::getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) | 763 | void LLTextEditor::getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const |
821 | { | 764 | { |
822 | if (mSegments.empty()) | 765 | if (mSegments.empty()) |
823 | { | 766 | { |
@@ -826,46 +769,21 @@ void LLTextEditor::getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp | |||
826 | } | 769 | } |
827 | 770 | ||
828 | LLTextSegment tseg(startpos); | 771 | LLTextSegment tseg(startpos); |
829 | segment_list_t::iterator seg_iter; | 772 | segment_list_t::const_iterator seg_iter; |
830 | seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &tseg, LLTextSegment::compare()); | 773 | seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &tseg, LLTextSegment::compare()); |
831 | if (seg_iter != mSegments.begin()) --seg_iter; | 774 | if (seg_iter != mSegments.begin()) --seg_iter; |
832 | *segidxp = seg_iter - mSegments.begin(); | 775 | *segidxp = seg_iter - mSegments.begin(); |
833 | *offsetp = startpos - (*seg_iter)->getStart(); | 776 | *offsetp = startpos - (*seg_iter)->getStart(); |
834 | } | 777 | } |
835 | 778 | ||
836 | const LLWString& LLTextEditor::getWText() const | 779 | const LLTextSegment* LLTextEditor::getPreviousSegment() |
837 | { | ||
838 | return mWText; | ||
839 | } | ||
840 | |||
841 | S32 LLTextEditor::getLength() const | ||
842 | { | ||
843 | return mWText.length(); | ||
844 | } | ||
845 | |||
846 | llwchar LLTextEditor::getWChar(S32 pos) | ||
847 | { | ||
848 | return mWText[pos]; | ||
849 | } | ||
850 | |||
851 | LLWString LLTextEditor::getWSubString(S32 pos, S32 len) | ||
852 | { | ||
853 | return mWText.substr(pos, len); | ||
854 | } | ||
855 | |||
856 | LLTextSegment* LLTextEditor::getCurrentSegment() | ||
857 | { | ||
858 | return getSegmentAtOffset(mCursorPos); | ||
859 | } | ||
860 | |||
861 | LLTextSegment* LLTextEditor::getPreviousSegment() | ||
862 | { | 780 | { |
863 | // find segment index at character to left of cursor (or rightmost edge of selection) | 781 | // find segment index at character to left of cursor (or rightmost edge of selection) |
864 | S32 idx = llmax(0, getSegmentIdxAtOffset(mCursorPos) - 1); | 782 | S32 idx = llmax(0, getSegmentIdxAtOffset(mCursorPos) - 1); |
865 | return idx >= 0 ? mSegments[idx] : NULL; | 783 | return idx >= 0 ? mSegments[idx] : NULL; |
866 | } | 784 | } |
867 | 785 | ||
868 | void LLTextEditor::getSelectedSegments(std::vector<LLTextSegment*>& segments) | 786 | void LLTextEditor::getSelectedSegments(std::vector<const LLTextSegment*>& segments) |
869 | { | 787 | { |
870 | S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; | 788 | S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; |
871 | S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; | 789 | S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; |
@@ -878,7 +796,7 @@ void LLTextEditor::getSelectedSegments(std::vector<LLTextSegment*>& segments) | |||
878 | } | 796 | } |
879 | } | 797 | } |
880 | 798 | ||
881 | S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) | 799 | S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const |
882 | { | 800 | { |
883 | // If round is true, if the position is on the right half of a character, the cursor | 801 | // If round is true, if the position is on the right half of a character, the cursor |
884 | // will be put to its right. If round is false, the cursor will always be put to the | 802 | // will be put to its right. If round is false, the cursor will always be put to the |
@@ -916,13 +834,13 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou | |||
916 | if (mAllowEmbeddedItems) | 834 | if (mAllowEmbeddedItems) |
917 | { | 835 | { |
918 | // Figure out which character we're nearest to. | 836 | // Figure out which character we're nearest to. |
919 | bindEmbeddedChars(mGLFont); | 837 | bindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); |
920 | pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start, | 838 | pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start, |
921 | (F32)(local_x - mTextRect.mLeft), | 839 | (F32)(local_x - mTextRect.mLeft), |
922 | (F32)(mTextRect.getWidth()), | 840 | (F32)(mTextRect.getWidth()), |
923 | line_len, | 841 | line_len, |
924 | round, TRUE); | 842 | round, TRUE); |
925 | unbindEmbeddedChars(mGLFont); | 843 | unbindEmbeddedChars(const_cast<LLFontGL*>(mGLFont)); |
926 | } | 844 | } |
927 | else | 845 | else |
928 | { | 846 | { |
@@ -958,8 +876,8 @@ void LLTextEditor::setCursorPos(S32 offset) | |||
958 | mDesiredXPixel = -1; | 876 | mDesiredXPixel = -1; |
959 | } | 877 | } |
960 | 878 | ||
961 | 879 | // virtual | |
962 | BOOL LLTextEditor::canDeselect() | 880 | BOOL LLTextEditor::canDeselect() const |
963 | { | 881 | { |
964 | return hasSelection(); | 882 | return hasSelection(); |
965 | } | 883 | } |
@@ -1126,12 +1044,13 @@ void LLTextEditor::indentSelectedLines( S32 spaces ) | |||
1126 | } | 1044 | } |
1127 | } | 1045 | } |
1128 | 1046 | ||
1129 | 1047 | //virtual | |
1130 | BOOL LLTextEditor::canSelectAll() | 1048 | BOOL LLTextEditor::canSelectAll() const |
1131 | { | 1049 | { |
1132 | return TRUE; | 1050 | return TRUE; |
1133 | } | 1051 | } |
1134 | 1052 | ||
1053 | // virtual | ||
1135 | void LLTextEditor::selectAll() | 1054 | void LLTextEditor::selectAll() |
1136 | { | 1055 | { |
1137 | mSelectionStart = getLength(); | 1056 | mSelectionStart = getLength(); |
@@ -1143,7 +1062,7 @@ void LLTextEditor::selectAll() | |||
1143 | BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) | 1062 | BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) |
1144 | { | 1063 | { |
1145 | for ( child_list_const_iter_t child_it = getChildList()->begin(); | 1064 | for ( child_list_const_iter_t child_it = getChildList()->begin(); |
1146 | child_it != getChildList()->end(); ++child_it) | 1065 | child_it != getChildList()->end(); ++child_it) |
1147 | { | 1066 | { |
1148 | LLView* viewp = *child_it; | 1067 | LLView* viewp = *child_it; |
1149 | S32 local_x = x - viewp->getRect().mLeft; | 1068 | S32 local_x = x - viewp->getRect().mLeft; |
@@ -1159,7 +1078,7 @@ BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rec | |||
1159 | return TRUE; | 1078 | return TRUE; |
1160 | } | 1079 | } |
1161 | 1080 | ||
1162 | LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); | 1081 | const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); |
1163 | if( cur_segment ) | 1082 | if( cur_segment ) |
1164 | { | 1083 | { |
1165 | BOOL has_tool_tip = FALSE; | 1084 | BOOL has_tool_tip = FALSE; |
@@ -1267,7 +1186,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) | |||
1267 | } | 1186 | } |
1268 | 1187 | ||
1269 | // Delay cursor flashing | 1188 | // Delay cursor flashing |
1270 | mKeystrokeTimer.reset(); | 1189 | resetKeystrokeTimer(); |
1271 | 1190 | ||
1272 | return handled; | 1191 | return handled; |
1273 | } | 1192 | } |
@@ -1320,7 +1239,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) | |||
1320 | if( handled ) | 1239 | if( handled ) |
1321 | { | 1240 | { |
1322 | // Delay cursor flashing | 1241 | // Delay cursor flashing |
1323 | mKeystrokeTimer.reset(); | 1242 | resetKeystrokeTimer(); |
1324 | } | 1243 | } |
1325 | 1244 | ||
1326 | // Opaque | 1245 | // Opaque |
@@ -1329,7 +1248,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) | |||
1329 | // Check to see if we're over an HTML-style link | 1248 | // Check to see if we're over an HTML-style link |
1330 | if( !mSegments.empty() ) | 1249 | if( !mSegments.empty() ) |
1331 | { | 1250 | { |
1332 | LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); | 1251 | const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); |
1333 | if( cur_segment ) | 1252 | if( cur_segment ) |
1334 | { | 1253 | { |
1335 | if(cur_segment->getStyle().isLink()) | 1254 | if(cur_segment->getStyle().isLink()) |
@@ -1353,7 +1272,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) | |||
1353 | if( !handled ) | 1272 | if( !handled ) |
1354 | { | 1273 | { |
1355 | lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; | 1274 | lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; |
1356 | if (!mScrollbar->getVisible() || x < mRect.getWidth() - SCROLLBAR_SIZE) | 1275 | if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE) |
1357 | { | 1276 | { |
1358 | getWindow()->setCursor(UI_CURSOR_IBEAM); | 1277 | getWindow()->setCursor(UI_CURSOR_IBEAM); |
1359 | } | 1278 | } |
@@ -1411,7 +1330,7 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) | |||
1411 | } | 1330 | } |
1412 | 1331 | ||
1413 | // Delay cursor flashing | 1332 | // Delay cursor flashing |
1414 | mKeystrokeTimer.reset(); | 1333 | resetKeystrokeTimer(); |
1415 | 1334 | ||
1416 | if( hasMouseCapture() ) | 1335 | if( hasMouseCapture() ) |
1417 | { | 1336 | { |
@@ -1467,7 +1386,7 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) | |||
1467 | mIsSelecting = FALSE; | 1386 | mIsSelecting = FALSE; |
1468 | 1387 | ||
1469 | // delay cursor flashing | 1388 | // delay cursor flashing |
1470 | mKeystrokeTimer.reset(); | 1389 | resetKeystrokeTimer(); |
1471 | 1390 | ||
1472 | handled = TRUE; | 1391 | handled = TRUE; |
1473 | } | 1392 | } |
@@ -1548,50 +1467,51 @@ S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) | |||
1548 | // a pseudo-tab (up to for spaces in a row) | 1467 | // a pseudo-tab (up to for spaces in a row) |
1549 | void LLTextEditor::removeCharOrTab() | 1468 | void LLTextEditor::removeCharOrTab() |
1550 | { | 1469 | { |
1551 | if( getEnabled() ) | 1470 | if( !getEnabled() ) |
1552 | { | 1471 | { |
1553 | if( mCursorPos > 0 ) | 1472 | return; |
1554 | { | 1473 | } |
1555 | S32 chars_to_remove = 1; | 1474 | if( mCursorPos > 0 ) |
1475 | { | ||
1476 | S32 chars_to_remove = 1; | ||
1556 | 1477 | ||
1557 | const LLWString &text = mWText; | 1478 | const LLWString &text = mWText; |
1558 | if (text[mCursorPos - 1] == ' ') | 1479 | if (text[mCursorPos - 1] == ' ') |
1480 | { | ||
1481 | // Try to remove a "tab" | ||
1482 | S32 line, offset; | ||
1483 | getLineAndOffset(mCursorPos, &line, &offset); | ||
1484 | if (offset > 0) | ||
1559 | { | 1485 | { |
1560 | // Try to remove a "tab" | 1486 | chars_to_remove = offset % SPACES_PER_TAB; |
1561 | S32 line, offset; | 1487 | if( chars_to_remove == 0 ) |
1562 | getLineAndOffset(mCursorPos, &line, &offset); | ||
1563 | if (offset > 0) | ||
1564 | { | 1488 | { |
1565 | chars_to_remove = offset % SPACES_PER_TAB; | 1489 | chars_to_remove = SPACES_PER_TAB; |
1566 | if( chars_to_remove == 0 ) | 1490 | } |
1567 | { | ||
1568 | chars_to_remove = SPACES_PER_TAB; | ||
1569 | } | ||
1570 | 1491 | ||
1571 | for( S32 i = 0; i < chars_to_remove; i++ ) | 1492 | for( S32 i = 0; i < chars_to_remove; i++ ) |
1493 | { | ||
1494 | if (text[ mCursorPos - i - 1] != ' ') | ||
1572 | { | 1495 | { |
1573 | if (text[ mCursorPos - i - 1] != ' ') | 1496 | // Fewer than a full tab's worth of spaces, so |
1574 | { | 1497 | // just delete a single character. |
1575 | // Fewer than a full tab's worth of spaces, so | 1498 | chars_to_remove = 1; |
1576 | // just delete a single character. | 1499 | break; |
1577 | chars_to_remove = 1; | ||
1578 | break; | ||
1579 | } | ||
1580 | } | 1500 | } |
1581 | } | 1501 | } |
1582 | } | 1502 | } |
1583 | |||
1584 | for (S32 i = 0; i < chars_to_remove; i++) | ||
1585 | { | ||
1586 | setCursorPos(mCursorPos - 1); | ||
1587 | remove( mCursorPos, 1, FALSE ); | ||
1588 | } | ||
1589 | } | 1503 | } |
1590 | else | 1504 | |
1505 | for (S32 i = 0; i < chars_to_remove; i++) | ||
1591 | { | 1506 | { |
1592 | reportBadKeystroke(); | 1507 | setCursorPos(mCursorPos - 1); |
1508 | remove( mCursorPos, 1, FALSE ); | ||
1593 | } | 1509 | } |
1594 | } | 1510 | } |
1511 | else | ||
1512 | { | ||
1513 | reportBadKeystroke(); | ||
1514 | } | ||
1595 | } | 1515 | } |
1596 | 1516 | ||
1597 | // Remove a single character from the text | 1517 | // Remove a single character from the text |
@@ -1602,17 +1522,18 @@ S32 LLTextEditor::removeChar(S32 pos) | |||
1602 | 1522 | ||
1603 | void LLTextEditor::removeChar() | 1523 | void LLTextEditor::removeChar() |
1604 | { | 1524 | { |
1605 | if (getEnabled()) | 1525 | if (!getEnabled()) |
1606 | { | 1526 | { |
1607 | if (mCursorPos > 0) | 1527 | return; |
1608 | { | 1528 | } |
1609 | setCursorPos(mCursorPos - 1); | 1529 | if (mCursorPos > 0) |
1610 | removeChar(mCursorPos); | 1530 | { |
1611 | } | 1531 | setCursorPos(mCursorPos - 1); |
1612 | else | 1532 | removeChar(mCursorPos); |
1613 | { | 1533 | } |
1614 | reportBadKeystroke(); | 1534 | else |
1615 | } | 1535 | { |
1536 | reportBadKeystroke(); | ||
1616 | } | 1537 | } |
1617 | } | 1538 | } |
1618 | 1539 | ||
@@ -1639,19 +1560,20 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) | |||
1639 | 1560 | ||
1640 | void LLTextEditor::addChar(llwchar wc) | 1561 | void LLTextEditor::addChar(llwchar wc) |
1641 | { | 1562 | { |
1642 | if( getEnabled() ) | 1563 | if( !getEnabled() ) |
1643 | { | 1564 | { |
1644 | if( hasSelection() ) | 1565 | return; |
1645 | { | ||
1646 | deleteSelection(TRUE); | ||
1647 | } | ||
1648 | else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) | ||
1649 | { | ||
1650 | removeChar(mCursorPos); | ||
1651 | } | ||
1652 | |||
1653 | setCursorPos(mCursorPos + addChar( mCursorPos, wc )); | ||
1654 | } | 1566 | } |
1567 | if( hasSelection() ) | ||
1568 | { | ||
1569 | deleteSelection(TRUE); | ||
1570 | } | ||
1571 | else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) | ||
1572 | { | ||
1573 | removeChar(mCursorPos); | ||
1574 | } | ||
1575 | |||
1576 | setCursorPos(mCursorPos + addChar( mCursorPos, wc )); | ||
1655 | } | 1577 | } |
1656 | 1578 | ||
1657 | 1579 | ||
@@ -1747,7 +1669,6 @@ BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) | |||
1747 | } | 1669 | } |
1748 | } | 1670 | } |
1749 | 1671 | ||
1750 | |||
1751 | if( !handled && mHandleEditKeysDirectly ) | 1672 | if( !handled && mHandleEditKeysDirectly ) |
1752 | { | 1673 | { |
1753 | if( (MASK_CONTROL & mask) && ('A' == key) ) | 1674 | if( (MASK_CONTROL & mask) && ('A' == key) ) |
@@ -1900,7 +1821,8 @@ void LLTextEditor::deleteSelection(BOOL group_with_next_op ) | |||
1900 | } | 1821 | } |
1901 | } | 1822 | } |
1902 | 1823 | ||
1903 | BOOL LLTextEditor::canCut() | 1824 | // virtual |
1825 | BOOL LLTextEditor::canCut() const | ||
1904 | { | 1826 | { |
1905 | return !mReadOnly && hasSelection(); | 1827 | return !mReadOnly && hasSelection(); |
1906 | } | 1828 | } |
@@ -1908,36 +1830,37 @@ BOOL LLTextEditor::canCut() | |||
1908 | // cut selection to clipboard | 1830 | // cut selection to clipboard |
1909 | void LLTextEditor::cut() | 1831 | void LLTextEditor::cut() |
1910 | { | 1832 | { |
1911 | if( canCut() ) | 1833 | if( !canCut() ) |
1912 | { | 1834 | { |
1913 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); | 1835 | return; |
1914 | S32 length = abs( mSelectionStart - mSelectionEnd ); | ||
1915 | gClipboard.copyFromSubstring( mWText, left_pos, length, mSourceID ); | ||
1916 | deleteSelection( FALSE ); | ||
1917 | |||
1918 | updateLineStartList(); | ||
1919 | updateScrollFromCursor(); | ||
1920 | } | 1836 | } |
1837 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); | ||
1838 | S32 length = abs( mSelectionStart - mSelectionEnd ); | ||
1839 | gClipboard.copyFromSubstring( mWText, left_pos, length, mSourceID ); | ||
1840 | deleteSelection( FALSE ); | ||
1841 | |||
1842 | updateLineStartList(); | ||
1843 | updateScrollFromCursor(); | ||
1921 | } | 1844 | } |
1922 | 1845 | ||
1923 | BOOL LLTextEditor::canCopy() | 1846 | BOOL LLTextEditor::canCopy() const |
1924 | { | 1847 | { |
1925 | return hasSelection(); | 1848 | return hasSelection(); |
1926 | } | 1849 | } |
1927 | 1850 | ||
1928 | |||
1929 | // copy selection to clipboard | 1851 | // copy selection to clipboard |
1930 | void LLTextEditor::copy() | 1852 | void LLTextEditor::copy() |
1931 | { | 1853 | { |
1932 | if( canCopy() ) | 1854 | if( !canCopy() ) |
1933 | { | 1855 | { |
1934 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); | 1856 | return; |
1935 | S32 length = abs( mSelectionStart - mSelectionEnd ); | ||
1936 | gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); | ||
1937 | } | 1857 | } |
1858 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); | ||
1859 | S32 length = abs( mSelectionStart - mSelectionEnd ); | ||
1860 | gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); | ||
1938 | } | 1861 | } |
1939 | 1862 | ||
1940 | BOOL LLTextEditor::canPaste() | 1863 | BOOL LLTextEditor::canPaste() const |
1941 | { | 1864 | { |
1942 | return !mReadOnly && gClipboard.canPasteString(); | 1865 | return !mReadOnly && gClipboard.canPasteString(); |
1943 | } | 1866 | } |
@@ -1946,47 +1869,49 @@ BOOL LLTextEditor::canPaste() | |||
1946 | // paste from clipboard | 1869 | // paste from clipboard |
1947 | void LLTextEditor::paste() | 1870 | void LLTextEditor::paste() |
1948 | { | 1871 | { |
1949 | if (canPaste()) | 1872 | if (!canPaste()) |
1873 | { | ||
1874 | return; | ||
1875 | } | ||
1876 | LLUUID source_id; | ||
1877 | LLWString paste = gClipboard.getPasteWString(&source_id); | ||
1878 | if (paste.empty()) | ||
1950 | { | 1879 | { |
1951 | LLUUID source_id; | 1880 | return; |
1952 | LLWString paste = gClipboard.getPasteWString(&source_id); | 1881 | } |
1953 | if (!paste.empty()) | 1882 | // Delete any selected characters (the paste replaces them) |
1883 | if( hasSelection() ) | ||
1884 | { | ||
1885 | deleteSelection(TRUE); | ||
1886 | } | ||
1887 | |||
1888 | // Clean up string (replace tabs and remove characters that our fonts don't support). | ||
1889 | LLWString clean_string(paste); | ||
1890 | LLWString::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); | ||
1891 | if( mAllowEmbeddedItems ) | ||
1892 | { | ||
1893 | const llwchar LF = 10; | ||
1894 | S32 len = clean_string.length(); | ||
1895 | for( S32 i = 0; i < len; i++ ) | ||
1954 | { | 1896 | { |
1955 | // Delete any selected characters (the paste replaces them) | 1897 | llwchar wc = clean_string[i]; |
1956 | if( hasSelection() ) | 1898 | if( (wc < LLFont::FIRST_CHAR) && (wc != LF) ) |
1957 | { | 1899 | { |
1958 | deleteSelection(TRUE); | 1900 | clean_string[i] = LL_UNKNOWN_CHAR; |
1959 | } | 1901 | } |
1960 | 1902 | else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) | |
1961 | // Clean up string (replace tabs and remove characters that our fonts don't support). | ||
1962 | LLWString clean_string(paste); | ||
1963 | LLWString::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); | ||
1964 | if( mAllowEmbeddedItems ) | ||
1965 | { | 1903 | { |
1966 | const llwchar LF = 10; | 1904 | clean_string[i] = pasteEmbeddedItem(wc); |
1967 | S32 len = clean_string.length(); | ||
1968 | for( S32 i = 0; i < len; i++ ) | ||
1969 | { | ||
1970 | llwchar wc = clean_string[i]; | ||
1971 | if( (wc < LLFont::FIRST_CHAR) && (wc != LF) ) | ||
1972 | { | ||
1973 | clean_string[i] = LL_UNKNOWN_CHAR; | ||
1974 | } | ||
1975 | else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) | ||
1976 | { | ||
1977 | clean_string[i] = pasteEmbeddedItem(wc); | ||
1978 | } | ||
1979 | } | ||
1980 | } | 1905 | } |
1981 | |||
1982 | // Insert the new text into the existing text. | ||
1983 | setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE)); | ||
1984 | deselect(); | ||
1985 | |||
1986 | updateLineStartList(); | ||
1987 | updateScrollFromCursor(); | ||
1988 | } | 1906 | } |
1989 | } | 1907 | } |
1908 | |||
1909 | // Insert the new text into the existing text. | ||
1910 | setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE)); | ||
1911 | deselect(); | ||
1912 | |||
1913 | updateLineStartList(); | ||
1914 | updateScrollFromCursor(); | ||
1990 | } | 1915 | } |
1991 | 1916 | ||
1992 | 1917 | ||
@@ -2240,7 +2165,7 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent ) | |||
2240 | { | 2165 | { |
2241 | // Special case for TAB. If want to move to next field, report | 2166 | // Special case for TAB. If want to move to next field, report |
2242 | // not handled and let the parent take care of field movement. | 2167 | // not handled and let the parent take care of field movement. |
2243 | if (KEY_TAB == key && mTabToNextField) | 2168 | if (KEY_TAB == key && mTabsToNextField) |
2244 | { | 2169 | { |
2245 | return FALSE; | 2170 | return FALSE; |
2246 | } | 2171 | } |
@@ -2296,7 +2221,7 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent ) | |||
2296 | 2221 | ||
2297 | if( handled ) | 2222 | if( handled ) |
2298 | { | 2223 | { |
2299 | mKeystrokeTimer.reset(); | 2224 | resetKeystrokeTimer(); |
2300 | 2225 | ||
2301 | // Most keystrokes will make the selection box go away, but not all will. | 2226 | // Most keystrokes will make the selection box go away, but not all will. |
2302 | if( !selection_modified && | 2227 | if( !selection_modified && |
@@ -2350,7 +2275,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_pare | |||
2350 | 2275 | ||
2351 | if( handled ) | 2276 | if( handled ) |
2352 | { | 2277 | { |
2353 | mKeystrokeTimer.reset(); | 2278 | resetKeystrokeTimer(); |
2354 | 2279 | ||
2355 | // Most keystrokes will make the selection box go away, but not all will. | 2280 | // Most keystrokes will make the selection box go away, but not all will. |
2356 | deselect(); | 2281 | deselect(); |
@@ -2364,58 +2289,58 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_pare | |||
2364 | } | 2289 | } |
2365 | 2290 | ||
2366 | 2291 | ||
2367 | 2292 | // virtual | |
2368 | BOOL LLTextEditor::canDoDelete() | 2293 | BOOL LLTextEditor::canDoDelete() const |
2369 | { | 2294 | { |
2370 | return !mReadOnly && ( hasSelection() || (mCursorPos < getLength()) ); | 2295 | return !mReadOnly && ( hasSelection() || (mCursorPos < getLength()) ); |
2371 | } | 2296 | } |
2372 | 2297 | ||
2373 | void LLTextEditor::doDelete() | 2298 | void LLTextEditor::doDelete() |
2374 | { | 2299 | { |
2375 | if( canDoDelete() ) | 2300 | if( !canDoDelete() ) |
2376 | { | 2301 | { |
2377 | if( hasSelection() ) | 2302 | return; |
2303 | } | ||
2304 | if( hasSelection() ) | ||
2305 | { | ||
2306 | deleteSelection(FALSE); | ||
2307 | } | ||
2308 | else | ||
2309 | if( mCursorPos < getLength() ) | ||
2310 | { | ||
2311 | S32 i; | ||
2312 | S32 chars_to_remove = 1; | ||
2313 | const LLWString &text = mWText; | ||
2314 | if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) | ||
2378 | { | 2315 | { |
2379 | deleteSelection(FALSE); | 2316 | // Try to remove a full tab's worth of spaces |
2380 | } | 2317 | S32 line, offset; |
2381 | else | 2318 | getLineAndOffset( mCursorPos, &line, &offset ); |
2382 | if( mCursorPos < getLength() ) | 2319 | chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); |
2383 | { | 2320 | if( chars_to_remove == 0 ) |
2384 | S32 i; | ||
2385 | S32 chars_to_remove = 1; | ||
2386 | const LLWString &text = mWText; | ||
2387 | if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) | ||
2388 | { | 2321 | { |
2389 | // Try to remove a full tab's worth of spaces | 2322 | chars_to_remove = SPACES_PER_TAB; |
2390 | S32 line, offset; | ||
2391 | getLineAndOffset( mCursorPos, &line, &offset ); | ||
2392 | chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); | ||
2393 | if( chars_to_remove == 0 ) | ||
2394 | { | ||
2395 | chars_to_remove = SPACES_PER_TAB; | ||
2396 | } | ||
2397 | |||
2398 | for( i = 0; i < chars_to_remove; i++ ) | ||
2399 | { | ||
2400 | if( text[mCursorPos + i] != ' ' ) | ||
2401 | { | ||
2402 | chars_to_remove = 1; | ||
2403 | break; | ||
2404 | } | ||
2405 | } | ||
2406 | } | 2323 | } |
2407 | 2324 | ||
2408 | |||
2409 | for( i = 0; i < chars_to_remove; i++ ) | 2325 | for( i = 0; i < chars_to_remove; i++ ) |
2410 | { | 2326 | { |
2411 | setCursorPos(mCursorPos + 1); | 2327 | if( text[mCursorPos + i] != ' ' ) |
2412 | removeChar(); | 2328 | { |
2329 | chars_to_remove = 1; | ||
2330 | break; | ||
2331 | } | ||
2413 | } | 2332 | } |
2414 | } | 2333 | } |
2415 | 2334 | ||
2416 | updateLineStartList(); | 2335 | for( i = 0; i < chars_to_remove; i++ ) |
2417 | updateScrollFromCursor(); | 2336 | { |
2337 | setCursorPos(mCursorPos + 1); | ||
2338 | removeChar(); | ||
2339 | } | ||
2418 | } | 2340 | } |
2341 | |||
2342 | updateLineStartList(); | ||
2343 | updateScrollFromCursor(); | ||
2419 | } | 2344 | } |
2420 | 2345 | ||
2421 | //---------------------------------------------------------------------------- | 2346 | //---------------------------------------------------------------------------- |
@@ -2429,65 +2354,66 @@ void LLTextEditor::blockUndo() | |||
2429 | mUndoStack.clear(); | 2354 | mUndoStack.clear(); |
2430 | } | 2355 | } |
2431 | 2356 | ||
2432 | 2357 | // virtual | |
2433 | BOOL LLTextEditor::canUndo() | 2358 | BOOL LLTextEditor::canUndo() const |
2434 | { | 2359 | { |
2435 | return !mReadOnly && mLastCmd != NULL; | 2360 | return !mReadOnly && mLastCmd != NULL; |
2436 | } | 2361 | } |
2437 | 2362 | ||
2438 | void LLTextEditor::undo() | 2363 | void LLTextEditor::undo() |
2439 | { | 2364 | { |
2440 | if( canUndo() ) | 2365 | if( !canUndo() ) |
2441 | { | 2366 | { |
2442 | deselect(); | 2367 | return; |
2443 | 2368 | } | |
2444 | S32 pos = 0; | 2369 | deselect(); |
2445 | do | 2370 | S32 pos = 0; |
2446 | { | 2371 | do |
2447 | pos = mLastCmd->undo(this); | 2372 | { |
2448 | undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); | 2373 | pos = mLastCmd->undo(this); |
2449 | if (iter != mUndoStack.end()) | 2374 | undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); |
2450 | ++iter; | 2375 | if (iter != mUndoStack.end()) |
2451 | if (iter != mUndoStack.end()) | 2376 | ++iter; |
2452 | mLastCmd = *iter; | 2377 | if (iter != mUndoStack.end()) |
2453 | else | 2378 | mLastCmd = *iter; |
2454 | mLastCmd = NULL; | 2379 | else |
2380 | mLastCmd = NULL; | ||
2455 | 2381 | ||
2456 | } while( mLastCmd && mLastCmd->groupWithNext() ); | 2382 | } while( mLastCmd && mLastCmd->groupWithNext() ); |
2457 | 2383 | ||
2458 | setCursorPos(pos); | 2384 | setCursorPos(pos); |
2459 | 2385 | ||
2460 | updateLineStartList(); | 2386 | updateLineStartList(); |
2461 | updateScrollFromCursor(); | 2387 | updateScrollFromCursor(); |
2462 | } | ||
2463 | } | 2388 | } |
2464 | 2389 | ||
2465 | BOOL LLTextEditor::canRedo() | 2390 | BOOL LLTextEditor::canRedo() const |
2466 | { | 2391 | { |
2467 | return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); | 2392 | return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); |
2468 | } | 2393 | } |
2469 | 2394 | ||
2470 | void LLTextEditor::redo() | 2395 | void LLTextEditor::redo() |
2471 | { | 2396 | { |
2472 | if( canRedo() ) | 2397 | if( !canRedo() ) |
2473 | { | 2398 | { |
2474 | deselect(); | 2399 | return; |
2475 | 2400 | } | |
2476 | S32 pos = 0; | 2401 | deselect(); |
2477 | do | 2402 | S32 pos = 0; |
2403 | do | ||
2404 | { | ||
2405 | if( !mLastCmd ) | ||
2478 | { | 2406 | { |
2479 | if( !mLastCmd ) | 2407 | mLastCmd = mUndoStack.back(); |
2480 | { | 2408 | } |
2481 | mLastCmd = mUndoStack.back(); | 2409 | else |
2482 | } | 2410 | { |
2411 | undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); | ||
2412 | if (iter != mUndoStack.begin()) | ||
2413 | mLastCmd = *(--iter); | ||
2483 | else | 2414 | else |
2484 | { | 2415 | mLastCmd = NULL; |
2485 | undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); | 2416 | } |
2486 | if (iter != mUndoStack.begin()) | ||
2487 | mLastCmd = *(--iter); | ||
2488 | else | ||
2489 | mLastCmd = NULL; | ||
2490 | } | ||
2491 | 2417 | ||
2492 | if( mLastCmd ) | 2418 | if( mLastCmd ) |
2493 | { | 2419 | { |
@@ -2500,9 +2426,8 @@ void LLTextEditor::redo() | |||
2500 | 2426 | ||
2501 | setCursorPos(pos); | 2427 | setCursorPos(pos); |
2502 | 2428 | ||
2503 | updateLineStartList(); | 2429 | updateLineStartList(); |
2504 | updateScrollFromCursor(); | 2430 | updateScrollFromCursor(); |
2505 | } | ||
2506 | } | 2431 | } |
2507 | 2432 | ||
2508 | void LLTextEditor::onFocusReceived() | 2433 | void LLTextEditor::onFocusReceived() |
@@ -2548,8 +2473,8 @@ void LLTextEditor::setEnabled(BOOL enabled) | |||
2548 | void LLTextEditor::drawBackground() | 2473 | void LLTextEditor::drawBackground() |
2549 | { | 2474 | { |
2550 | S32 left = 0; | 2475 | S32 left = 0; |
2551 | S32 top = mRect.getHeight(); | 2476 | S32 top = getRect().getHeight(); |
2552 | S32 right = mRect.getWidth(); | 2477 | S32 right = getRect().getWidth(); |
2553 | S32 bottom = 0; | 2478 | S32 bottom = 0; |
2554 | 2479 | ||
2555 | LLColor4 bg_color = mReadOnlyBgColor; | 2480 | LLColor4 bg_color = mReadOnlyBgColor; |
@@ -2677,7 +2602,7 @@ void LLTextEditor::drawSelectionBackground() | |||
2677 | LLGLSNoTexture no_texture; | 2602 | LLGLSNoTexture no_texture; |
2678 | const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; | 2603 | const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; |
2679 | F32 alpha = hasFocus() ? 1.f : 0.5f; | 2604 | F32 alpha = hasFocus() ? 1.f : 0.5f; |
2680 | glColor4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); | 2605 | gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); |
2681 | 2606 | ||
2682 | if( selection_left_y == selection_right_y ) | 2607 | if( selection_left_y == selection_right_y ) |
2683 | { | 2608 | { |
@@ -2805,14 +2730,14 @@ void LLTextEditor::drawCursor() | |||
2805 | 2730 | ||
2806 | LLGLSNoTexture no_texture; | 2731 | LLGLSNoTexture no_texture; |
2807 | 2732 | ||
2808 | glColor4fv( mCursorColor.mV ); | 2733 | gGL.color4fv( mCursorColor.mV ); |
2809 | 2734 | ||
2810 | gl_rect_2d(llfloor(cursor_left), llfloor(cursor_top), | 2735 | gl_rect_2d(llfloor(cursor_left), llfloor(cursor_top), |
2811 | llfloor(cursor_right), llfloor(cursor_bottom)); | 2736 | llfloor(cursor_right), llfloor(cursor_bottom)); |
2812 | 2737 | ||
2813 | if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n') | 2738 | if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n') |
2814 | { | 2739 | { |
2815 | LLTextSegment* segmentp = getSegmentAtOffset(mCursorPos); | 2740 | const LLTextSegment* segmentp = getSegmentAtOffset(mCursorPos); |
2816 | LLColor4 text_color; | 2741 | LLColor4 text_color; |
2817 | if (segmentp) | 2742 | if (segmentp) |
2818 | { | 2743 | { |
@@ -2826,7 +2751,6 @@ void LLTextEditor::drawCursor() | |||
2826 | { | 2751 | { |
2827 | text_color = mFgColor; | 2752 | text_color = mFgColor; |
2828 | } | 2753 | } |
2829 | LLGLSTexture texture; | ||
2830 | mGLFont->render(text, mCursorPos, next_char_left, cursor_bottom + line_height, | 2754 | mGLFont->render(text, mCursorPos, next_char_left, cursor_bottom + line_height, |
2831 | LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f), | 2755 | LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f), |
2832 | LLFontGL::LEFT, LLFontGL::TOP, | 2756 | LLFontGL::LEFT, LLFontGL::TOP, |
@@ -2945,122 +2869,118 @@ void LLTextEditor::drawText() | |||
2945 | { | 2869 | { |
2946 | const LLWString &text = mWText; | 2870 | const LLWString &text = mWText; |
2947 | const S32 text_len = getLength(); | 2871 | const S32 text_len = getLength(); |
2872 | if( text_len <= 0 ) | ||
2873 | { | ||
2874 | return; | ||
2875 | } | ||
2876 | S32 selection_left = -1; | ||
2877 | S32 selection_right = -1; | ||
2878 | // Draw selection even if we don't have keyboard focus for search/replace | ||
2879 | if( hasSelection()) | ||
2880 | { | ||
2881 | selection_left = llmin( mSelectionStart, mSelectionEnd ); | ||
2882 | selection_right = llmax( mSelectionStart, mSelectionEnd ); | ||
2883 | } | ||
2948 | 2884 | ||
2949 | if( text_len > 0 ) | 2885 | LLGLSUIDefault gls_ui; |
2886 | |||
2887 | S32 cur_line = mScrollbar->getDocPos(); | ||
2888 | S32 num_lines = getLineCount(); | ||
2889 | if (cur_line >= num_lines) | ||
2890 | { | ||
2891 | return; | ||
2892 | } | ||
2893 | |||
2894 | S32 line_start = getLineStart(cur_line); | ||
2895 | LLTextSegment t(line_start); | ||
2896 | segment_list_t::iterator seg_iter; | ||
2897 | seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare()); | ||
2898 | if (seg_iter == mSegments.end() || (*seg_iter)->getStart() > line_start) --seg_iter; | ||
2899 | LLTextSegment* cur_segment = *seg_iter; | ||
2900 | |||
2901 | S32 line_height = llround( mGLFont->getLineHeight() ); | ||
2902 | F32 text_y = (F32)(mTextRect.mTop - line_height); | ||
2903 | while((mTextRect.mBottom <= text_y) && (cur_line < num_lines)) | ||
2950 | { | 2904 | { |
2951 | S32 selection_left = -1; | 2905 | S32 next_start = -1; |
2952 | S32 selection_right = -1; | 2906 | S32 line_end = text_len; |
2953 | // Draw selection even if we don't have keyboard focus for search/replace | 2907 | |
2954 | if( hasSelection()) | 2908 | if ((cur_line + 1) < num_lines) |
2955 | { | 2909 | { |
2956 | selection_left = llmin( mSelectionStart, mSelectionEnd ); | 2910 | next_start = getLineStart(cur_line + 1); |
2957 | selection_right = llmax( mSelectionStart, mSelectionEnd ); | 2911 | line_end = next_start; |
2958 | } | 2912 | } |
2959 | 2913 | if ( text[line_end-1] == '\n' ) | |
2960 | LLGLSUIDefault gls_ui; | ||
2961 | |||
2962 | S32 cur_line = mScrollbar->getDocPos(); | ||
2963 | S32 num_lines = getLineCount(); | ||
2964 | if (cur_line >= num_lines) | ||
2965 | { | 2914 | { |
2966 | return; | 2915 | --line_end; |
2967 | } | 2916 | } |
2968 | 2917 | ||
2969 | S32 line_start = getLineStart(cur_line); | 2918 | F32 text_x = (F32)mTextRect.mLeft; |
2970 | LLTextSegment t(line_start); | ||
2971 | segment_list_t::iterator seg_iter; | ||
2972 | seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare()); | ||
2973 | if (seg_iter == mSegments.end() || (*seg_iter)->getStart() > line_start) --seg_iter; | ||
2974 | LLTextSegment* cur_segment = *seg_iter; | ||
2975 | |||
2976 | S32 line_height = llround( mGLFont->getLineHeight() ); | ||
2977 | F32 text_y = (F32)(mTextRect.mTop - line_height); | ||
2978 | while((mTextRect.mBottom <= text_y) && (cur_line < num_lines)) | ||
2979 | { | ||
2980 | S32 next_start = -1; | ||
2981 | S32 line_end = text_len; | ||
2982 | 2919 | ||
2983 | if ((cur_line + 1) < num_lines) | 2920 | S32 seg_start = line_start; |
2984 | { | 2921 | while( seg_start < line_end ) |
2985 | next_start = getLineStart(cur_line + 1); | 2922 | { |
2986 | line_end = next_start; | 2923 | while( cur_segment->getEnd() <= seg_start ) |
2987 | } | ||
2988 | if ( text[line_end-1] == '\n' ) | ||
2989 | { | 2924 | { |
2990 | --line_end; | 2925 | seg_iter++; |
2926 | if (seg_iter == mSegments.end()) | ||
2927 | { | ||
2928 | llwarns << "Ran off the segmentation end!" << llendl; | ||
2929 | return; | ||
2930 | } | ||
2931 | cur_segment = *seg_iter; | ||
2991 | } | 2932 | } |
2992 | 2933 | ||
2993 | F32 text_x = (F32)mTextRect.mLeft; | 2934 | // Draw a segment within the line |
2994 | 2935 | S32 clipped_end = llmin( line_end, cur_segment->getEnd() ); | |
2995 | S32 seg_start = line_start; | 2936 | S32 clipped_len = clipped_end - seg_start; |
2996 | while( seg_start < line_end ) | 2937 | if( clipped_len > 0 ) |
2997 | { | 2938 | { |
2998 | while( cur_segment->getEnd() <= seg_start ) | 2939 | LLStyle style = cur_segment->getStyle(); |
2940 | if ( style.isImage() && (cur_segment->getStart() >= seg_start) && (cur_segment->getStart() <= clipped_end)) | ||
2999 | { | 2941 | { |
3000 | seg_iter++; | 2942 | LLImageGL *image = style.getImage(); |
3001 | if (seg_iter == mSegments.end()) | 2943 | gl_draw_scaled_image( llround(text_x), llround(text_y)+line_height-style.mImageHeight, style.mImageWidth, style.mImageHeight, image, LLColor4::white ); |
3002 | { | ||
3003 | llwarns << "Ran off the segmentation end!" << llendl; | ||
3004 | return; | ||
3005 | } | ||
3006 | cur_segment = *seg_iter; | ||
3007 | } | 2944 | } |
3008 | |||
3009 | // Draw a segment within the line | ||
3010 | S32 clipped_end = llmin( line_end, cur_segment->getEnd() ); | ||
3011 | S32 clipped_len = clipped_end - seg_start; | ||
3012 | if( clipped_len > 0 ) | ||
3013 | { | ||
3014 | LLStyle style = cur_segment->getStyle(); | ||
3015 | if ( style.isImage() && (cur_segment->getStart() >= seg_start) && (cur_segment->getStart() <= clipped_end)) | ||
3016 | { | ||
3017 | LLImageGL *image = style.getImage(); | ||
3018 | |||
3019 | gl_draw_scaled_image( llround(text_x), llround(text_y)+line_height-style.mImageHeight, style.mImageWidth, style.mImageHeight, image, LLColor4::white ); | ||
3020 | |||
3021 | } | ||
3022 | 2945 | ||
3023 | if (cur_segment == mHoverSegment && style.getIsEmbeddedItem()) | 2946 | if (cur_segment == mHoverSegment && style.getIsEmbeddedItem()) |
3024 | { | 2947 | { |
3025 | style.mUnderline = TRUE; | 2948 | style.mUnderline = TRUE; |
3026 | } | 2949 | } |
3027 | 2950 | ||
3028 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); | 2951 | S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); |
3029 | 2952 | ||
3030 | if ( (mParseHTML) && (left_pos > seg_start) && (left_pos < clipped_end) && mIsSelecting && (mSelectionStart == mSelectionEnd) ) | 2953 | if ( (mParseHTML) && (left_pos > seg_start) && (left_pos < clipped_end) && mIsSelecting && (mSelectionStart == mSelectionEnd) ) |
3031 | { | 2954 | { |
3032 | mHTML = style.getLinkHREF(); | 2955 | mHTML = style.getLinkHREF(); |
3033 | } | 2956 | } |
3034 | 2957 | ||
3035 | drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x ); | 2958 | drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x ); |
3036 | 2959 | ||
3037 | // Note: text_x is incremented by drawClippedSegment() | 2960 | // Note: text_x is incremented by drawClippedSegment() |
3038 | seg_start += clipped_len; | 2961 | seg_start += clipped_len; |
3039 | } | ||
3040 | } | 2962 | } |
2963 | } | ||
3041 | 2964 | ||
3042 | // move down one line | 2965 | // move down one line |
3043 | text_y -= (F32)line_height; | 2966 | text_y -= (F32)line_height; |
3044 | 2967 | ||
3045 | line_start = next_start; | 2968 | line_start = next_start; |
3046 | cur_line++; | 2969 | cur_line++; |
3047 | } | ||
3048 | } | 2970 | } |
3049 | } | 2971 | } |
3050 | 2972 | ||
3051 | // Draws a single text segment, reversing the color for selection if needed. | 2973 | // Draws a single text segment, reversing the color for selection if needed. |
3052 | void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyle& style, F32* right_x ) | 2974 | void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyle& style, F32* right_x ) |
3053 | { | 2975 | { |
3054 | const LLFontGL* font = mGLFont; | ||
3055 | |||
3056 | LLColor4 color; | ||
3057 | |||
3058 | if (!style.isVisible()) | 2976 | if (!style.isVisible()) |
3059 | { | 2977 | { |
3060 | return; | 2978 | return; |
3061 | } | 2979 | } |
3062 | 2980 | ||
3063 | color = style.getColor(); | 2981 | const LLFontGL* font = mGLFont; |
2982 | |||
2983 | LLColor4 color = style.getColor(); | ||
3064 | 2984 | ||
3065 | if ( style.getFontString()[0] ) | 2985 | if ( style.getFontString()[0] ) |
3066 | { | 2986 | { |
@@ -3131,12 +3051,14 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32 | |||
3131 | 3051 | ||
3132 | void LLTextEditor::draw() | 3052 | void LLTextEditor::draw() |
3133 | { | 3053 | { |
3134 | if( getVisible() ) | 3054 | if( !getVisible() ) |
3135 | { | 3055 | { |
3136 | { | 3056 | return; |
3137 | LLLocalClipRect clip(LLRect(0, mRect.getHeight(), mRect.getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); | 3057 | } |
3058 | { | ||
3059 | LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0)); | ||
3138 | 3060 | ||
3139 | bindEmbeddedChars( mGLFont ); | 3061 | bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
3140 | 3062 | ||
3141 | drawBackground(); | 3063 | drawBackground(); |
3142 | drawSelectionBackground(); | 3064 | drawSelectionBackground(); |
@@ -3144,34 +3066,30 @@ void LLTextEditor::draw() | |||
3144 | drawText(); | 3066 | drawText(); |
3145 | drawCursor(); | 3067 | drawCursor(); |
3146 | 3068 | ||
3147 | unbindEmbeddedChars( mGLFont ); | 3069 | unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
3148 | 3070 | ||
3149 | //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret | 3071 | //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret |
3150 | // when in readonly mode | 3072 | // when in readonly mode |
3151 | mBorder->setKeyboardFocusHighlight( gFocusMgr.getKeyboardFocus() == this);// && !mReadOnly); | 3073 | mBorder->setKeyboardFocusHighlight( gFocusMgr.getKeyboardFocus() == this);// && !mReadOnly); |
3152 | } | ||
3153 | LLView::draw(); // Draw children (scrollbar and border) | ||
3154 | } | 3074 | } |
3155 | 3075 | ||
3156 | // remember if we are supposed to be at the bottom of the buffer | 3076 | // remember if we are supposed to be at the bottom of the buffer |
3157 | mScrolledToBottom = isScrolledToBottom(); | 3077 | mScrolledToBottom = isScrolledToBottom(); |
3158 | } | ||
3159 | 3078 | ||
3160 | void LLTextEditor::reportBadKeystroke() | 3079 | LLView::draw(); // Draw children (scrollbar and border) |
3161 | { | ||
3162 | make_ui_sound("UISndBadKeystroke"); | ||
3163 | } | 3080 | } |
3164 | 3081 | ||
3165 | 3082 | ||
3166 | void LLTextEditor::onTabInto() | 3083 | void LLTextEditor::onTabInto() |
3167 | { | 3084 | { |
3168 | // selecting all on tabInto causes users to hit tab twice and replace their text with a tab character | 3085 | // selecting all on tabInto causes users to hit tab twice and replace their text with a tab character |
3169 | // theoretically, one could selectAll if mTabToNextField is true, but we couldn't think of a use case | 3086 | // theoretically, one could selectAll if mTabsToNextField is true, but we couldn't think of a use case |
3170 | // where you'd want to select all anyway | 3087 | // where you'd want to select all anyway |
3171 | // preserve insertion point when returning to the editor | 3088 | // preserve insertion point when returning to the editor |
3172 | //selectAll(); | 3089 | //selectAll(); |
3173 | } | 3090 | } |
3174 | 3091 | ||
3092 | // virtual | ||
3175 | void LLTextEditor::clear() | 3093 | void LLTextEditor::clear() |
3176 | { | 3094 | { |
3177 | setText(LLString::null); | 3095 | setText(LLString::null); |
@@ -3200,7 +3118,7 @@ void LLTextEditor::setFocus( BOOL new_state ) | |||
3200 | gEditMenuHandler = this; | 3118 | gEditMenuHandler = this; |
3201 | 3119 | ||
3202 | // Don't start the cursor flashing right away | 3120 | // Don't start the cursor flashing right away |
3203 | mKeystrokeTimer.reset(); | 3121 | resetKeystrokeTimer(); |
3204 | } | 3122 | } |
3205 | else | 3123 | else |
3206 | { | 3124 | { |
@@ -3214,6 +3132,7 @@ void LLTextEditor::setFocus( BOOL new_state ) | |||
3214 | } | 3132 | } |
3215 | } | 3133 | } |
3216 | 3134 | ||
3135 | // virtual | ||
3217 | BOOL LLTextEditor::acceptsTextInput() const | 3136 | BOOL LLTextEditor::acceptsTextInput() const |
3218 | { | 3137 | { |
3219 | return !mReadOnly; | 3138 | return !mReadOnly; |
@@ -3268,7 +3187,7 @@ void LLTextEditor::changePage( S32 delta ) | |||
3268 | 3187 | ||
3269 | void LLTextEditor::changeLine( S32 delta ) | 3188 | void LLTextEditor::changeLine( S32 delta ) |
3270 | { | 3189 | { |
3271 | bindEmbeddedChars( mGLFont ); | 3190 | bindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
3272 | 3191 | ||
3273 | S32 line, offset; | 3192 | S32 line, offset; |
3274 | getLineAndOffset( mCursorPos, &line, &offset ); | 3193 | getLineAndOffset( mCursorPos, &line, &offset ); |
@@ -3295,7 +3214,7 @@ void LLTextEditor::changeLine( S32 delta ) | |||
3295 | } | 3214 | } |
3296 | else | 3215 | else |
3297 | { | 3216 | { |
3298 | unbindEmbeddedChars( mGLFont ); | 3217 | unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
3299 | return; | 3218 | return; |
3300 | } | 3219 | } |
3301 | 3220 | ||
@@ -3320,7 +3239,7 @@ void LLTextEditor::changeLine( S32 delta ) | |||
3320 | 3239 | ||
3321 | // put desired position into remember-buffer after setCursorPos() | 3240 | // put desired position into remember-buffer after setCursorPos() |
3322 | mDesiredXPixel = desired_x_pixel; | 3241 | mDesiredXPixel = desired_x_pixel; |
3323 | unbindEmbeddedChars( mGLFont ); | 3242 | unbindEmbeddedChars( const_cast<LLFontGL*>(mGLFont) ); |
3324 | } | 3243 | } |
3325 | 3244 | ||
3326 | BOOL LLTextEditor::isScrolledToTop() | 3245 | BOOL LLTextEditor::isScrolledToTop() |
@@ -3768,20 +3687,14 @@ BOOL LLTextEditor::tryToRevertToPristineState() | |||
3768 | return isPristine(); // TRUE => success | 3687 | return isPristine(); // TRUE => success |
3769 | } | 3688 | } |
3770 | 3689 | ||
3771 | // virtual Return TRUE if changes have been made | ||
3772 | BOOL LLTextEditor::isDirty() const | ||
3773 | { | ||
3774 | return( mLastCmd != NULL || (mPristineCmd && (mPristineCmd != mLastCmd)) ); | ||
3775 | } | ||
3776 | |||
3777 | 3690 | ||
3778 | void LLTextEditor::updateTextRect() | 3691 | void LLTextEditor::updateTextRect() |
3779 | { | 3692 | { |
3780 | mTextRect.setOriginAndSize( | 3693 | mTextRect.setOriginAndSize( |
3781 | UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD, | 3694 | UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD, |
3782 | UI_TEXTEDITOR_BORDER, | 3695 | UI_TEXTEDITOR_BORDER, |
3783 | mRect.getWidth() - SCROLLBAR_SIZE - 2 * (UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD), | 3696 | getRect().getWidth() - SCROLLBAR_SIZE - 2 * (UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD), |
3784 | mRect.getHeight() - 2 * UI_TEXTEDITOR_BORDER - UI_TEXTEDITOR_V_PAD_TOP ); | 3697 | getRect().getHeight() - 2 * UI_TEXTEDITOR_BORDER - UI_TEXTEDITOR_V_PAD_TOP ); |
3785 | } | 3698 | } |
3786 | 3699 | ||
3787 | void LLTextEditor::loadKeywords(const LLString& filename, | 3700 | void LLTextEditor::loadKeywords(const LLString& filename, |
@@ -3862,8 +3775,7 @@ void LLTextEditor::pruneSegments() | |||
3862 | } | 3775 | } |
3863 | else | 3776 | else |
3864 | { | 3777 | { |
3865 | llwarns << "Tried to erase end of empty LLTextEditor" | 3778 | llwarns << "Tried to erase end of empty LLTextEditor" << llendl; |
3866 | << llendl; | ||
3867 | } | 3779 | } |
3868 | } | 3780 | } |
3869 | 3781 | ||
@@ -3949,21 +3861,9 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask) | |||
3949 | return FALSE; | 3861 | return FALSE; |
3950 | } | 3862 | } |
3951 | 3863 | ||
3952 | llwchar LLTextEditor::pasteEmbeddedItem(llwchar ext_char) | ||
3953 | { | ||
3954 | return ext_char; | ||
3955 | } | ||
3956 | |||
3957 | void LLTextEditor::bindEmbeddedChars(const LLFontGL* font) | ||
3958 | { | ||
3959 | } | ||
3960 | |||
3961 | void LLTextEditor::unbindEmbeddedChars(const LLFontGL* font) | ||
3962 | { | ||
3963 | } | ||
3964 | 3864 | ||
3965 | // Finds the text segment (if any) at the give local screen position | 3865 | // Finds the text segment (if any) at the give local screen position |
3966 | LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) | 3866 | const LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) const |
3967 | { | 3867 | { |
3968 | // Find the cursor position at the requested local screen position | 3868 | // Find the cursor position at the requested local screen position |
3969 | S32 offset = getCursorPosFromLocalCoord( x, y, FALSE ); | 3869 | S32 offset = getCursorPosFromLocalCoord( x, y, FALSE ); |
@@ -3971,13 +3871,13 @@ LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) | |||
3971 | return idx >= 0 ? mSegments[idx] : NULL; | 3871 | return idx >= 0 ? mSegments[idx] : NULL; |
3972 | } | 3872 | } |
3973 | 3873 | ||
3974 | LLTextSegment* LLTextEditor::getSegmentAtOffset(S32 offset) | 3874 | const LLTextSegment* LLTextEditor::getSegmentAtOffset(S32 offset) const |
3975 | { | 3875 | { |
3976 | S32 idx = getSegmentIdxAtOffset(offset); | 3876 | S32 idx = getSegmentIdxAtOffset(offset); |
3977 | return idx >= 0 ? mSegments[idx] : NULL; | 3877 | return idx >= 0 ? mSegments[idx] : NULL; |
3978 | } | 3878 | } |
3979 | 3879 | ||
3980 | S32 LLTextEditor::getSegmentIdxAtOffset(S32 offset) | 3880 | S32 LLTextEditor::getSegmentIdxAtOffset(S32 offset) const |
3981 | { | 3881 | { |
3982 | if (mSegments.empty() || offset < 0 || offset >= getLength()) | 3882 | if (mSegments.empty() || offset < 0 || offset >= getLength()) |
3983 | { | 3883 | { |
@@ -4149,7 +4049,7 @@ LLTextSegment::LLTextSegment( const LLColor3& color, S32 start, S32 end ) : | |||
4149 | { | 4049 | { |
4150 | } | 4050 | } |
4151 | 4051 | ||
4152 | BOOL LLTextSegment::getToolTip(LLString& msg) | 4052 | BOOL LLTextSegment::getToolTip(LLString& msg) const |
4153 | { | 4053 | { |
4154 | if (mToken && !mToken->getToolTip().empty()) | 4054 | if (mToken && !mToken->getToolTip().empty()) |
4155 | { | 4055 | { |
@@ -4162,7 +4062,7 @@ BOOL LLTextSegment::getToolTip(LLString& msg) | |||
4162 | 4062 | ||
4163 | 4063 | ||
4164 | 4064 | ||
4165 | void LLTextSegment::dump() | 4065 | void LLTextSegment::dump() const |
4166 | { | 4066 | { |
4167 | llinfos << "Segment [" << | 4067 | llinfos << "Segment [" << |
4168 | // mColor.mV[VX] << ", " << | 4068 | // mColor.mV[VX] << ", " << |
@@ -4182,13 +4082,9 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const | |||
4182 | // Attributes | 4082 | // Attributes |
4183 | 4083 | ||
4184 | node->createChild("max_length", TRUE)->setIntValue(getMaxLength()); | 4084 | node->createChild("max_length", TRUE)->setIntValue(getMaxLength()); |
4185 | |||
4186 | node->createChild("embedded_items", TRUE)->setBoolValue(mAllowEmbeddedItems); | 4085 | node->createChild("embedded_items", TRUE)->setBoolValue(mAllowEmbeddedItems); |
4187 | |||
4188 | node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); | 4086 | node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); |
4189 | |||
4190 | node->createChild("word_wrap", TRUE)->setBoolValue(mWordWrap); | 4087 | node->createChild("word_wrap", TRUE)->setBoolValue(mWordWrap); |
4191 | |||
4192 | node->createChild("hide_scrollbar", TRUE)->setBoolValue(mHideScrollbarForShortDocs); | 4088 | node->createChild("hide_scrollbar", TRUE)->setBoolValue(mHideScrollbarForShortDocs); |
4193 | 4089 | ||
4194 | addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor"); | 4090 | addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor"); |
@@ -4274,7 +4170,7 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node) | |||
4274 | } | 4170 | } |
4275 | 4171 | ||
4276 | /////////////////////////////////////////////////////////////////// | 4172 | /////////////////////////////////////////////////////////////////// |
4277 | S32 LLTextEditor::findHTMLToken(const LLString &line, S32 pos, BOOL reverse) | 4173 | S32 LLTextEditor::findHTMLToken(const LLString &line, S32 pos, BOOL reverse) const |
4278 | { | 4174 | { |
4279 | LLString openers=" \t('\"[{<>"; | 4175 | LLString openers=" \t('\"[{<>"; |
4280 | LLString closers=" \t)'\"]}><;"; | 4176 | LLString closers=" \t)'\"]}><;"; |
@@ -4311,7 +4207,7 @@ S32 LLTextEditor::findHTMLToken(const LLString &line, S32 pos, BOOL reverse) | |||
4311 | return retval; | 4207 | return retval; |
4312 | } | 4208 | } |
4313 | 4209 | ||
4314 | BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) | 4210 | BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) const |
4315 | { | 4211 | { |
4316 | 4212 | ||
4317 | S32 m1,m2,m3; | 4213 | S32 m1,m2,m3; |