aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/lllineeditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llui/lllineeditor.cpp363
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
72const F32 AUTO_SCROLL_TIME = 0.05f; 72const F32 AUTO_SCROLL_TIME = 0.05f;
73const F32 LABEL_HPAD = 5.f; 73const F32 LABEL_HPAD = 5.f;
74 74
75const F32 PREEDIT_MARKER_BRIGHTNESS = 0.4f;
76const S32 PREEDIT_MARKER_GAP = 1;
77const S32 PREEDIT_MARKER_POSITION = 2;
78const S32 PREEDIT_MARKER_THICKNESS = 1;
79const F32 PREEDIT_STANDOUT_BRIGHTNESS = 0.6f;
80const S32 PREEDIT_STANDOUT_GAP = 1;
81const S32 PREEDIT_STANDOUT_POSITION = 2;
82const 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
76class LLLineEditorRollback 85class 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
226void LLLineEditor::onFocusLost() 234void 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(); 240void 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
246void LLLineEditor::onCommit() 263void 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
314void LLLineEditor::setBorderWidth(S32 left, S32 right) 331void 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
813void LLLineEditor::setDrawAsterixes(BOOL b)
814{
815 mDrawAsterixes = b;
816 updateAllowingLanguageInput();
817}
818
797S32 LLLineEditor::prevWordPos(S32 cursorPos) const 819S32 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.
1680S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) 1728S32 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
1827void 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
2394void 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
2412BOOL LLLineEditor::hasPreeditString() const
2413{
2414 return (mPreeditPositions.size() > 1);
2415}
2416
2417void 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
2438void 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
2502BOOL 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
2560void 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
2574void 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
2588void 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
2620S32 LLLineEditor::getPreeditFontSize() const
2621{
2622 return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
2623}
2624
2625
2339LLSearchEditor::LLSearchEditor(const LLString& name, 2626LLSearchEditor::LLSearchEditor(const LLString& name,
2340 const LLRect& rect, 2627 const LLRect& rect,
2341 S32 max_length_bytes, 2628 S32 max_length_bytes,