summaryrefslogtreecommitdiff
path: root/indra/llui/lltexteditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/lltexteditor.cpp')
-rw-r--r--indra/llui/lltexteditor.cpp1981
1 files changed, 103 insertions, 1878 deletions
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 39f09b297f..997c5b8fa8 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -77,106 +77,31 @@ static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor");
//
const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32;
const S32 UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4;
-const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
-const S32 CURSOR_THICKNESS = 2;
const S32 SPACES_PER_TAB = 4;
-
-// helper functors
-struct LLTextEditor::compare_bottom
-{
- bool operator()(const S32& a, const LLTextEditor::line_info& b) const
- {
- return a > b.mBottom; // bottom of a is higher than bottom of b
- }
-
- bool operator()(const LLTextEditor::line_info& a, const S32& b) const
- {
- return a.mBottom > b; // bottom of a is higher than bottom of b
- }
-
- bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
- {
- return a.mBottom > b.mBottom; // bottom of a is higher than bottom of b
- }
-
-};
-
-// helper functors
-struct LLTextEditor::compare_top
-{
- bool operator()(const S32& a, const LLTextEditor::line_info& b) const
- {
- return a > b.mTop; // top of a is higher than top of b
- }
-
- bool operator()(const LLTextEditor::line_info& a, const S32& b) const
- {
- return a.mTop > b; // top of a is higher than top of b
- }
-
- bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
- {
- return a.mTop > b.mTop; // top of a is higher than top of b
- }
-};
-
-struct LLTextEditor::line_end_compare
-{
- bool operator()(const S32& pos, const LLTextEditor::line_info& info) const
- {
- return (pos < info.mDocIndexEnd);
- }
-
- bool operator()(const LLTextEditor::line_info& info, const S32& pos) const
- {
- return (info.mDocIndexEnd < pos);
- }
-
- bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
- {
- return (a.mDocIndexEnd < b.mDocIndexEnd);
- }
-
-};
-
-//
-// DocumentPanel
-//
-
-class DocumentPanel : public LLPanel
-{
-public:
- DocumentPanel(const Params&);
-};
-
-DocumentPanel::DocumentPanel(const Params& p)
-: LLPanel(p)
-{}
-
///////////////////////////////////////////////////////////////////
-class LLTextEditor::LLTextCmdInsert : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd
{
public:
- LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment)
- : LLTextCmd(pos, group_with_next, segment), mWString(ws)
+ TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment)
+ : TextCmd(pos, group_with_next, segment), mWString(ws)
{
}
- virtual ~LLTextCmdInsert() {}
- virtual BOOL execute( LLTextEditor* editor, S32* delta )
+ virtual ~TextCmdInsert() {}
+ virtual BOOL execute( LLTextBase* editor, S32* delta )
{
*delta = insert(editor, getPosition(), mWString );
LLWStringUtil::truncate(mWString, *delta);
//mWString = wstring_truncate(mWString, *delta);
return (*delta != 0);
}
- virtual S32 undo( LLTextEditor* editor )
+ virtual S32 undo( LLTextBase* editor )
{
remove(editor, getPosition(), mWString.length() );
return getPosition();
}
- virtual S32 redo( LLTextEditor* editor )
+ virtual S32 redo( LLTextBase* editor )
{
insert(editor, getPosition(), mWString );
return getPosition() + mWString.length();
@@ -187,11 +112,11 @@ private:
};
///////////////////////////////////////////////////////////////////
-class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd
{
public:
- LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment)
- : LLTextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE)
+ TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment)
+ : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE)
{
}
virtual void blockExtensions()
@@ -205,14 +130,14 @@ public:
return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length());
}
- virtual BOOL execute( LLTextEditor* editor, S32* delta )
+ virtual BOOL execute( LLTextBase* editor, S32* delta )
{
*delta = insert(editor, getPosition(), mWString);
LLWStringUtil::truncate(mWString, *delta);
//mWString = wstring_truncate(mWString, *delta);
return (*delta != 0);
}
- virtual BOOL extendAndExecute( LLTextEditor* editor, S32 pos, llwchar wc, S32* delta )
+ virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta )
{
LLWString ws;
ws += wc;
@@ -224,12 +149,12 @@ public:
}
return (*delta != 0);
}
- virtual S32 undo( LLTextEditor* editor )
+ virtual S32 undo( LLTextBase* editor )
{
remove(editor, getPosition(), mWString.length() );
return getPosition();
}
- virtual S32 redo( LLTextEditor* editor )
+ virtual S32 redo( LLTextBase* editor )
{
insert(editor, getPosition(), mWString );
return getPosition() + mWString.length();
@@ -243,25 +168,25 @@ private:
///////////////////////////////////////////////////////////////////
-class LLTextEditor::LLTextCmdOverwriteChar : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd
{
public:
- LLTextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc)
- : LLTextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {}
+ TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc)
+ : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {}
- virtual BOOL execute( LLTextEditor* editor, S32* delta )
+ virtual BOOL execute( LLTextBase* editor, S32* delta )
{
- mOldChar = editor->getWChar(getPosition());
+ mOldChar = editor->getWText()[getPosition()];
overwrite(editor, getPosition(), mChar);
*delta = 0;
return TRUE;
}
- virtual S32 undo( LLTextEditor* editor )
+ virtual S32 undo( LLTextBase* editor )
{
overwrite(editor, getPosition(), mOldChar);
return getPosition();
}
- virtual S32 redo( LLTextEditor* editor )
+ virtual S32 redo( LLTextBase* editor )
{
overwrite(editor, getPosition(), mChar);
return getPosition()+1;
@@ -274,26 +199,26 @@ private:
///////////////////////////////////////////////////////////////////
-class LLTextEditor::LLTextCmdRemove : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd
{
public:
- LLTextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) :
- LLTextCmd(pos, group_with_next), mLen(len)
+ TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) :
+ TextCmd(pos, group_with_next), mLen(len)
{
std::swap(mSegments, segments);
}
- virtual BOOL execute( LLTextEditor* editor, S32* delta )
+ virtual BOOL execute( LLTextBase* editor, S32* delta )
{
- mWString = editor->getWSubString(getPosition(), mLen);
+ mWString = editor->getWText().substr(getPosition(), mLen);
*delta = remove(editor, getPosition(), mLen );
return (*delta != 0);
}
- virtual S32 undo( LLTextEditor* editor )
+ virtual S32 undo( LLTextBase* editor )
{
insert(editor, getPosition(), mWString);
return getPosition() + mWString.length();
}
- virtual S32 redo( LLTextEditor* editor )
+ virtual S32 redo( LLTextBase* editor )
{
remove(editor, getPosition(), mLen );
return getPosition();
@@ -307,138 +232,61 @@ private:
///////////////////////////////////////////////////////////////////
LLTextEditor::Params::Params()
: default_text("default_text"),
- max_text_length("max_length", 255),
- read_only("read_only", false),
embedded_items("embedded_items", false),
- hide_scrollbar("hide_scrollbar"),
- hide_border("hide_border", false),
- word_wrap("word_wrap", false),
ignore_tab("ignore_tab", true),
- track_bottom("track_bottom", false),
handle_edit_keys_directly("handle_edit_keys_directly", false),
show_line_numbers("show_line_numbers", false),
- cursor_color("cursor_color"),
default_color("default_color"),
- text_color("text_color"),
- text_readonly_color("text_readonly_color"),
- bg_readonly_color("bg_readonly_color"),
- bg_writeable_color("bg_writeable_color"),
- bg_focus_color("bg_focus_color"),
- link_color("link_color"),
- commit_on_focus_lost("commit_on_focus_lost", false),
- length("length"), // ignored
- type("type"), // ignored
- is_unicode("is_unicode")// ignored
+ commit_on_focus_lost("commit_on_focus_lost", false)
{}
LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
- LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
LLTextBase(p),
- mMaxTextByteLength( p.max_text_length ),
mBaseDocIsPristine(TRUE),
mPristineCmd( NULL ),
mLastCmd( NULL ),
- mCursorPos( 0 ),
- mIsSelecting( FALSE ),
- mSelectionStart( 0 ),
- mSelectionEnd( 0 ),
- mOnScrollEndData( NULL ),
- mCursorColor( p.cursor_color() ),
- mFgColor( p.text_color() ),
mDefaultColor( p.default_color() ),
- mReadOnlyFgColor( p.text_readonly_color() ),
- mWriteableBgColor( p.bg_writeable_color() ),
- mReadOnlyBgColor( p.bg_readonly_color() ),
- mFocusBgColor( p.bg_focus_color() ),
- mLinkColor( p.link_color() ),
- mReadOnly(p.read_only),
mShowLineNumbers ( p.show_line_numbers ),
mCommitOnFocusLost( p.commit_on_focus_lost),
- mTrackBottom( p.track_bottom ),
mAllowEmbeddedItems( p.embedded_items ),
mHandleEditKeysDirectly( p.handle_edit_keys_directly ),
mMouseDownX(0),
mMouseDownY(0),
- mLastSelectionX(-1),
- mReflowNeeded(FALSE),
- mScrollNeeded(FALSE),
- mLastSelectionY(-1),
- mParseHighlights(FALSE),
- mTabsToNextField(p.ignore_tab),
- mScrollIndex(-1)
+ mTabsToNextField(p.ignore_tab)
{
- static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
-
- mWordWrap = p.word_wrap;
mDefaultFont = p.font;
- mParseHTML = FALSE;
mSourceID.generate();
- // reset desired x cursor position
- mDesiredXPixel = -1;
-
- LLScrollContainer::Params scroll_params;
- scroll_params.name = "text scroller";
- scroll_params.rect = getLocalRect();
- scroll_params.follows.flags = FOLLOWS_ALL;
- scroll_params.is_opaque = false;
- scroll_params.mouse_opaque = false;
- scroll_params.min_auto_scroll_rate = 200;
- scroll_params.max_auto_scroll_rate = 800;
- mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params);
- addChild(mScroller);
-
- LLPanel::Params panel_params;
- panel_params.name = "text_contents";
- panel_params.rect = LLRect(0, 500, 500, 0);
- panel_params.background_visible = true;
- panel_params.background_opaque = true;
- panel_params.mouse_opaque = false;
-
- mDocumentPanel = LLUICtrlFactory::create<DocumentPanel>(panel_params);
- mScroller->addChild(mDocumentPanel);
-
- updateTextRect();
-
- static LLUICachedControl<S32> text_editor_border ("UITextEditorBorder", 0);
+ //FIXME: use image?
LLViewBorder::Params params;
params.name = "text ed border";
params.rect = getLocalRect();
params.bevel_style = LLViewBorder::BEVEL_IN;
- params.border_thickness = text_editor_border;
+ params.border_thickness = 1;
+ params.visible = p.border_visible;
mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
addChild( mBorder );
- mBorder->setVisible(!p.hide_border);
-
- createDefaultSegment();
- appendText(p.default_text, FALSE, FALSE);
+ setText(p.default_text());
+ if (mShowLineNumbers)
+ {
+ mHPad += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
+ updateTextRect();
+ }
}
void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
{
- resetDirty(); // Update saved text state
- LLUICtrl::initFromParams(p);
- // HACK: work around enabled == readonly design bug -- RN
- // setEnabled will modify our read only status, so do this after
- // LLUICtrl::initFromParams
- if (p.read_only.isProvided())
- {
- mReadOnly = p.read_only;
- }
-
+ LLTextBase::initFromParams(p);
+
if (p.commit_on_focus_lost.isProvided())
{
mCommitOnFocusLost = p.commit_on_focus_lost;
}
- updateSegments();
updateAllowingLanguageInput();
-
- // HACK: text editors always need to be enabled so that we can scroll
- LLView::setEnabled(true);
}
LLTextEditor::~LLTextEditor()
@@ -455,282 +303,18 @@ LLTextEditor::~LLTextEditor()
std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
}
-LLTextViewModel* LLTextEditor::getViewModel() const
-{
- return (LLTextViewModel*)mViewModel.get();
-}
-
-static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");
-void LLTextEditor::reflow(S32 start_index)
-{
- if (!mReflowNeeded) return;
-
- LLFastTimer ft(FTM_TEXT_REFLOW);
- static LLUICachedControl<S32> texteditor_vpad_top ("UITextEditorVPadTop", 0);
-
- updateSegments();
-
- while(mReflowNeeded)
- {
- bool scrolled_to_bottom = mScroller->isAtBottom();
- mReflowNeeded = FALSE;
-
- LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos);
- bool follow_selection = mTextRect.overlaps(old_cursor_rect); // cursor is visible
- S32 first_line = getFirstVisibleLine();
- // if scroll anchor not on first line, update it to first character of first line
- if (!mLineInfoList.empty()
- && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart
- || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
- {
- mScrollIndex = mLineInfoList[first_line].mDocIndexStart;
- }
- LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
- //first_char_rect.intersectWith(mTextRect);
-
- S32 cur_top = -texteditor_vpad_top;
-
- if (getLength())
- {
- segment_set_t::iterator seg_iter = mSegments.begin();
- S32 seg_offset = 0;
- S32 line_start_index = 0;
- S32 text_width = mTextRect.getWidth(); // optionally reserve room for margin
- S32 remaining_pixels = text_width;
- LLWString text(getWText());
- S32 line_count = 0;
-
- // find and erase line info structs starting at start_index and going to end of document
- if (!mLineInfoList.empty())
- {
- // find first element whose end comes after start_index
- line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare());
- line_start_index = iter->mDocIndexStart;
- line_count = iter->mLineNum;
- getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
- mLineInfoList.erase(iter, mLineInfoList.end());
- }
-
- // reserve enough space for line numbers
- S32 line_height = mShowLineNumbers ? (S32)(LLFontGL::getFontMonospace()->getLineHeight()) : 0;
-
- while(seg_iter != mSegments.end())
- {
- LLTextSegmentPtr segment = *seg_iter;
-
- // track maximum height of any segment on this line
- line_height = llmax(line_height, segment->getMaxHeight());
- S32 cur_index = segment->getStart() + seg_offset;
- // find run of text from this segment that we can display on one line
- S32 end_index = cur_index;
- while(end_index < segment->getEnd() && text[end_index] != '\n')
- {
- ++end_index;
- }
-
- // ask segment how many character fit in remaining space
- S32 max_characters = end_index - cur_index;
- S32 character_count = segment->getNumChars(llmax(0, remaining_pixels), seg_offset, cur_index - line_start_index, max_characters);
-
- seg_offset += character_count;
-
- S32 last_segment_char_on_line = segment->getStart() + seg_offset;
-
- // if we didn't finish the current segment...
- if (last_segment_char_on_line < segment->getEnd())
- {
- // set up index for next line
- // ...skip newline, we don't want to draw
- S32 next_line_count = line_count;
- if (text[last_segment_char_on_line] == '\n')
- {
- seg_offset++;
- last_segment_char_on_line++;
- next_line_count++;
- }
-
- // add line info and keep going
- mLineInfoList.push_back(line_info(line_start_index, last_segment_char_on_line, cur_top, cur_top - line_height, line_count));
-
- line_start_index = segment->getStart() + seg_offset;
- cur_top -= line_height;
- remaining_pixels = text_width;
- line_height = 0;
- line_count = next_line_count;
- }
- // ...just consumed last segment..
- else if (++segment_set_t::iterator(seg_iter) == mSegments.end())
- {
- mLineInfoList.push_back(line_info(line_start_index, last_segment_char_on_line, cur_top, cur_top - line_height, line_count));
- cur_top -= line_height;
- break;
- }
- // finished a segment and there are segments remaining on this line
- else
- {
- // subtract pixels used and increment segment
- remaining_pixels -= segment->getWidth(seg_offset, character_count);
- ++seg_iter;
- seg_offset = 0;
- }
- }
- }
-
- // change mDocumentPanel document size to accomodate reflowed text
- LLRect document_rect;
- document_rect.setOriginAndSize(1, 1,
- mScroller->getContentWindowRect().getWidth(),
- llmax(mScroller->getContentWindowRect().getHeight(), -cur_top));
- mDocumentPanel->setShape(document_rect);
-
- // after making document big enough to hold all the text, move the text to fit in the document
- if (!mLineInfoList.empty())
- {
- S32 delta_pos = mDocumentPanel->getRect().getHeight() - mLineInfoList.begin()->mTop - texteditor_vpad_top;
- // move line segments to fit new document rect
- for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)
- {
- it->mTop += delta_pos;
- it->mBottom += delta_pos;
- }
- }
-
- // calculate visible region for diplaying text
- updateTextRect();
-
- for (segment_set_t::iterator segment_it = mSegments.begin();
- segment_it != mSegments.end();
- ++segment_it)
- {
- LLTextSegmentPtr segmentp = *segment_it;
- segmentp->updateLayout(*this);
-
- }
-
- // apply scroll constraints after reflowing text
- if (!hasMouseCapture())
- {
- LLRect visible_content_rect = mScroller->getVisibleContentRect();
- if (scrolled_to_bottom && mTrackBottom)
- {
- // keep bottom of text buffer visible
- endOfDoc();
- }
- else if (hasSelection() && follow_selection)
- {
- // keep cursor in same vertical position on screen when selecting text
- LLRect new_cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos);
- new_cursor_rect_doc.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
- mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect);
- //llassert_always(getLocalRectFromDocIndex(mCursorPos).mBottom == old_cursor_rect.mBottom);
- }
- else
- {
- // keep first line of text visible
- LLRect new_first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
- new_first_char_rect.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
- mScroller->scrollToShowRect(new_first_char_rect, first_char_rect);
- //llassert_always(getLocalRectFromDocIndex(mScrollIndex).mBottom == first_char_rect.mBottom);
- }
- }
- }
-
- // reset desired x cursor position
- updateCursorXPos();
-}
-
////////////////////////////////////////////////////////////
// LLTextEditor
// Public methods
-BOOL LLTextEditor::truncate()
-{
- BOOL did_truncate = FALSE;
-
- // First rough check - if we're less than 1/4th the size, we're OK
- if (getLength() >= S32(mMaxTextByteLength / 4))
- {
- // Have to check actual byte size
- LLWString text(getWText());
- S32 utf8_byte_size = wstring_utf8_length(text);
- if ( utf8_byte_size > mMaxTextByteLength )
- {
- // Truncate safely in UTF-8
- std::string temp_utf8_text = wstring_to_utf8str(text);
- temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
- getViewModel()->setDisplay(utf8str_to_wstring( temp_utf8_text ));
- did_truncate = TRUE;
- }
- }
-
- return did_truncate;
-}
-
void LLTextEditor::setText(const LLStringExplicit &utf8str)
{
- // clear out the existing text and segments
- clearSegments();
-
- getViewModel()->setValue("");
-
- truncate();
- blockUndo();
-
- createDefaultSegment();
-
- startOfDoc();
- deselect();
-
- // append the new text (supports Url linking)
- std::string text(utf8str);
- LLStringUtil::removeCRLF(text);
- appendStyledText(text, false, false, LLStyle::Params());
-
- needsReflow();
-
- resetDirty();
-
- onValueChange(0, getLength());
-}
-
-void LLTextEditor::setWText(const LLWString &wtext)
-{
- // clear out the existing text and segments
- clearSegments();
-
- getViewModel()->setDisplay(LLWString());
-
- truncate();
blockUndo();
-
- createDefaultSegment();
-
- startOfDoc();
deselect();
- // append the new text (supports Url linking)
- appendStyledText(wstring_to_utf8str(wtext), false, false, LLStyle::Params());
-
- needsReflow();
+ LLTextBase::setText(utf8str);
resetDirty();
-
- onValueChange(0, getLength());
-}
-
-// virtual
-void LLTextEditor::setValue(const LLSD& value)
-{
- setText(value.asString());
-}
-
-std::string LLTextEditor::getText() const
-{
- if (mAllowEmbeddedItems)
- {
- llwarns << "getText() called on text with embedded items (not supported)" << llendl;
- }
- return getViewModel()->getValue().asString();
}
void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap)
@@ -828,12 +412,6 @@ void LLTextEditor::replaceTextAll(const std::string& search_text, const std::str
}
}
-// Picks a new cursor position based on the screen size of text being drawn.
-void LLTextEditor::setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset )
-{
- setCursorPos(getDocIndexFromLocalCoord(local_x, local_y, round), keep_cursor_offset);
-}
-
S32 LLTextEditor::prevWordPos(S32 cursorPos) const
{
LLWString wtext(getWText());
@@ -862,60 +440,6 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
return cursorPos;
}
-S32 LLTextEditor::getLineStart( S32 line ) const
-{
- S32 num_lines = getLineCount();
- if (num_lines == 0)
- {
- return 0;
- }
-
- line = llclamp(line, 0, num_lines-1);
- return mLineInfoList[line].mDocIndexStart;
-}
-
-S32 LLTextEditor::getLineHeight( S32 line ) const
-{
- S32 num_lines = getLineCount();
- if (num_lines == 0)
- {
- return 0;
- }
-
- line = llclamp(line, 0, num_lines-1);
- return mLineInfoList[line].mTop - mLineInfoList[line].mBottom;
-}
-
-// Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line.
-void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp, bool include_wordwrap) const
-{
- if (mLineInfoList.empty())
- {
- *linep = 0;
- *offsetp = startpos;
- }
- else
- {
- line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), startpos, line_end_compare());
- if (include_wordwrap)
- {
- *linep = iter - mLineInfoList.begin();
- }
- else
- {
- if (iter == mLineInfoList.end())
- {
- *linep = mLineInfoList.back().mLineNum;
- }
- else
- {
- *linep = iter->mLineNum;
- }
- }
- *offsetp = startpos - iter->mDocIndexStart;
- }
-}
-
const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const
{
// find segment index at character to left of cursor (or rightmost edge of selection)
@@ -957,201 +481,6 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,
}
}
-// If round is true, if the position is on the right half of a character, the cursor
-// will be put to its right. If round is false, the cursor will always be put to the
-// character's left.
-
-S32 LLTextEditor::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
-{
- // Figure out which line we're nearest to.
- LLRect visible_region = mScroller->getVisibleContentRect();
-
- // binary search for line that starts before local_y
- line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mTextRect.mBottom + visible_region.mBottom, compare_bottom());
-
- if (line_iter == mLineInfoList.end())
- {
- return getLength(); // past the end
- }
-
- S32 pos = getLength();
- S32 start_x = mTextRect.mLeft;
-
- segment_set_t::iterator line_seg_iter;
- S32 line_seg_offset;
- for(getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
- line_seg_iter != mSegments.end();
- ++line_seg_iter, line_seg_offset = 0)
- {
- const LLTextSegmentPtr segmentp = *line_seg_iter;
-
- S32 segment_line_start = segmentp->getStart() + line_seg_offset;
- S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start;
- S32 text_width = segmentp->getWidth(line_seg_offset, segment_line_length);
- if (local_x < start_x + text_width // cursor to left of right edge of text
- || segmentp->getEnd() >= line_iter->mDocIndexEnd - 1) // or this segment wraps to next line
- {
- // Figure out which character we're nearest to.
- S32 offset;
- if (!segmentp->canEdit())
- {
- S32 segment_width = segmentp->getWidth(0, segmentp->getEnd() - segmentp->getStart());
- if (round && local_x - start_x > segment_width / 2)
- {
- offset = segment_line_length;
- }
- else
- {
- offset = 0;
- }
- }
- else
- {
- offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
- }
- pos = segment_line_start + offset;
- break;
- }
- start_x += text_width;
- }
-
- return pos;
-}
-
-LLRect LLTextEditor::getLocalRectFromDocIndex(S32 pos) const
-{
- LLRect local_rect(mTextRect);
- local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
- if (mLineInfoList.empty())
- {
- return local_rect;
- }
-
- // clamp pos to valid values
- pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1);
-
-
- // find line that contains cursor
- line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare());
-
- LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
- local_rect.mLeft = mTextRect.mLeft - scrolled_view_rect.mLeft;
- local_rect.mBottom = mTextRect.mBottom + (line_iter->mBottom - scrolled_view_rect.mBottom);
- local_rect.mTop = mTextRect.mBottom + (line_iter->mTop - scrolled_view_rect.mBottom);
-
- segment_set_t::iterator line_seg_iter;
- S32 line_seg_offset;
- segment_set_t::iterator cursor_seg_iter;
- S32 cursor_seg_offset;
- getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
- getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset);
-
- while(line_seg_iter != mSegments.end())
- {
- const LLTextSegmentPtr segmentp = *line_seg_iter;
-
- if (line_seg_iter == cursor_seg_iter)
- {
- // cursor advanced to right based on difference in offset of cursor to start of line
- local_rect.mLeft += segmentp->getWidth(line_seg_offset, cursor_seg_offset - line_seg_offset);
-
- break;
- }
- else
- {
- // add remainder of current text segment to cursor position
- local_rect.mLeft += segmentp->getWidth(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset);
- // offset will be 0 for all segments after the first
- line_seg_offset = 0;
- // go to next text segment on this line
- ++line_seg_iter;
- }
- }
-
- local_rect.mRight = local_rect.mLeft;
-
- return local_rect;
-}
-
-void LLTextEditor::addDocumentChild(LLView* view)
-{
- mDocumentPanel->addChild(view);
-}
-
-void LLTextEditor::removeDocumentChild(LLView* view)
-{
- mDocumentPanel->removeChild(view);
-}
-
-bool LLTextEditor::setCursor(S32 row, S32 column)
-{
- if (0 <= row && row < (S32)mLineInfoList.size())
- {
- S32 doc_pos = mLineInfoList[row].mDocIndexStart;
- column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
- doc_pos += column;
- updateCursorXPos();
-
- return setCursorPos(doc_pos);
- }
- return false;
-}
-
-bool LLTextEditor::setCursorPos(S32 cursor_pos, bool keep_cursor_offset)
-{
- S32 new_cursor_pos = cursor_pos;
- if (new_cursor_pos != mCursorPos)
- {
- new_cursor_pos = getEditableIndex(new_cursor_pos, new_cursor_pos >= mCursorPos);
- }
-
- mCursorPos = llclamp(new_cursor_pos, 0, (S32)getLength());
- needsScroll();
- if (!keep_cursor_offset)
- updateCursorXPos();
- // did we get requested position?
- return new_cursor_pos == cursor_pos;
-}
-
-void LLTextEditor::updateCursorXPos()
-{
- // reset desired x cursor position
- mDesiredXPixel = getLocalRectFromDocIndex(mCursorPos).mLeft;
-}
-
-// constraint cursor to editable segments of document
-// NOTE: index must be within document range
-S32 LLTextEditor::getEditableIndex(S32 index, bool increasing_direction)
-{
- segment_set_t::iterator segment_iter;
- S32 offset;
- getSegmentAndOffset(index, &segment_iter, &offset);
-
- LLTextSegmentPtr segmentp = *segment_iter;
-
- if (segmentp->canEdit())
- {
- return segmentp->getStart() + offset;
- }
- else if (segmentp->getStart() < index && index < segmentp->getEnd())
- {
- // bias towards document end
- if (increasing_direction)
- {
- return segmentp->getEnd();
- }
- // bias towards document start
- else
- {
- return segmentp->getStart();
- }
- }
- else
- {
- return index;
- }
-}
-
// virtual
BOOL LLTextEditor::canDeselect() const
{
@@ -1167,25 +496,6 @@ void LLTextEditor::deselect()
}
-void LLTextEditor::startSelection()
-{
- if( !mIsSelecting )
- {
- mIsSelecting = TRUE;
- mSelectionStart = mCursorPos;
- mSelectionEnd = mCursorPos;
- }
-}
-
-void LLTextEditor::endSelection()
-{
- if( mIsSelecting )
- {
- mIsSelecting = FALSE;
- mSelectionEnd = mCursorPos;
- }
-}
-
BOOL LLTextEditor::selectionContainsLineBreaks()
{
if (hasSelection())
@@ -1334,23 +644,12 @@ void LLTextEditor::selectAll()
setCursorPos(mSelectionEnd);
}
-
-BOOL LLTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
-{
- if (childrenHandleToolTip(x, y, msg, sticky_rect_screen))
- {
- return TRUE;
- }
-
- return handleToolTipForUrl(this, x, y, msg, sticky_rect_screen);
-}
-
BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
// Let scrollbar have first dibs
- handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+ handled = LLTextBase::handleMouseDown(x, y, mask);
if( !handled )
{
@@ -1398,7 +697,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
}
// Delay cursor flashing
- resetKeystrokeTimer();
+ resetCursorBlink();
return handled;
}
@@ -1407,7 +706,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- handled = childrenHandleMiddleMouseDown(x, y, mask) != NULL;
+ handled = LLTextBase::handleMouseDown(x, y, mask);
if (!handled)
{
@@ -1424,19 +723,12 @@ BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
{
- static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
BOOL handled = FALSE;
if(hasMouseCapture() )
{
if( mIsSelecting )
{
- if (x != mLastSelectionX || y != mLastSelectionY)
- {
- mLastSelectionX = x;
- mLastSelectionY = y;
- }
-
mScroller->autoScroll(x, y);
S32 clamped_x = llclamp(x, mTextRect.mLeft, mTextRect.mRight);
@@ -1453,32 +745,19 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
if( !handled )
{
// Pass to children
- handled = LLView::childrenHandleHover(x, y, mask) != NULL;
+ handled = LLTextBase::handleHover(x, y, mask);
}
if( handled )
{
// Delay cursor flashing
- resetKeystrokeTimer();
+ resetCursorBlink();
}
- // Opaque
if( !handled )
{
- // Check to see if we're over an HTML-style link
- handled = handleHoverOverUrl(x, y);
- if( handled )
- {
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- getWindow()->setCursor(UI_CURSOR_HAND);
- }
-
- if( !handled )
- {
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;
- getWindow()->setCursor(UI_CURSOR_IBEAM);
- handled = TRUE;
- }
+ getWindow()->setCursor(UI_CURSOR_IBEAM);
+ handled = TRUE;
}
return handled;
@@ -1489,8 +768,12 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- // let scrollbar have first dibs
- handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
+ // if I'm not currently selecting text
+ if (!(hasSelection() && hasMouseCapture()))
+ {
+ // let text segments handle mouse event
+ handled = LLTextBase::handleMouseUp(x, y, mask);
+ }
if( !handled )
{
@@ -1503,11 +786,6 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
endSelection();
}
- if( !hasSelection() && hasMouseCapture() )
- {
- handleMouseUpOverUrl(x, y);
- }
-
// take selection to 'primary' clipboard
updatePrimary();
@@ -1515,7 +793,7 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
}
// Delay cursor flashing
- resetKeystrokeTimer();
+ resetCursorBlink();
if( hasMouseCapture() )
{
@@ -1532,8 +810,8 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- // let scrollbar have first dibs
- handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL;
+ // let scrollbar and text segments have first dibs
+ handled = LLTextBase::handleDoubleClick(x, y, mask);
if( !handled )
{
@@ -1571,7 +849,7 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
mIsSelecting = FALSE;
// delay cursor flashing
- resetKeystrokeTimer();
+ resetCursorBlink();
// take selection to 'primary' clipboard
updatePrimary();
@@ -1583,35 +861,18 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
}
-// Allow calling cards to be dropped onto text fields. Append the name and
-// a carriage return.
-// virtual
-BOOL LLTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
- BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
- EAcceptance *accept,
- std::string& tooltip_msg)
-{
- *accept = ACCEPT_NO;
-
- return TRUE;
-}
-
//----------------------------------------------------------------------------
// Returns change in number of characters in mText
-S32 LLTextEditor::execute( LLTextCmd* cmd )
+S32 LLTextEditor::execute( TextCmd* cmd )
{
S32 delta = 0;
if( cmd->execute(this, &delta) )
{
// Delete top of undo stack
undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd);
- if (enditer != mUndoStack.begin())
- {
- --enditer;
- std::for_each(mUndoStack.begin(), enditer, DeletePointer());
- mUndoStack.erase(mUndoStack.begin(), enditer);
- }
+ std::for_each(mUndoStack.begin(), enditer, DeletePointer());
+ mUndoStack.erase(mUndoStack.begin(), enditer);
// Push the new command is now on the top (front) of the undo stack.
mUndoStack.push_front(cmd);
mLastCmd = cmd;
@@ -1627,7 +888,7 @@ S32 LLTextEditor::execute( LLTextCmd* cmd )
S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment)
{
- return execute( new LLTextCmdInsert( pos, group_with_next_op, wstr, segment ) );
+ return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) );
}
S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
@@ -1638,12 +899,7 @@ S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
// store text segments
getSegmentsInRange(segments_to_remove, pos, pos + length, false);
- return execute( new LLTextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
-}
-
-S32 LLTextEditor::append(const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment)
-{
- return insert(getLength(), wstr, group_with_next_op, segment);
+ return execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
}
S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
@@ -1654,7 +910,7 @@ S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
}
else
{
- return execute(new LLTextCmdOverwriteChar(pos, FALSE, wc));
+ return execute(new TextCmdOverwriteChar(pos, FALSE, wc));
}
}
@@ -1674,8 +930,7 @@ void LLTextEditor::removeCharOrTab()
if (text[mCursorPos - 1] == ' ')
{
// Try to remove a "tab"
- S32 line, offset;
- getLineAndOffset(mCursorPos, &line, &offset);
+ S32 offset = getLineOffsetFromDocIndex(mCursorPos);
if (offset > 0)
{
chars_to_remove = offset % SPACES_PER_TAB;
@@ -1749,7 +1004,7 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc)
}
else
{
- return execute(new LLTextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
+ return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
}
}
@@ -2349,8 +1604,7 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return
deleteSelection(FALSE);
}
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
+ S32 offset = getLineOffsetFromDocIndex(mCursorPos);
S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB);
for( S32 i=0; i < spaces_needed; i++ )
@@ -2481,7 +1735,7 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
if( handled )
{
- resetKeystrokeTimer();
+ resetCursorBlink();
// Most keystrokes will make the selection box go away, but not all will.
if( !selection_modified &&
@@ -2534,7 +1788,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
if( handled )
{
- resetKeystrokeTimer();
+ resetCursorBlink();
// Most keystrokes will make the selection box go away, but not all will.
deselect();
@@ -2573,8 +1827,7 @@ void LLTextEditor::doDelete()
if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) )
{
// Try to remove a full tab's worth of spaces
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
+ S32 offset = getLineOffsetFromDocIndex(mCursorPos);
chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB);
if( chars_to_remove == 0 )
{
@@ -2694,7 +1947,7 @@ void LLTextEditor::redo()
void LLTextEditor::onFocusReceived()
{
- LLUICtrl::onFocusReceived();
+ LLTextBase::onFocusReceived();
updateAllowingLanguageInput();
}
@@ -2717,19 +1970,19 @@ void LLTextEditor::onFocusLost()
// Make sure cursor is shown again
getWindow()->showCursorFromMouseMove();
- LLUICtrl::onFocusLost();
+ LLTextBase::onFocusLost();
}
void LLTextEditor::onCommit()
{
setControlValue(getValue());
- LLUICtrl::onCommit();
+ LLTextBase::onCommit();
}
void LLTextEditor::setEnabled(BOOL enabled)
{
// just treat enabled as read-only flag
- BOOL read_only = !enabled;
+ bool read_only = !enabled;
if (read_only != mReadOnly)
{
mReadOnly = read_only;
@@ -2738,195 +1991,6 @@ void LLTextEditor::setEnabled(BOOL enabled)
}
}
-void LLTextEditor::drawBackground()
-{
- S32 left = 0;
- S32 top = getRect().getHeight();
- S32 bottom = 0;
-
- LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor.get()
- : hasFocus() ? mFocusBgColor.get() : mWriteableBgColor.get();
- if( mShowLineNumbers ) {
- gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor.get() ); // line number area always read-only
- gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
- }
-}
-
-// Draws the black box behind the selected text
-void LLTextEditor::drawSelectionBackground()
-{
- // Draw selection even if we don't have keyboard focus for search/replace
- if( hasSelection() && !mLineInfoList.empty())
- {
- LLWString text = getWText();
- std::vector<LLRect> selection_rects;
-
- S32 selection_left = llmin( mSelectionStart, mSelectionEnd );
- S32 selection_right = llmax( mSelectionStart, mSelectionEnd );
- LLRect selection_rect = mTextRect;
-
- // Skip through the lines we aren't drawing.
- LLRect content_display_rect = mScroller->getVisibleContentRect();
-
- // binary search for line that starts before top of visible buffer
- line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
- line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
-
- bool done = false;
-
- // Find the coordinates of the selected area
- for (;line_iter != end_iter && !done; ++line_iter)
- {
- // is selection visible on this line?
- if (line_iter->mDocIndexEnd > selection_left && line_iter->mDocIndexStart < selection_right)
- {
- segment_set_t::iterator segment_iter;
- S32 segment_offset;
- getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
-
- LLRect selection_rect;
- selection_rect.mLeft = 0;
- selection_rect.mRight = 0;
- selection_rect.mBottom = line_iter->mBottom;
- selection_rect.mTop = line_iter->mTop;
-
- for(;segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
- {
- LLTextSegmentPtr segmentp = *segment_iter;
-
- S32 segment_line_start = segmentp->getStart() + segment_offset;
- S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
-
- // if selection after beginning of segment
- if(selection_left >= segment_line_start)
- {
- S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
- selection_rect.mLeft += segmentp->getWidth(segment_offset, num_chars);
- }
-
- // if selection spans end of current segment...
- if (selection_right > segment_line_end)
- {
- // extend selection slightly beyond end of line
- // to indicate selection of newline character (use "n" character to determine width)
- selection_rect.mRight += segmentp->getWidth(segment_offset, segment_line_end - segment_line_start);
- }
- // else if selection ends on current segment...
- else
- {
- S32 num_chars = selection_right - segment_line_start;
- selection_rect.mRight += segmentp->getWidth(segment_offset, num_chars);
-
- break;
- }
- }
- selection_rects.push_back(selection_rect);
- }
- }
-
- // Draw the selection box (we're using a box instead of reversing the colors on the selected text).
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- const LLColor4& color = mReadOnly ? mReadOnlyBgColor.get() : mWriteableBgColor.get();
- F32 alpha = hasFocus() ? 0.7f : 0.3f;
- gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
-
- for (std::vector<LLRect>::iterator rect_it = selection_rects.begin();
- rect_it != selection_rects.end();
- ++rect_it)
- {
- LLRect selection_rect = *rect_it;
- selection_rect.translate(mTextRect.mLeft - content_display_rect.mLeft, mTextRect.mBottom - content_display_rect.mBottom);
- gl_rect_2d(selection_rect);
- }
- }
-}
-
-void LLTextEditor::drawCursor()
-{
- if( hasFocus()
- && gFocusMgr.getAppHasFocus()
- && !mReadOnly)
- {
- LLWString wtext = getWText();
- const llwchar* text = wtext.c_str();
-
- LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
- cursor_rect.translate(-1, 0);
- segment_set_t::iterator seg_it = getSegIterContaining(mCursorPos);
-
- // take style from last segment
- LLTextSegmentPtr segmentp;
-
- if (seg_it != mSegments.end())
- {
- segmentp = *seg_it;
- }
- else
- {
- //segmentp = mSegments.back();
- return;
- }
-
- // Draw the cursor
- // (Flash the cursor every half second starting a fixed time after the last keystroke)
- F32 elapsed = mKeystrokeTimer.getElapsedTimeF32();
- if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) )
- {
-
- if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
- {
- S32 width = llmax(CURSOR_THICKNESS, segmentp->getWidth(mCursorPos - segmentp->getStart(), 1));
- cursor_rect.mRight = cursor_rect.mLeft + width;
- }
- else
- {
- cursor_rect.mRight = cursor_rect.mLeft + CURSOR_THICKNESS;
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- gGL.color4fv( mCursorColor.get().mV );
-
- gl_rect_2d(cursor_rect);
-
- if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n')
- {
- LLColor4 text_color;
- const LLFontGL* fontp;
- if (segmentp)
- {
- text_color = segmentp->getColor();
- fontp = segmentp->getStyle()->getFont();
- }
- else if (mReadOnly)
- {
- text_color = mReadOnlyFgColor.get();
- fontp = mDefaultFont;
- }
- else
- {
- text_color = mFgColor.get();
- fontp = mDefaultFont;
- }
- fontp->render(text, mCursorPos, cursor_rect.mLeft, cursor_rect.mBottom,
- LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f),
- LLFontGL::LEFT, LLFontGL::BOTTOM,
- LLFontGL::NORMAL,
- LLFontGL::NO_SHADOW,
- 1);
- }
-
- // Make sure the IME is in the right place
- LLRect screen_pos = calcScreenRect();
- LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) );
-
- ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
- ime_pos.mY = (S32) (ime_pos.mY * LLUI::sGLScaleFactor.mV[VY]);
- getWindow()->setLanguageTextInput( ime_pos );
- }
- }
-}
-
void LLTextEditor::drawPreeditMarker()
{
static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
@@ -3032,96 +2096,6 @@ void LLTextEditor::drawPreeditMarker()
}
-void LLTextEditor::drawText()
-{
- LLWString text = getWText();
- const S32 text_len = getLength();
- if( text_len <= 0 )
- {
- return;
- }
- S32 selection_left = -1;
- S32 selection_right = -1;
- // Draw selection even if we don't have keyboard focus for search/replace
- if( hasSelection())
- {
- selection_left = llmin( mSelectionStart, mSelectionEnd );
- selection_right = llmax( mSelectionStart, mSelectionEnd );
- }
-
- LLGLSUIDefault gls_ui;
- LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
- LLRect content_rect = mScroller->getContentWindowRect();
- S32 first_line = getFirstVisibleLine();
- S32 num_lines = getLineCount();
- if (first_line >= num_lines)
- {
- return;
- }
-
- S32 line_start = getLineStart(first_line);
- // find first text segment that spans top of visible portion of text buffer
- segment_set_t::iterator seg_iter = getSegIterContaining(line_start);
- if (seg_iter == mSegments.end())
- {
- return;
- }
-
- LLTextSegmentPtr cur_segment = *seg_iter;
-
- for (S32 cur_line = first_line; cur_line < num_lines; cur_line++)
- {
- line_info& line = mLineInfoList[cur_line];
-
- if ((line.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom)
- {
- break;
- }
-
- S32 next_start = -1;
- S32 line_end = text_len;
-
- if ((cur_line + 1) < num_lines)
- {
- next_start = getLineStart(cur_line + 1);
- line_end = next_start;
- }
- if ( text[line_end-1] == '\n' )
- {
- --line_end;
- }
-
- LLRect text_rect(mTextRect.mLeft - scrolled_view_rect.mLeft,
- line.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom,
- mTextRect.getWidth() - scrolled_view_rect.mLeft,
- line.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom);
-
- // draw a single line of text
- S32 seg_start = line_start;
- while( seg_start < line_end )
- {
- while( cur_segment->getEnd() <= seg_start )
- {
- seg_iter++;
- if (seg_iter == mSegments.end())
- {
- llwarns << "Ran off the segmentation end!" << llendl;
-
- return;
- }
- cur_segment = *seg_iter;
- }
-
- S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart();
- text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect));
-
- seg_start = clipped_end + cur_segment->getStart();
- }
-
- line_start = next_start;
- }
-}
-
void LLTextEditor::drawLineNumbers()
{
LLGLSUIDefault gls_ui;
@@ -3136,24 +2110,31 @@ void LLTextEditor::drawLineNumbers()
return;
}
- S32 cursor_line = getCurrentLine();
+ S32 cursor_line = getLineNumFromDocIndex(mCursorPos);
if (mShowLineNumbers)
{
+ S32 left = 0;
+ S32 top = getRect().getHeight();
+ S32 bottom = 0;
+
+ gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor.get() ); // line number area always read-only
+ gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
+
S32 last_line_num = -1;
for (S32 cur_line = first_line; cur_line < num_lines; cur_line++)
{
line_info& line = mLineInfoList[cur_line];
- if ((line.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom)
+ if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom)
{
break;
}
- S32 line_bottom = line.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom;
+ S32 line_bottom = line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom;
// draw the line numbers
- if(line.mLineNum != last_line_num && line.mTop <= scrolled_view_rect.mTop)
+ if(line.mLineNum != last_line_num && line.mRect.mTop <= scrolled_view_rect.mTop)
{
const LLFontGL *num_font = LLFontGL::getFontMonospace();
const LLWString ltext = utf8str_to_wstring(llformat("%d", line.mLineNum ));
@@ -3180,58 +2161,23 @@ void LLTextEditor::drawLineNumbers()
void LLTextEditor::draw()
{
- // reflow if needed, on demand
- reflow();
-
- // then update scroll position, as cursor may have moved
- updateScrollFromCursor();
-
- LLColor4 bg_color = mReadOnly
- ? mReadOnlyBgColor.get()
- : hasFocus()
- ? mFocusBgColor.get()
- : mWriteableBgColor.get();
-
- mDocumentPanel->setBackgroundColor(bg_color);
-
- LLView::draw();
- drawBackground(); //overlays scrolling panel bg
- drawLineNumbers();
-
{
// pad clipping rectangle so that cursor can draw at full width
// when at left edge of mTextRect
LLRect clip_rect(mTextRect);
clip_rect.stretch(1);
LLLocalClipRect clip(clip_rect);
- drawSelectionBackground();
drawPreeditMarker();
- drawText();
- drawCursor();
}
+ LLTextBase::draw();
+ drawLineNumbers();
+
//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
// when in readonly mode
mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly);
}
-
-S32 LLTextEditor::getFirstVisibleLine() const
-{
- LLRect visible_region = mScroller->getVisibleContentRect();
-
- // binary search for line that starts before top of visible buffer
- line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
-
- return iter - mLineInfoList.begin();
-}
-
-// virtual
-void LLTextEditor::clear()
-{
- setText(LLStringUtil::null);
-}
-
// Start or stop the editor from accepting text-editing keystrokes
// see also LLLineEditor
void LLTextEditor::setFocus( BOOL new_state )
@@ -3247,7 +2193,7 @@ void LLTextEditor::setFocus( BOOL new_state )
getWindow()->allowLanguageTextInput(this, FALSE);
}
- LLUICtrl::setFocus( new_state );
+ LLTextBase::setFocus( new_state );
if( new_state )
{
@@ -3255,7 +2201,7 @@ void LLTextEditor::setFocus( BOOL new_state )
gEditMenuHandler = this;
// Don't start the cursor flashing right away
- resetKeystrokeTimer();
+ resetCursorBlink();
}
else
{
@@ -3269,96 +2215,6 @@ void LLTextEditor::setFocus( BOOL new_state )
}
}
-// virtual
-BOOL LLTextEditor::acceptsTextInput() const
-{
- return !mReadOnly;
-}
-
-// Given a line (from the start of the doc) and an offset into the line, find the offset (pos) into text.
-S32 LLTextEditor::getPos( S32 line, S32 offset )
-{
- S32 line_start = getLineStart(line);
- S32 next_start = getLineStart(line+1);
- if (next_start == line_start)
- {
- next_start = getLength() + 1;
- }
- S32 line_length = next_start - line_start - 1;
- line_length = llmax(line_length, 0);
- return line_start + llmin( offset, line_length );
-}
-
-
-void LLTextEditor::changePage( S32 delta )
-{
- const S32 PIXEL_OVERLAP_ON_PAGE_CHANGE = 10;
- if (delta == 0) return;
-
- //RN: use pixel heights
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
-
- LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
-
- if( delta == -1 )
- {
- mScroller->pageUp(PIXEL_OVERLAP_ON_PAGE_CHANGE);
- }
- else
- if( delta == 1 )
- {
- mScroller->pageDown(PIXEL_OVERLAP_ON_PAGE_CHANGE);
- }
-
- if (getLocalRectFromDocIndex(mCursorPos) == cursor_rect)
- {
- // cursor didn't change apparent position, so move to top or bottom of document, respectively
- if (delta < 0)
- {
- startOfDoc();
- }
- else
- {
- endOfDoc();
- }
- }
- else
- {
- setCursorAtLocalPos(cursor_rect.getCenterX(), cursor_rect.getCenterY(), true, false);
- }
-}
-
-void LLTextEditor::changeLine( S32 delta )
-{
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
-
- S32 new_line = line;
- if( (delta < 0) && (line > 0 ) )
- {
- new_line = line - 1;
- }
- else if( (delta > 0) && (line < (getLineCount() - 1)) )
- {
- new_line = line + 1;
- }
-
- LLRect visible_region = mScroller->getVisibleContentRect();
-
- S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mBottom + mTextRect.mBottom - visible_region.mBottom, TRUE);
- setCursorPos(new_cursor_pos, true);
-}
-
-
-void LLTextEditor::startOfLine()
-{
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
- setCursorPos(mCursorPos - offset);
-}
-
-
// public
void LLTextEditor::setCursorAndScrollToEnd()
{
@@ -3366,92 +2222,16 @@ void LLTextEditor::setCursorAndScrollToEnd()
endOfDoc();
}
-void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap )
-{
- getLineAndOffset( mCursorPos, line, col, include_wordwrap );
-}
-
void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap )
{
- getLineAndColumnForPosition(mCursorPos, line, col, include_wordwrap);
-}
-
-S32 LLTextEditor::getCurrentLine()
-{
- return getLineForPosition(mCursorPos);
-}
-
-S32 LLTextEditor::getLineForPosition(S32 position)
-{
- S32 line, col;
- getLineAndColumnForPosition(position, &line, &col, FALSE);
- return line;
-}
-
-
-void LLTextEditor::endOfLine()
-{
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
- S32 num_lines = getLineCount();
- if (line + 1 >= num_lines)
- {
- setCursorPos(getLength());
- }
- else
- {
- setCursorPos( getLineStart(line + 1) - 1 );
- }
-}
-
-void LLTextEditor::startOfDoc()
-{
- setCursorPos(0);
-}
-
-void LLTextEditor::endOfDoc()
-{
- setCursorPos(getLength());
-}
-
-// Sets the scrollbar from the cursor position
-void LLTextEditor::updateScrollFromCursor()
-{
- // Update scroll position even in read-only mode (when there's no cursor displayed)
- // because startOfDoc()/endOfDoc() modify cursor position. See EXT-736.
-
- if (!mScrollNeeded)
- {
- return;
- }
- mScrollNeeded = FALSE;
-
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
-
- // scroll so that the cursor is at the top of the page
- LLRect scroller_doc_window = mScroller->getVisibleContentRect();
- LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos);
- cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom);
- mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5));
-}
-
-void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- LLView::reshape( width, height, called_from_parent );
-
- // do this first after reshape, because other things depend on
- // up-to-date mTextRect
- updateTextRect();
-
- needsReflow();
+ *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap);
+ *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap);
}
void LLTextEditor::autoIndent()
{
// Count the number of spaces in the current line
- S32 line, offset;
- getLineAndOffset( mCursorPos, &line, &offset );
+ S32 line = getLineNumFromDocIndex(mCursorPos);
S32 line_start = getLineStart(line);
S32 space_count = 0;
S32 i;
@@ -3496,221 +2276,6 @@ void LLTextEditor::insertText(const std::string &new_text)
setEnabled( enabled );
}
-
-void LLTextEditor::appendColoredText(const std::string &new_text,
- bool allow_undo,
- bool prepend_newline,
- const LLColor4 &color,
- const std::string& font_name)
-{
- LLColor4 lcolor=color;
- if (mParseHighlights)
- {
- LLTextParser* highlight = LLTextParser::getInstance();
- highlight->parseFullLineHighlights(new_text, &lcolor);
- }
-
- LLStyle::Params style_params;
- style_params.color = lcolor;
- if (font_name.empty())
- {
- style_params.font = mDefaultFont;
- }
- else
- {
- style_params.font.name = font_name;
- }
- appendStyledText(new_text, allow_undo, prepend_newline, style_params);
-}
-
-void LLTextEditor::appendStyledText(const std::string &new_text,
- bool allow_undo,
- bool prepend_newline,
- const LLStyle::Params& style_params)
-{
- S32 part = (S32)LLTextParser::WHOLE;
- if(mParseHTML)
- {
-
- S32 start=0,end=0;
- LLUrlMatch match;
- std::string text = new_text;
- while ( LLUrlRegistry::instance().findUrl(text, match,
- boost::bind(&LLTextEditor::onUrlLabelUpdated, this, _1, _2)) )
- {
- start = match.getStart();
- end = match.getEnd()+1;
-
- LLStyle::Params link_params = style_params;
- link_params.color = mLinkColor;
- link_params.font.style = "UNDERLINE";
- link_params.link_href = match.getUrl();
-
- // output the text before the Url
- if (start > 0)
- {
- if (part == (S32)LLTextParser::WHOLE ||
- part == (S32)LLTextParser::START)
- {
- part = (S32)LLTextParser::START;
- }
- else
- {
- part = (S32)LLTextParser::MIDDLE;
- }
- std::string subtext=text.substr(0,start);
- appendHighlightedText(subtext,allow_undo, prepend_newline, part, style_params);
- prepend_newline = false;
- }
-
- // output the styled Url
- appendText(match.getLabel(),allow_undo, prepend_newline, link_params);
- prepend_newline = false;
-
- // set the tooltip for the Url label
- if (! match.getTooltip().empty())
- {
- segment_set_t::iterator it = getSegIterContaining(getLength()-1);
- if (it != mSegments.end())
- {
- LLTextSegmentPtr segment = *it;
- segment->setToolTip(match.getTooltip());
- }
- }
-
- // output an optional icon after the Url
- if (! match.getIcon().empty())
- {
- LLUIImagePtr image = LLUI::getUIImage(match.getIcon());
- if (image)
- {
- LLStyle::Params icon;
- icon.image = image;
- // TODO: fix spacing of images and remove the fixed char spacing
- appendText(" ", allow_undo, prepend_newline, icon);
- }
- }
-
- // move on to the rest of the text after the Url
- if (end < (S32)text.length())
- {
- text = text.substr(end,text.length() - end);
- end=0;
- part=(S32)LLTextParser::END;
- }
- else
- {
- break;
- }
- }
- if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
- if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, style_params);
- }
- else
- {
- appendHighlightedText(new_text, allow_undo, prepend_newline, part, style_params);
- }
-}
-
-void LLTextEditor::appendHighlightedText(const std::string &new_text,
- bool allow_undo,
- bool prepend_newline,
- S32 highlight_part,
- const LLStyle::Params& style_params)
-{
- if (mParseHighlights)
- {
- LLTextParser* highlight = LLTextParser::getInstance();
-
- if (highlight && !style_params.isDefault())
- {
- LLStyle::Params highlight_params = style_params;
-
- LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params.color(), highlight_part);
- bool lprepend=prepend_newline;
- for (S32 i=0;i<pieces.size();i++)
- {
- LLSD color_llsd = pieces[i]["color"];
- LLColor4 lcolor;
- lcolor.setValue(color_llsd);
- highlight_params.color = lcolor;
- if (i != 0 && (pieces.size() > 1) ) lprepend=FALSE;
- appendText((std::string)pieces[i]["text"], allow_undo, lprepend, highlight_params);
- }
- return;
- }
- }
- appendText(new_text, allow_undo, prepend_newline, style_params);
-}
-
-// Appends new text to end of document
-void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline,
- const LLStyle::Params& stylep)
-{
- if (new_text.empty()) return;
-
- // Save old state
- S32 selection_start = mSelectionStart;
- S32 selection_end = mSelectionEnd;
- BOOL was_selecting = mIsSelecting;
- S32 cursor_pos = mCursorPos;
- S32 old_length = getLength();
- BOOL cursor_was_at_end = (mCursorPos == old_length);
-
- deselect();
-
- setCursorPos(old_length);
-
- LLWString wide_text;
-
- // Add carriage return if not first line
- if (getLength() != 0
- && prepend_newline)
- {
- wide_text = utf8str_to_wstring(std::string("\n") + new_text);
- }
- else
- {
- wide_text = utf8str_to_wstring(new_text);
- }
-
- LLTextSegmentPtr segmentp;
- if (!stylep.isDefault())
- {
- S32 segment_start = old_length;
- S32 segment_end = old_length + wide_text.size();
- segmentp = new LLNormalTextSegment(new LLStyle(stylep), segment_start, segment_end, *this );
- }
-
- append(wide_text, TRUE, segmentp);
-
- needsReflow();
-
- // Set the cursor and scroll position
- if( selection_start != selection_end )
- {
- mSelectionStart = selection_start;
- mSelectionEnd = selection_end;
-
- mIsSelecting = was_selecting;
- setCursorPos(cursor_pos);
- }
- else if( cursor_was_at_end )
- {
- setCursorPos(getLength());
- }
- else
- {
- setCursorPos(cursor_pos);
- }
-
- if( !allow_undo )
- {
- blockUndo();
- }
-}
-
-
void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline)
{
// Save old state
@@ -3739,7 +2304,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
}
LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size());
- append(widget_wide_text, FALSE, segment);
+ insert(getLength(), widget_wide_text, FALSE, segment);
needsReflow();
@@ -3767,12 +2332,6 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
}
}
-void LLTextEditor::onUrlLabelUpdated(const std::string &url,
- const std::string &label)
-{
- // LLUrlRegistry has given us a new label for one of our Urls
- replaceUrlLabel(url, label);
-}
void LLTextEditor::replaceUrlLabel(const std::string &url,
const std::string &label)
@@ -3830,164 +2389,10 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars)
mSelectionStart = llclamp(mSelectionStart, 0, len);
mSelectionEnd = llclamp(mSelectionEnd, 0, len);
- reflow();
+ needsReflow();
needsScroll();
}
-///////////////////////////////////////////////////////////////////
-// Returns change in number of characters in mWText
-
-S32 LLTextEditor::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextEditor::segment_vec_t* segments )
-{
- LLWString text(getWText());
- S32 old_len = text.length(); // length() returns character length
- S32 insert_len = wstr.length();
-
- pos = getEditableIndex(pos, true);
-
- segment_set_t::iterator seg_iter = getSegIterContaining(pos);
-
- LLTextSegmentPtr default_segment;
-
- LLTextSegmentPtr segmentp;
- if (seg_iter != mSegments.end())
- {
- segmentp = *seg_iter;
- }
- else
- {
- //segmentp = mSegments.back();
- return pos;
- }
-
- if (segmentp->canEdit())
- {
- segmentp->setEnd(segmentp->getEnd() + insert_len);
- if (seg_iter != mSegments.end())
- {
- ++seg_iter;
- }
- }
- else
- {
- // create default editable segment to hold new text
- default_segment = new LLNormalTextSegment( getDefaultStyle(), pos, pos + insert_len, *this);
- }
-
- // shift remaining segments to right
- for(;seg_iter != mSegments.end(); ++seg_iter)
- {
- LLTextSegmentPtr segmentp = *seg_iter;
- segmentp->setStart(segmentp->getStart() + insert_len);
- segmentp->setEnd(segmentp->getEnd() + insert_len);
- }
-
- // insert new segments
- if (segments)
- {
- if (default_segment.notNull())
- {
- // potentially overwritten by segments passed in
- insertSegment(default_segment);
- }
- for (segment_vec_t::iterator seg_iter = segments->begin();
- seg_iter != segments->end();
- ++seg_iter)
- {
- LLTextSegment* segmentp = *seg_iter;
- insertSegment(segmentp);
- }
- }
-
- text.insert(pos, wstr);
- getViewModel()->setDisplay(text);
-
- if ( truncate() )
- {
- // The user's not getting everything he's hoping for
- make_ui_sound("UISndBadKeystroke");
- insert_len = getLength() - old_len;
- }
-
- onValueChange(pos, pos + insert_len);
-
- return insert_len;
-}
-
-S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length)
-{
- LLWString text(getWText());
- segment_set_t::iterator seg_iter = getSegIterContaining(pos);
- while(seg_iter != mSegments.end())
- {
- LLTextSegmentPtr segmentp = *seg_iter;
- S32 end = pos + length;
- if (segmentp->getStart() < pos)
- {
- // deleting from middle of segment
- if (segmentp->getEnd() > end)
- {
- segmentp->setEnd(segmentp->getEnd() - length);
- }
- // truncating segment
- else
- {
- segmentp->setEnd(pos);
- }
- }
- else if (segmentp->getStart() < end)
- {
- // deleting entire segment
- if (segmentp->getEnd() <= end)
- {
- // remove segment
- segmentp->unlinkFromDocument(this);
- segment_set_t::iterator seg_to_erase(seg_iter++);
- mSegments.erase(seg_to_erase);
- continue;
- }
- // deleting head of segment
- else
- {
- segmentp->setStart(pos);
- segmentp->setEnd(segmentp->getEnd() - length);
- }
- }
- else
- {
- // shifting segments backward to fill deleted portion
- segmentp->setStart(segmentp->getStart() - length);
- segmentp->setEnd(segmentp->getEnd() - length);
- }
- ++seg_iter;
- }
-
- text.erase(pos, length);
- getViewModel()->setDisplay(text);
-
- // recreate default segment in case we erased everything
- createDefaultSegment();
-
- onValueChange(pos, pos);
-
- return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length
-}
-
-S32 LLTextEditor::overwriteCharNoUndo(S32 pos, llwchar wc)
-{
- if (pos > (S32)getLength())
- {
- return 0;
- }
- LLWString text(getWText());
- text[pos] = wc;
- getViewModel()->setDisplay(text);
-
- onValueChange(pos, pos + 1);
-
- return 1;
-}
-
//----------------------------------------------------------------------------
void LLTextEditor::makePristine()
@@ -4051,29 +2456,13 @@ BOOL LLTextEditor::tryToRevertToPristineState()
}
-void LLTextEditor::updateTextRect()
-{
- static LLUICachedControl<S32> texteditor_border ("UITextEditorBorder", 0);
- static LLUICachedControl<S32> texteditor_h_pad ("UITextEditorHPad", 0);
-
- LLRect old_text_rect = mTextRect;
- mTextRect = mScroller->getContentWindowRect();
- mTextRect.stretch(texteditor_border * -1);
- mTextRect.mLeft += texteditor_h_pad;
- mTextRect.mLeft += mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
- if (mTextRect != old_text_rect)
- {
- needsReflow();
- }
-}
-
-LLFastTimer::DeclareTimer FTM_TEXT_EDITOR_LOAD_KEYWORD("Text Editor Load Keywords");
+static LLFastTimer::DeclareTimer FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting");
void LLTextEditor::loadKeywords(const std::string& filename,
const std::vector<std::string>& funcs,
const std::vector<std::string>& tooltips,
const LLColor3& color)
{
- LLFastTimer ft(FTM_TEXT_EDITOR_LOAD_KEYWORD);
+ LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
if(mKeywords.loadFromFile(filename))
{
S32 count = llmin(funcs.size(), tooltips.size());
@@ -4094,27 +2483,9 @@ void LLTextEditor::loadKeywords(const std::string& filename,
}
}
-void LLTextEditor::createDefaultSegment()
-{
- // ensures that there is always at least one segment
- if (mSegments.empty())
- {
- LLTextSegmentPtr default_segment = new LLNormalTextSegment( getDefaultStyle(), 0, getLength() + 1, *this);
- mSegments.insert(default_segment);
- default_segment->linkToDocument(this);
- }
-}
-
-LLStyleSP LLTextEditor::getDefaultStyle()
-{
- LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get() );
- return LLStyleSP(new LLStyle(LLStyle::Params().color(text_color).font(mDefaultFont)));
-}
-
-LLFastTimer::DeclareTimer FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments");
void LLTextEditor::updateSegments()
{
- LLFastTimer ft(FTM_UPDATE_TEXT_SEGMENTS);
+ LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
if (mKeywords.isLoaded())
{
// HACK: No non-ascii keywords for now
@@ -4125,11 +2496,11 @@ void LLTextEditor::updateSegments()
segment_set_t::iterator insert_it = mSegments.begin();
for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it)
{
- insert_it = mSegments.insert(insert_it, *list_it);
+ insertSegment(*list_it);
}
}
- createDefaultSegment();
+ LLTextBase::updateSegments();
}
void LLTextEditor::updateLinkSegments()
@@ -4155,66 +2526,7 @@ void LLTextEditor::updateLinkSegments()
}
}
-void LLTextEditor::insertSegment(LLTextSegmentPtr segment_to_insert)
-{
- if (segment_to_insert.isNull())
- {
- return;
- }
-
- segment_set_t::iterator cur_seg_iter = getSegIterContaining(segment_to_insert->getStart());
- if (cur_seg_iter == mSegments.end())
- {
- mSegments.insert(segment_to_insert);
- segment_to_insert->linkToDocument(this);
- }
- else
- {
- LLTextSegmentPtr cur_segmentp = *cur_seg_iter;
- if (cur_segmentp->getStart() < segment_to_insert->getStart())
- {
- S32 old_segment_end = cur_segmentp->getEnd();
- // split old at start point for new segment
- cur_segmentp->setEnd(segment_to_insert->getStart());
- // advance to next segment
- ++cur_seg_iter;
- // insert remainder of old segment
- LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( cur_segmentp->getStyle(), segment_to_insert->getStart(), old_segment_end, *this);
- cur_seg_iter = mSegments.insert(cur_seg_iter, remainder_segment);
- remainder_segment->linkToDocument(this);
- // insert new segment before remainder of old segment
- cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
-
- segment_to_insert->linkToDocument(this);
- // move to "remanider" segment and start truncation there
- ++cur_seg_iter;
- }
- else
- {
- cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
- ++cur_seg_iter;
- segment_to_insert->linkToDocument(this);
- }
-
- // now delete/truncate remaining segments as necessary
- while(cur_seg_iter != mSegments.end())
- {
- cur_segmentp = *cur_seg_iter;
- if (cur_segmentp->getEnd() <= segment_to_insert->getEnd())
- {
- cur_segmentp->unlinkFromDocument(this);
- segment_set_t::iterator seg_to_erase(cur_seg_iter++);
- mSegments.erase(seg_to_erase);
- }
- else
- {
- cur_segmentp->setStart(segment_to_insert->getEnd());
- break;
- }
- }
- }
-}
void LLTextEditor::onMouseCaptureLost()
{
@@ -4400,7 +2712,7 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,
if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
{
- mPreeditOverwrittenWString = getWSubString(insert_preedit_at, mPreeditWString.length());
+ mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length());
removeStringNoUndo(insert_preedit_at, mPreeditWString.length());
}
else
@@ -4415,7 +2727,7 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,
setCursorPos(insert_preedit_at + caret_position);
// Update of the preedit should be caused by some key strokes.
- mKeystrokeTimer.reset();
+ resetCursorBlink();
onKeyStroke();
}
@@ -4578,93 +2890,6 @@ S32 LLTextEditor::getPreeditFontSize() const
return llround(mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
}
-LLWString LLTextEditor::getWText() const
-{
- return getViewModel()->getDisplay();
-}
-
-void LLTextEditor::onValueChange(S32 start, S32 end)
-{
-}
-
-//
-// LLInlineViewSegment
-//
-
-LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end)
-: LLTextSegment(start, end),
- mView(view)
-{
-}
-
-LLInlineViewSegment::~LLInlineViewSegment()
-{
- mView->die();
-}
-
-S32 LLInlineViewSegment::getWidth(S32 first_char, S32 num_chars) const
-{
- if (first_char == 0 && num_chars == 0)
- {
- return 0;
- }
- else
- {
- return mView->getRect().getWidth();
- }
-}
-
-S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
-{
- if (line_offset != 0 && num_pixels < mView->getRect().getWidth())
- {
- return 0;
- }
- else
- {
- return mEnd - mStart;
- }
-}
-
-void LLInlineViewSegment::updateLayout(const LLTextBase& editor)
-{
- const LLTextEditor *ed = dynamic_cast<const LLTextEditor *>(&editor);
- if (ed)
- {
- LLRect start_rect = ed->getLocalRectFromDocIndex(mStart);
- LLRect doc_rect = ed->getDocumentPanel()->getRect();
- mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom);
- }
-}
-
-F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
-{
- return (F32)(draw_rect.mLeft + mView->getRect().getWidth());
-}
-
-S32 LLInlineViewSegment::getMaxHeight() const
-{
- return mView->getRect().getHeight();
-}
-
-void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor)
-{
- LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor);
- if (ed)
- {
- ed->removeDocumentChild(mView);
- }
-}
-
-void LLInlineViewSegment::linkToDocument(LLTextBase* editor)
-{
- LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor);
- if (ed)
- {
- ed->addDocumentChild(mView);
- }
-}
-
BOOL LLTextEditor::isDirty() const
{
if(mReadOnly)