summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorSteven Bennetts <steve@lindenlab.com>2008-08-13 19:37:05 +0000
committerSteven Bennetts <steve@lindenlab.com>2008-08-13 19:37:05 +0000
commitb9b4a4d9347053a3834ca2928063136948f09d1d (patch)
treec2affaf017c2967989ff0b4a2b125d348736a04a /indra/llui
parent0a3b9e8e141a6f38ecbdf6020312e7a89b153bc4 (diff)
QAR-782 Merge featurettes batch #2
merge featurettes-6-merge-2 -> release dataserver-is-deprecated
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/lllineeditor.cpp11
-rw-r--r--indra/llui/lllineeditor.h2
-rw-r--r--indra/llui/llmenugl.cpp4
-rw-r--r--indra/llui/lltexteditor.cpp158
-rw-r--r--indra/llui/lltexteditor.h4
-rw-r--r--indra/llui/llview.cpp4
6 files changed, 137 insertions, 46 deletions
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 666e807a8d..bacfe67ad8 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -2570,6 +2570,17 @@ void LLLineEditor::setReplaceNewlinesWithSpaces(BOOL replace)
mReplaceNewlinesWithSpaces = replace;
}
+LLWString LLLineEditor::getConvertedText() const
+{
+ LLWString text = getWText();
+ LLWStringUtil::trim(text);
+ if (!mReplaceNewlinesWithSpaces)
+ {
+ LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
+ }
+ return text;
+}
+
static LLRegisterWidget<LLSearchEditor> r2("search_editor");
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 8bf7613c79..c2dbedd3f5 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -140,6 +140,8 @@ public:
const std::string& getText() const { return mText.getString(); }
const LLWString& getWText() const { return mText.getWString(); }
+ LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines
+
S32 getLength() const { return mText.length(); }
S32 getCursor() const { return mCursorPos; }
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 3237ef8e27..03edaf69d3 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3484,8 +3484,8 @@ BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
// virtual
void LLPieMenu::arrange()
{
- const S32 rect_height = 180;
- const S32 rect_width = 180;
+ const S32 rect_height = 190;
+ const S32 rect_width = 190;
// all divide by 6
const S32 CARD_X = 60;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 4f02715d2c..ae97cfe13c 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -72,6 +72,8 @@ const S32 UI_TEXTEDITOR_BUFFER_BLOCK_SIZE = 512;
const S32 UI_TEXTEDITOR_BORDER = 1;
const S32 UI_TEXTEDITOR_H_PAD = 4;
const S32 UI_TEXTEDITOR_V_PAD_TOP = 4;
+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;
@@ -85,6 +87,7 @@ const S32 PREEDIT_STANDOUT_GAP = 1;
const S32 PREEDIT_STANDOUT_POSITION = 2;
const S32 PREEDIT_STANDOUT_THICKNESS = 2;
+
LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
void (* LLTextEditor::mURLcallback)(const std::string&) = NULL;
bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL;
@@ -269,6 +272,7 @@ LLTextEditor::LLTextEditor(
mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ),
mReadOnly(FALSE),
mWordWrap( FALSE ),
+ mShowLineNumbers ( FALSE ),
mTabsToNextField( TRUE ),
mCommitOnFocusLost( FALSE ),
mHideScrollbarForShortDocs( FALSE ),
@@ -397,7 +401,8 @@ void LLTextEditor::updateLineStartList(S32 startpos)
{
mLineStartList.push_back(line_info(seg_idx,seg_offset));
BOOL line_ended = FALSE;
- S32 line_width = 0;
+ S32 start_x = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
+ S32 line_width = start_x;
while(!line_ended && seg_idx < seg_num)
{
LLTextSegment* segment = mSegments[seg_idx];
@@ -427,7 +432,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
const llwchar* str = mWText.c_str() + start_idx;
S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width,
end_idx - start_idx, mWordWrap, mAllowEmbeddedItems );
- if( 0 == drawn && line_width == 0)
+ if( 0 == drawn && line_width == start_x)
{
// If at the beginning of a line, draw at least one character, even if it doesn't all fit.
drawn = 1;
@@ -798,7 +803,12 @@ void LLTextEditor::getSelectedSegments(std::vector<const LLTextSegment*>& segmen
S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
{
- // If round is true, if the position is on the right half of a character, the cursor
+ if(mShowLineNumbers)
+ {
+ local_x -= UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
+ }
+
+ // 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.
@@ -2467,20 +2477,15 @@ void LLTextEditor::drawBackground()
S32 right = getRect().getWidth();
S32 bottom = 0;
- LLColor4 bg_color = mReadOnlyBgColor;
-
- if( !mReadOnly )
- {
- if (gFocusMgr.getKeyboardFocus() == this)
- {
- bg_color = mFocusBgColor;
- }
- else
- {
- bg_color = mWriteableBgColor;
- }
+ LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor
+ : gFocusMgr.getKeyboardFocus() == this ? mFocusBgColor : mWriteableBgColor;
+ if( mShowLineNumbers ) {
+ gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor ); // line number area always read-only
+ gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, right, bottom, bg_color); // body text area to the right of line numbers
+ gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
+ } else {
+ gl_rect_2d(left, top, right, bottom, bg_color); // body text area
}
- gl_rect_2d(left, top, right, bottom, bg_color);
LLView::draw();
}
@@ -2593,12 +2598,13 @@ void LLTextEditor::drawSelectionBackground()
const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor;
F32 alpha = hasFocus() ? 1.f : 0.5f;
gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
+ S32 margin_offset = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
if( selection_left_y == selection_right_y )
{
// Draw from selection start to selection end
- gl_rect_2d( selection_left_x, selection_left_y + line_height + 1,
- selection_right_x, selection_right_y);
+ gl_rect_2d( selection_left_x + margin_offset, selection_left_y + line_height + 1,
+ selection_right_x + margin_offset, selection_right_y);
}
else
{
@@ -2610,16 +2616,16 @@ void LLTextEditor::drawSelectionBackground()
S32 line_end = line_endings.front();
line_endings.pop();
- gl_rect_2d( selection_left_x, selection_left_y + line_height + 1,
- line_end, selection_left_y );
+ gl_rect_2d( selection_left_x + margin_offset, selection_left_y + line_height + 1,
+ line_end + margin_offset, selection_left_y );
S32 line_num = left_line_num + 1;
while(line_endings.size())
{
S32 vert_offset = -(line_num - left_line_num) * line_height;
// Draw the block between the two lines
- gl_rect_2d( mTextRect.mLeft, selection_left_y + vert_offset + line_height + 1,
- line_endings.front(), selection_left_y + vert_offset);
+ gl_rect_2d( mTextRect.mLeft + margin_offset, selection_left_y + vert_offset + line_height + 1,
+ line_endings.front() + margin_offset, selection_left_y + vert_offset);
line_endings.pop();
line_num++;
}
@@ -2629,8 +2635,8 @@ void LLTextEditor::drawSelectionBackground()
{
selection_right_x += CURSOR_THICKNESS;
}
- gl_rect_2d( mTextRect.mLeft, selection_right_y + line_height + 1,
- selection_right_x, selection_right_y );
+ gl_rect_2d( mTextRect.mLeft + margin_offset, selection_right_y + line_height + 1,
+ selection_right_x + margin_offset, selection_right_y );
}
}
}
@@ -2693,6 +2699,11 @@ void LLTextEditor::drawCursor()
cur_pos++;
}
+ if(mShowLineNumbers)
+ {
+ cursor_left += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
+ }
+
// Draw the cursor
if( cursor_visible )
{
@@ -2859,10 +2870,7 @@ void LLTextEditor::drawText()
{
const LLWString &text = mWText;
const S32 text_len = getLength();
- if( text_len <= 0 )
- {
- return;
- }
+ 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
@@ -2874,14 +2882,26 @@ void LLTextEditor::drawText()
LLGLSUIDefault gls_ui;
- S32 cur_line = mScrollbar->getDocPos();
+ // There are several concepts that are important for understanding the following drawing code.
+ // The document is logically a sequence of characters (stored in a LLWString).
+ // Variables below with "start" or "end" in their names refer to positions or offsets into it.
+ // Next there are two kinds of "line" variables to understand. Newline characters in the
+ // character sequence represent logical lines. These are what get numbered and so variables
+ // representing this kind of line have "num" in their names.
+ // The others represent line fragments or displayed lines which the scrollbar deals with.
+ // When the "show line numbers" property is turned on, we draw line numbers to the left of the
+ // beginning of each logical line and not in front of wrapped "continuation" display lines. -MG
+
+ S32 cur_line = mScrollbar->getDocPos(); // scrollbar counts each wrap as a new line.
S32 num_lines = getLineCount();
- if (cur_line >= num_lines)
- {
- return;
- }
-
+ if (cur_line >= num_lines) return;
S32 line_start = getLineStart(cur_line);
+ S32 prev_start = getLineStart(cur_line-1);
+ S32 cur_line_num = getLineForPosition(line_start); // doesn't count wraps. i.e. only counts newlines.
+ S32 prev_line_num = getLineForPosition(prev_start);
+ BOOL cur_line_is_continuation = cur_line_num > 0 && cur_line_num == prev_line_num;
+ BOOL line_wraps = FALSE;
+
LLTextSegment t(line_start);
segment_list_t::iterator seg_iter;
seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare());
@@ -2900,12 +2920,36 @@ void LLTextEditor::drawText()
next_start = getLineStart(cur_line + 1);
line_end = next_start;
}
- if ( text[line_end-1] == '\n' )
+ line_wraps = text[line_end-1] != '\n';
+ if ( ! line_wraps )
{
- --line_end;
+ --line_end; // don't attempt to draw the newline char.
}
- F32 text_x = (F32)mTextRect.mLeft;
+ F32 text_start = (F32)mTextRect.mLeft;
+ F32 text_x = text_start + (mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0);
+
+ // draw the line numbers
+ if( mShowLineNumbers && !cur_line_is_continuation)
+ {
+ const LLFontGL *num_font = LLFontGL::sMonospace;
+ F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2);
+ const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num ));
+ BOOL is_cur_line = getCurrentLine() == cur_line_num;
+ const U8 style = is_cur_line ? LLFontGL::BOLD : LLFontGL::NORMAL;
+ const LLColor4 fg_color = is_cur_line ? LLColor4::black : LLColor4::grey4;
+ num_font->render(
+ ltext, // string to draw
+ 0, // begin offset
+ 3., // x
+ y_top, // y
+ fg_color,
+ LLFontGL::LEFT, // horizontal alignment
+ LLFontGL::VCENTER, // vertical alignment
+ style,
+ S32_MAX, // max chars
+ UI_TEXTEDITOR_LINE_NUMBER_MARGIN); // max pixels
+ }
S32 seg_start = line_start;
while( seg_start < line_end )
@@ -2950,16 +2994,28 @@ void LLTextEditor::drawText()
drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x );
+ if( text_x == text_start && mShowLineNumbers )
+ {
+ text_x += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
+ }
+
// Note: text_x is incremented by drawClippedSegment()
seg_start += clipped_len;
}
}
- // move down one line
- text_y -= (F32)line_height;
+ // move down one line
+ text_y -= (F32)line_height;
+
+ if( line_wraps )
+ {
+ cur_line_num--;
+ }
+ cur_line_is_continuation = line_wraps; // so as to not not number the continuation lines
line_start = next_start;
cur_line++;
+ cur_line_num++;
}
}
@@ -3258,8 +3314,7 @@ void LLTextEditor::setCursorAndScrollToEnd()
updateScrollFromCursor();
}
-
-void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap )
+void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap )
{
if( include_wordwrap )
{
@@ -3271,7 +3326,7 @@ void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wo
S32 line_count = 0;
S32 line_start = 0;
S32 i;
- for( i = 0; text[i] && (i < mCursorPos); i++ )
+ for( i = 0; text[i] && (i < position); i++ )
{
if( '\n' == text[i] )
{
@@ -3284,6 +3339,23 @@ void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wo
}
}
+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()
{
@@ -4152,6 +4224,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
node->getAttributeBOOL("word_wrap", word_wrap);
setWordWrap(word_wrap);
+ node->getAttributeBOOL("show_line_numbers", mShowLineNumbers);
+
node->getAttributeBOOL("track_bottom", mTrackBottom);
LLColor4 color;
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index e261d13872..ff93d087ea 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -160,7 +160,10 @@ public:
void setCursorPos(S32 offset);
void setCursorAndScrollToEnd();
+ void getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap );
void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap );
+ S32 getLineForPosition(S32 position);
+ S32 getCurrentLine();
void loadKeywords(const std::string& filename,
const std::vector<std::string>& funcs,
@@ -500,6 +503,7 @@ private:
BOOL mReadOnly;
BOOL mWordWrap;
+ BOOL mShowLineNumbers;
BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces
BOOL mCommitOnFocusLost;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index b05014d94e..3bce976c8a 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -724,9 +724,9 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s
tool_tip = getShowNamesToolTip();
}
- BOOL showNamesTextBox = LLUI::sShowXUINames && dynamic_cast<LLTextBox*>(this) != NULL;
+ BOOL show_names_text_box = LLUI::sShowXUINames && dynamic_cast<LLTextBox*>(this) != NULL;
- if( !handled && (blockMouseEvent(x, y) || showNamesTextBox) && !tool_tip.empty())
+ if( !handled && (blockMouseEvent(x, y) || show_names_text_box))
{
msg = tool_tip;