diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llui/lllineeditor.cpp | 363 |
1 files changed, 325 insertions, 38 deletions
diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp index 2851beb..88c8d75 100644 --- a/linden/indra/llui/lllineeditor.cpp +++ b/linden/indra/llui/lllineeditor.cpp | |||
@@ -12,12 +12,12 @@ | |||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | 12 | * ("GPL"), unless you have obtained a separate licensing agreement |
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | 13 | * ("Other License"), formally executed by you and Linden Lab. Terms of |
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | 14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or |
15 | * online at http://secondlife.com/developers/opensource/gplv2 | 15 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 |
16 | * | 16 | * |
17 | * There are special exceptions to the terms and conditions of the GPL as | 17 | * There are special exceptions to the terms and conditions of the GPL as |
18 | * it is applied to this Source Code. View the full text of the exception | 18 | * it is applied to this Source Code. View the full text of the exception |
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | 19 | * in the file doc/FLOSS-exception.txt in this software distribution, or |
20 | * online at http://secondlife.com/developers/opensource/flossexception | 20 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception |
21 | * | 21 | * |
22 | * By copying, modifying or distributing this software, you acknowledge | 22 | * By copying, modifying or distributing this software, you acknowledge |
23 | * that you have read and understood your obligations described above, | 23 | * that you have read and understood your obligations described above, |
@@ -72,6 +72,15 @@ const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing | |||
72 | const F32 AUTO_SCROLL_TIME = 0.05f; | 72 | const F32 AUTO_SCROLL_TIME = 0.05f; |
73 | const F32 LABEL_HPAD = 5.f; | 73 | const F32 LABEL_HPAD = 5.f; |
74 | 74 | ||
75 | const F32 PREEDIT_MARKER_BRIGHTNESS = 0.4f; | ||
76 | const S32 PREEDIT_MARKER_GAP = 1; | ||
77 | const S32 PREEDIT_MARKER_POSITION = 2; | ||
78 | const S32 PREEDIT_MARKER_THICKNESS = 1; | ||
79 | const F32 PREEDIT_STANDOUT_BRIGHTNESS = 0.6f; | ||
80 | const S32 PREEDIT_STANDOUT_GAP = 1; | ||
81 | const S32 PREEDIT_STANDOUT_POSITION = 2; | ||
82 | const S32 PREEDIT_STANDOUT_THICKNESS = 2; | ||
83 | |||
75 | // This is a friend class of and is only used by LLLineEditor | 84 | // This is a friend class of and is only used by LLLineEditor |
76 | class LLLineEditorRollback | 85 | class LLLineEditorRollback |
77 | { | 86 | { |
@@ -119,7 +128,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect, | |||
119 | S32 max_length_bytes, | 128 | S32 max_length_bytes, |
120 | void (*commit_callback)(LLUICtrl* caller, void* user_data ), | 129 | void (*commit_callback)(LLUICtrl* caller, void* user_data ), |
121 | void (*keystroke_callback)(LLLineEditor* caller, void* user_data ), | 130 | void (*keystroke_callback)(LLLineEditor* caller, void* user_data ), |
122 | void (*focus_lost_callback)(LLUICtrl* caller, void* user_data ), | 131 | void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data ), |
123 | void* userdata, | 132 | void* userdata, |
124 | LLLinePrevalidateFunc prevalidate_func, | 133 | LLLinePrevalidateFunc prevalidate_func, |
125 | LLViewBorder::EBevel border_bevel, | 134 | LLViewBorder::EBevel border_bevel, |
@@ -127,7 +136,6 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect, | |||
127 | S32 border_thickness) | 136 | S32 border_thickness) |
128 | : | 137 | : |
129 | LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ), | 138 | LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ), |
130 | mMaxLengthChars(max_length_bytes), | ||
131 | mMaxLengthBytes(max_length_bytes), | 139 | mMaxLengthBytes(max_length_bytes), |
132 | mCursorPos( 0 ), | 140 | mCursorPos( 0 ), |
133 | mScrollHPos( 0 ), | 141 | mScrollHPos( 0 ), |
@@ -223,12 +231,19 @@ LLString LLLineEditor::getWidgetTag() const | |||
223 | return LL_LINE_EDITOR_TAG; | 231 | return LL_LINE_EDITOR_TAG; |
224 | } | 232 | } |
225 | 233 | ||
226 | void LLLineEditor::onFocusLost() | 234 | void LLLineEditor::onFocusReceived() |
227 | { | 235 | { |
228 | // Need to notify early when loosing focus. | 236 | LLUICtrl::onFocusReceived(); |
229 | getWindow()->allowLanguageTextInput(FALSE); | 237 | updateAllowingLanguageInput(); |
238 | } | ||
230 | 239 | ||
231 | LLUICtrl::onFocusLost(); | 240 | void LLLineEditor::onFocusLost() |
241 | { | ||
242 | // The call to updateAllowLanguageInput() | ||
243 | // when loosing the keyboard focus *may* | ||
244 | // indirectly invoke handleUnicodeCharHere(), | ||
245 | // so it must be called before onCommit. | ||
246 | updateAllowingLanguageInput(); | ||
232 | 247 | ||
233 | if( mCommitOnFocusLost && mText.getString() != mPrevText) | 248 | if( mCommitOnFocusLost && mText.getString() != mPrevText) |
234 | { | 249 | { |
@@ -241,6 +256,8 @@ void LLLineEditor::onFocusLost() | |||
241 | } | 256 | } |
242 | 257 | ||
243 | getWindow()->showCursorFromMouseMove(); | 258 | getWindow()->showCursorFromMouseMove(); |
259 | |||
260 | LLUICtrl::onFocusLost(); | ||
244 | } | 261 | } |
245 | 262 | ||
246 | void LLLineEditor::onCommit() | 263 | void LLLineEditor::onCommit() |
@@ -301,6 +318,7 @@ void LLLineEditor::setEnabled(BOOL enabled) | |||
301 | { | 318 | { |
302 | mReadOnly = !enabled; | 319 | mReadOnly = !enabled; |
303 | setTabStop(!mReadOnly); | 320 | setTabStop(!mReadOnly); |
321 | updateAllowingLanguageInput(); | ||
304 | } | 322 | } |
305 | 323 | ||
306 | 324 | ||
@@ -308,7 +326,6 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length) | |||
308 | { | 326 | { |
309 | S32 max_len = llmax(0, max_text_length); | 327 | S32 max_len = llmax(0, max_text_length); |
310 | mMaxLengthBytes = max_len; | 328 | mMaxLengthBytes = max_len; |
311 | mMaxLengthChars = max_len; | ||
312 | } | 329 | } |
313 | 330 | ||
314 | void LLLineEditor::setBorderWidth(S32 left, S32 right) | 331 | void LLLineEditor::setBorderWidth(S32 left, S32 right) |
@@ -334,18 +351,22 @@ void LLLineEditor::setText(const LLStringExplicit &new_text) | |||
334 | 351 | ||
335 | // Check to see if entire field is selected. | 352 | // Check to see if entire field is selected. |
336 | S32 len = mText.length(); | 353 | S32 len = mText.length(); |
337 | BOOL allSelected = (len > 0) && (( mSelectionStart == 0 && mSelectionEnd == len ) | 354 | BOOL all_selected = (len > 0) |
338 | || ( mSelectionStart == len && mSelectionEnd == 0 )); | 355 | && (( mSelectionStart == 0 && mSelectionEnd == len ) |
356 | || ( mSelectionStart == len && mSelectionEnd == 0 )); | ||
357 | |||
358 | // Do safe truncation so we don't split multi-byte characters | ||
359 | // also consider entire string selected when mSelectAllonFocusReceived is set on an empty, focused line editor | ||
360 | all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived); | ||
339 | 361 | ||
340 | LLString truncated_utf8 = new_text; | 362 | LLString truncated_utf8 = new_text; |
341 | if (truncated_utf8.size() > (U32)mMaxLengthBytes) | 363 | if (truncated_utf8.size() > (U32)mMaxLengthBytes) |
342 | { | 364 | { |
343 | utf8str_truncate(truncated_utf8, mMaxLengthBytes); | 365 | truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes); |
344 | } | 366 | } |
345 | mText.assign(truncated_utf8); | 367 | mText.assign(truncated_utf8); |
346 | mText.truncate(mMaxLengthChars); | ||
347 | 368 | ||
348 | if (allSelected) | 369 | if (all_selected) |
349 | { | 370 | { |
350 | // ...keep whole thing selected | 371 | // ...keep whole thing selected |
351 | selectAll(); | 372 | selectAll(); |
@@ -735,17 +756,12 @@ void LLLineEditor::addChar(const llwchar uni_char) | |||
735 | mText.erase(getCursor(), 1); | 756 | mText.erase(getCursor(), 1); |
736 | } | 757 | } |
737 | 758 | ||
738 | S32 length_chars = mText.length(); | 759 | S32 cur_bytes = mText.getString().size(); |
739 | S32 cur_bytes = mText.getString().size();; | ||
740 | S32 new_bytes = wchar_utf8_length(new_c); | 760 | S32 new_bytes = wchar_utf8_length(new_c); |
741 | 761 | ||
742 | BOOL allow_char = TRUE; | 762 | BOOL allow_char = TRUE; |
743 | 763 | ||
744 | // Inserting character | 764 | // Check byte length limit |
745 | if (length_chars == mMaxLengthChars) | ||
746 | { | ||
747 | allow_char = FALSE; | ||
748 | } | ||
749 | if ((new_bytes + cur_bytes) > mMaxLengthBytes) | 765 | if ((new_bytes + cur_bytes) > mMaxLengthBytes) |
750 | { | 766 | { |
751 | allow_char = FALSE; | 767 | allow_char = FALSE; |
@@ -794,6 +810,12 @@ void LLLineEditor::setSelection(S32 start, S32 end) | |||
794 | setCursor(start); | 810 | setCursor(start); |
795 | } | 811 | } |
796 | 812 | ||
813 | void LLLineEditor::setDrawAsterixes(BOOL b) | ||
814 | { | ||
815 | mDrawAsterixes = b; | ||
816 | updateAllowingLanguageInput(); | ||
817 | } | ||
818 | |||
797 | S32 LLLineEditor::prevWordPos(S32 cursorPos) const | 819 | S32 LLLineEditor::prevWordPos(S32 cursorPos) const |
798 | { | 820 | { |
799 | const LLWString& wtext = mText.getWString(); | 821 | const LLWString& wtext = mText.getWString(); |
@@ -1022,13 +1044,11 @@ void LLLineEditor::paste() | |||
1022 | 1044 | ||
1023 | // Insert the string | 1045 | // Insert the string |
1024 | 1046 | ||
1025 | //check to see that the size isn't going to be larger than the | 1047 | // Check to see that the size isn't going to be larger than the max number of bytes |
1026 | //max number of characters or bytes | ||
1027 | U32 available_bytes = mMaxLengthBytes - wstring_utf8_length(mText); | 1048 | U32 available_bytes = mMaxLengthBytes - wstring_utf8_length(mText); |
1028 | size_t available_chars = mMaxLengthChars - mText.length(); | ||
1029 | 1049 | ||
1030 | if ( available_bytes < (U32) wstring_utf8_length(clean_string) ) | 1050 | if ( available_bytes < (U32) wstring_utf8_length(clean_string) ) |
1031 | { | 1051 | { // Doesn't all fit |
1032 | llwchar current_symbol = clean_string[0]; | 1052 | llwchar current_symbol = clean_string[0]; |
1033 | U32 wchars_that_fit = 0; | 1053 | U32 wchars_that_fit = 0; |
1034 | U32 total_bytes = wchar_utf8_length(current_symbol); | 1054 | U32 total_bytes = wchar_utf8_length(current_symbol); |
@@ -1043,20 +1063,13 @@ void LLLineEditor::paste() | |||
1043 | current_symbol = clean_string[++wchars_that_fit]; | 1063 | current_symbol = clean_string[++wchars_that_fit]; |
1044 | total_bytes += wchar_utf8_length(current_symbol); | 1064 | total_bytes += wchar_utf8_length(current_symbol); |
1045 | } | 1065 | } |
1046 | 1066 | // Truncate the clean string at the limit of what will fit | |
1047 | clean_string = clean_string.substr(0, wchars_that_fit); | 1067 | clean_string = clean_string.substr(0, wchars_that_fit); |
1048 | reportBadKeystroke(); | 1068 | reportBadKeystroke(); |
1049 | } | 1069 | } |
1050 | else if (available_chars < clean_string.length()) | ||
1051 | { | ||
1052 | // We can't insert all the characters. Insert as many as possible | ||
1053 | // but make a noise to alert the user. JC | ||
1054 | clean_string = clean_string.substr(0, available_chars); | ||
1055 | reportBadKeystroke(); | ||
1056 | } | ||
1057 | 1070 | ||
1058 | mText.insert(getCursor(), clean_string); | 1071 | mText.insert(getCursor(), clean_string); |
1059 | setCursor(llmin(mMaxLengthChars, getCursor() + (S32)clean_string.length())); | 1072 | setCursor( getCursor() + (S32)clean_string.length() ); |
1060 | deselect(); | 1073 | deselect(); |
1061 | 1074 | ||
1062 | // Validate new string and rollback the if needed. | 1075 | // Validate new string and rollback the if needed. |
@@ -1523,6 +1536,41 @@ void LLLineEditor::draw() | |||
1523 | } | 1536 | } |
1524 | LLColor4 label_color = mTentativeFgColor; | 1537 | LLColor4 label_color = mTentativeFgColor; |
1525 | 1538 | ||
1539 | if (hasPreeditString()) | ||
1540 | { | ||
1541 | // Draw preedit markers. This needs to be before drawing letters. | ||
1542 | for (U32 i = 0; i < mPreeditStandouts.size(); i++) | ||
1543 | { | ||
1544 | const S32 preedit_left = mPreeditPositions[i]; | ||
1545 | const S32 preedit_right = mPreeditPositions[i + 1]; | ||
1546 | if (preedit_right > mScrollHPos) | ||
1547 | { | ||
1548 | S32 preedit_pixels_left = findPixelNearestPos(llmax(preedit_left, mScrollHPos) - getCursor()); | ||
1549 | S32 preedit_pixels_right = llmin(findPixelNearestPos(preedit_right - getCursor()), background.mRight); | ||
1550 | if (preedit_pixels_left >= background.mRight) | ||
1551 | { | ||
1552 | break; | ||
1553 | } | ||
1554 | if (mPreeditStandouts[i]) | ||
1555 | { | ||
1556 | gl_rect_2d(preedit_pixels_left + PREEDIT_STANDOUT_GAP, | ||
1557 | background.mBottom + PREEDIT_STANDOUT_POSITION, | ||
1558 | preedit_pixels_right - PREEDIT_STANDOUT_GAP - 1, | ||
1559 | background.mBottom + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS, | ||
1560 | (text_color * PREEDIT_STANDOUT_BRIGHTNESS + bg_color * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f)); | ||
1561 | } | ||
1562 | else | ||
1563 | { | ||
1564 | gl_rect_2d(preedit_pixels_left + PREEDIT_MARKER_GAP, | ||
1565 | background.mBottom + PREEDIT_MARKER_POSITION, | ||
1566 | preedit_pixels_right - PREEDIT_MARKER_GAP - 1, | ||
1567 | background.mBottom + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS, | ||
1568 | (text_color * PREEDIT_MARKER_BRIGHTNESS + bg_color * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f)); | ||
1569 | } | ||
1570 | } | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1526 | S32 rendered_text = 0; | 1574 | S32 rendered_text = 0; |
1527 | F32 rendered_pixels_right = (F32)mMinHPixels; | 1575 | F32 rendered_pixels_right = (F32)mMinHPixels; |
1528 | F32 text_bottom = (F32)background.mBottom + (F32)UI_LINEEDITOR_V_PAD; | 1576 | F32 text_bottom = (F32)background.mBottom + (F32)UI_LINEEDITOR_V_PAD; |
@@ -1677,7 +1725,7 @@ void LLLineEditor::draw() | |||
1677 | 1725 | ||
1678 | 1726 | ||
1679 | // Returns the local screen space X coordinate associated with the text cursor position. | 1727 | // Returns the local screen space X coordinate associated with the text cursor position. |
1680 | S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) | 1728 | S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const |
1681 | { | 1729 | { |
1682 | S32 dpos = getCursor() - mScrollHPos + cursor_offset; | 1730 | S32 dpos = getCursor() - mScrollHPos + cursor_offset; |
1683 | S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mMinHPixels; | 1731 | S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mMinHPixels; |
@@ -1715,7 +1763,7 @@ void LLLineEditor::setFocus( BOOL new_state ) | |||
1715 | 1763 | ||
1716 | if (!new_state) | 1764 | if (!new_state) |
1717 | { | 1765 | { |
1718 | getWindow()->allowLanguageTextInput(FALSE); | 1766 | getWindow()->allowLanguageTextInput(this, FALSE); |
1719 | } | 1767 | } |
1720 | 1768 | ||
1721 | 1769 | ||
@@ -1757,7 +1805,7 @@ void LLLineEditor::setFocus( BOOL new_state ) | |||
1757 | // fine on 1.15.0.2, since all prevalidate func reject any | 1805 | // fine on 1.15.0.2, since all prevalidate func reject any |
1758 | // non-ASCII characters. I'm not sure on future versions, | 1806 | // non-ASCII characters. I'm not sure on future versions, |
1759 | // however. | 1807 | // however. |
1760 | getWindow()->allowLanguageTextInput(mPrevalidateFunc == NULL); | 1808 | getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL); |
1761 | } | 1809 | } |
1762 | } | 1810 | } |
1763 | 1811 | ||
@@ -1776,6 +1824,12 @@ void LLLineEditor::setRect(const LLRect& rect) | |||
1776 | } | 1824 | } |
1777 | } | 1825 | } |
1778 | 1826 | ||
1827 | void LLLineEditor::setPrevalidate(BOOL (*func)(const LLWString &)) | ||
1828 | { | ||
1829 | mPrevalidateFunc = func; | ||
1830 | updateAllowingLanguageInput(); | ||
1831 | } | ||
1832 | |||
1779 | // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. | 1833 | // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. |
1780 | // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for | 1834 | // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for |
1781 | // the simple reasons that intermediate states may be invalid even if the final result is valid. | 1835 | // the simple reasons that intermediate states may be invalid even if the final result is valid. |
@@ -2336,6 +2390,239 @@ BOOL LLLineEditor::setLabelArg( const LLString& key, const LLStringExplicit& tex | |||
2336 | return TRUE; | 2390 | return TRUE; |
2337 | } | 2391 | } |
2338 | 2392 | ||
2393 | |||
2394 | void LLLineEditor::updateAllowingLanguageInput() | ||
2395 | { | ||
2396 | // Allow Language Text Input only when this LineEditor has | ||
2397 | // no prevalidate function attached (as long as other criteria | ||
2398 | // common to LLTextEditor). This criterion works | ||
2399 | // fine on 1.15.0.2, since all prevalidate func reject any | ||
2400 | // non-ASCII characters. I'm not sure on future versions, | ||
2401 | // however... | ||
2402 | if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) | ||
2403 | { | ||
2404 | getWindow()->allowLanguageTextInput(this, TRUE); | ||
2405 | } | ||
2406 | else | ||
2407 | { | ||
2408 | getWindow()->allowLanguageTextInput(this, FALSE); | ||
2409 | } | ||
2410 | } | ||
2411 | |||
2412 | BOOL LLLineEditor::hasPreeditString() const | ||
2413 | { | ||
2414 | return (mPreeditPositions.size() > 1); | ||
2415 | } | ||
2416 | |||
2417 | void LLLineEditor::resetPreedit() | ||
2418 | { | ||
2419 | if (hasPreeditString()) | ||
2420 | { | ||
2421 | const S32 preedit_pos = mPreeditPositions.front(); | ||
2422 | mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos); | ||
2423 | mText.insert(preedit_pos, mPreeditOverwrittenWString); | ||
2424 | setCursor(preedit_pos); | ||
2425 | |||
2426 | mPreeditWString.clear(); | ||
2427 | mPreeditOverwrittenWString.clear(); | ||
2428 | mPreeditPositions.clear(); | ||
2429 | |||
2430 | mKeystrokeTimer.reset(); | ||
2431 | if (mKeystrokeCallback) | ||
2432 | { | ||
2433 | mKeystrokeCallback(this, mCallbackUserData); | ||
2434 | } | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | void LLLineEditor::updatePreedit(const LLWString &preedit_string, | ||
2439 | const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) | ||
2440 | { | ||
2441 | // Just in case. | ||
2442 | if (mReadOnly) | ||
2443 | { | ||
2444 | return; | ||
2445 | } | ||
2446 | |||
2447 | if (hasSelection()) | ||
2448 | { | ||
2449 | if (hasPreeditString()) | ||
2450 | { | ||
2451 | llwarns << "Preedit and selection!" << llendl; | ||
2452 | deselect(); | ||
2453 | } | ||
2454 | else | ||
2455 | { | ||
2456 | deleteSelection(); | ||
2457 | } | ||
2458 | } | ||
2459 | |||
2460 | S32 insert_preedit_at = getCursor(); | ||
2461 | if (hasPreeditString()) | ||
2462 | { | ||
2463 | insert_preedit_at = mPreeditPositions.front(); | ||
2464 | //mText.replace(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at, mPreeditOverwrittenWString); | ||
2465 | mText.erase(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at); | ||
2466 | mText.insert(insert_preedit_at, mPreeditOverwrittenWString); | ||
2467 | } | ||
2468 | |||
2469 | mPreeditWString = preedit_string; | ||
2470 | mPreeditPositions.resize(preedit_segment_lengths.size() + 1); | ||
2471 | S32 position = insert_preedit_at; | ||
2472 | for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) | ||
2473 | { | ||
2474 | mPreeditPositions[i] = position; | ||
2475 | position += preedit_segment_lengths[i]; | ||
2476 | } | ||
2477 | mPreeditPositions.back() = position; | ||
2478 | if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) | ||
2479 | { | ||
2480 | mPreeditOverwrittenWString.assign( LLWString( mText, insert_preedit_at, mPreeditWString.length() ) ); | ||
2481 | mText.erase(insert_preedit_at, mPreeditWString.length()); | ||
2482 | } | ||
2483 | else | ||
2484 | { | ||
2485 | mPreeditOverwrittenWString.clear(); | ||
2486 | } | ||
2487 | mText.insert(insert_preedit_at, mPreeditWString); | ||
2488 | |||
2489 | mPreeditStandouts = preedit_standouts; | ||
2490 | |||
2491 | setCursor(position); | ||
2492 | setCursor(mPreeditPositions.front() + caret_position); | ||
2493 | |||
2494 | // Update of the preedit should be caused by some key strokes. | ||
2495 | mKeystrokeTimer.reset(); | ||
2496 | if( mKeystrokeCallback ) | ||
2497 | { | ||
2498 | mKeystrokeCallback( this, mCallbackUserData ); | ||
2499 | } | ||
2500 | } | ||
2501 | |||
2502 | BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const | ||
2503 | { | ||
2504 | if (control) | ||
2505 | { | ||
2506 | LLRect control_rect_screen; | ||
2507 | localRectToScreen(mRect, &control_rect_screen); | ||
2508 | LLUI::screenRectToGL(control_rect_screen, control); | ||
2509 | } | ||
2510 | |||
2511 | S32 preedit_left_column, preedit_right_column; | ||
2512 | if (hasPreeditString()) | ||
2513 | { | ||
2514 | preedit_left_column = mPreeditPositions.front(); | ||
2515 | preedit_right_column = mPreeditPositions.back(); | ||
2516 | } | ||
2517 | else | ||
2518 | { | ||
2519 | preedit_left_column = preedit_right_column = getCursor(); | ||
2520 | } | ||
2521 | if (preedit_right_column < mScrollHPos) | ||
2522 | { | ||
2523 | // This should not occure... | ||
2524 | return FALSE; | ||
2525 | } | ||
2526 | |||
2527 | const S32 query = (query_offset >= 0 ? preedit_left_column + query_offset : getCursor()); | ||
2528 | if (query < mScrollHPos || query < preedit_left_column || query > preedit_right_column) | ||
2529 | { | ||
2530 | return FALSE; | ||
2531 | } | ||
2532 | |||
2533 | if (coord) | ||
2534 | { | ||
2535 | S32 query_local = findPixelNearestPos(query - getCursor()); | ||
2536 | S32 query_screen_x, query_screen_y; | ||
2537 | localPointToScreen(query_local, mRect.getHeight() / 2, &query_screen_x, &query_screen_y); | ||
2538 | LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); | ||
2539 | } | ||
2540 | |||
2541 | if (bounds) | ||
2542 | { | ||
2543 | S32 preedit_left_local = findPixelNearestPos(llmax(preedit_left_column, mScrollHPos) - getCursor()); | ||
2544 | S32 preedit_right_local = llmin(findPixelNearestPos(preedit_right_column - getCursor()), mRect.getWidth() - mBorderThickness); | ||
2545 | if (preedit_left_local > preedit_right_local) | ||
2546 | { | ||
2547 | // Is this condition possible? | ||
2548 | preedit_right_local = preedit_left_local; | ||
2549 | } | ||
2550 | |||
2551 | LLRect preedit_rect_local(preedit_left_local, mRect.getHeight(), preedit_right_local, 0); | ||
2552 | LLRect preedit_rect_screen; | ||
2553 | localRectToScreen(preedit_rect_local, &preedit_rect_screen); | ||
2554 | LLUI::screenRectToGL(preedit_rect_screen, bounds); | ||
2555 | } | ||
2556 | |||
2557 | return TRUE; | ||
2558 | } | ||
2559 | |||
2560 | void LLLineEditor::getPreeditRange(S32 *position, S32 *length) const | ||
2561 | { | ||
2562 | if (hasPreeditString()) | ||
2563 | { | ||
2564 | *position = mPreeditPositions.front(); | ||
2565 | *length = mPreeditPositions.back() - mPreeditPositions.front(); | ||
2566 | } | ||
2567 | else | ||
2568 | { | ||
2569 | *position = mCursorPos; | ||
2570 | *length = 0; | ||
2571 | } | ||
2572 | } | ||
2573 | |||
2574 | void LLLineEditor::getSelectionRange(S32 *position, S32 *length) const | ||
2575 | { | ||
2576 | if (hasSelection()) | ||
2577 | { | ||
2578 | *position = llmin(mSelectionStart, mSelectionEnd); | ||
2579 | *length = llabs(mSelectionStart - mSelectionEnd); | ||
2580 | } | ||
2581 | else | ||
2582 | { | ||
2583 | *position = mCursorPos; | ||
2584 | *length = 0; | ||
2585 | } | ||
2586 | } | ||
2587 | |||
2588 | void LLLineEditor::markAsPreedit(S32 position, S32 length) | ||
2589 | { | ||
2590 | deselect(); | ||
2591 | setCursor(position); | ||
2592 | if (hasPreeditString()) | ||
2593 | { | ||
2594 | llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl; | ||
2595 | } | ||
2596 | mPreeditWString.assign( LLWString( mText.getWString(), position, length ) ); | ||
2597 | if (length > 0) | ||
2598 | { | ||
2599 | mPreeditPositions.resize(2); | ||
2600 | mPreeditPositions[0] = position; | ||
2601 | mPreeditPositions[1] = position + length; | ||
2602 | mPreeditStandouts.resize(1); | ||
2603 | mPreeditStandouts[0] = FALSE; | ||
2604 | } | ||
2605 | else | ||
2606 | { | ||
2607 | mPreeditPositions.clear(); | ||
2608 | mPreeditStandouts.clear(); | ||
2609 | } | ||
2610 | if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) | ||
2611 | { | ||
2612 | mPreeditOverwrittenWString = mPreeditWString; | ||
2613 | } | ||
2614 | else | ||
2615 | { | ||
2616 | mPreeditOverwrittenWString.clear(); | ||
2617 | } | ||
2618 | } | ||
2619 | |||
2620 | S32 LLLineEditor::getPreeditFontSize() const | ||
2621 | { | ||
2622 | return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]); | ||
2623 | } | ||
2624 | |||
2625 | |||
2339 | LLSearchEditor::LLSearchEditor(const LLString& name, | 2626 | LLSearchEditor::LLSearchEditor(const LLString& name, |
2340 | const LLRect& rect, | 2627 | const LLRect& rect, |
2341 | S32 max_length_bytes, | 2628 | S32 max_length_bytes, |