summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorKelly Washington <kelly@lindenlab.com>2007-05-30 17:39:09 +0000
committerKelly Washington <kelly@lindenlab.com>2007-05-30 17:39:09 +0000
commit3e9872a297c3cf3f929e688e0e89a78f6bc050f5 (patch)
treeab3877f764cc27dbdca0b683f07e6ea3a3ac8a23 /indra/llui
parent7b61f1d0ec30e97fd3b7c5caf4b0e675c6e9a1f5 (diff)
merge -r61423:62602 svn/branches/maintenance --> release
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/lllineeditor.cpp81
-rw-r--r--indra/llui/lllineeditor.h10
-rw-r--r--indra/llui/lltexteditor.cpp25
-rw-r--r--indra/llui/lltexteditor.h1
-rw-r--r--indra/llui/llview.cpp3
5 files changed, 117 insertions, 3 deletions
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 43ea584aa1..7e7999c9f9 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -137,6 +137,14 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
{
llassert( max_length_bytes > 0 );
+ // line history support:
+ // - initialize line history list
+ mLineHistory.insert( mLineHistory.end(), "" );
+ // - disable line history by default
+ mHaveHistory = FALSE;
+ // - reset current history line pointer
+ mCurrentHistoryLine = 0;
+
if (font)
{
mGLFont = font;
@@ -209,10 +217,33 @@ void LLLineEditor::onFocusLost()
void LLLineEditor::onCommit()
{
+ // put current line into the line history
+ updateHistory();
+
LLUICtrl::onCommit();
selectAll();
}
+// line history support
+void LLLineEditor::updateHistory()
+{
+ // On history enabled line editors, remember committed line and
+ // reset current history line number.
+ // Be sure only to remember lines that are not empty and that are
+ // different from the last on the list.
+ if( mHaveHistory && mText.length() && ( mLineHistory.empty() || getText() != mLineHistory.back() ) )
+ {
+ // discard possible empty line at the end of the history
+ // inserted by setText()
+ if( !mLineHistory.back().length() )
+ {
+ mLineHistory.pop_back();
+ }
+ mLineHistory.insert( mLineHistory.end(), getText() );
+ mCurrentHistoryLine = mLineHistory.size() - 1;
+ }
+}
+
void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
{
LLUICtrl::reshape(width, height, called_from_parent );
@@ -220,6 +251,10 @@ void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
mMaxHPixels = mRect.getWidth() - 2 * (mBorderThickness + UI_LINEEDITOR_H_PAD) + 1 - mBorderRight;
}
+void LLLineEditor::setEnableLineHistory( BOOL enabled )
+{
+ mHaveHistory = enabled;
+}
void LLLineEditor::setEnabled(BOOL enabled)
{
@@ -280,6 +315,13 @@ void LLLineEditor::setText(const LLString &new_text)
deselect();
}
setCursor(llmin((S32)mText.length(), getCursor()));
+
+ // Newly set text goes always in the last line of history.
+ // Possible empty strings (as with chat line) will be deleted later.
+ mLineHistory.insert( mLineHistory.end(), new_text );
+ // Set current history line to end of history.
+ mCurrentHistoryLine = mLineHistory.size() - 1;
+
mPrevText = mText;
}
@@ -1066,6 +1108,45 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
}
break;
+ // handle ctrl-uparrow if we have a history enabled line editor.
+ case KEY_UP:
+ if( mHaveHistory && ( MASK_CONTROL & mask ) )
+ {
+ if( mCurrentHistoryLine > 0 )
+ {
+ mText.assign( mLineHistory[ --mCurrentHistoryLine ] );
+ setCursor(llmin((S32)mText.length(), getCursor()));
+ }
+ else
+ {
+ reportBadKeystroke();
+ }
+ handled = TRUE;
+ }
+ break;
+
+ // handle ctrl-downarrow if we have a history enabled line editor
+ case KEY_DOWN:
+ if( mHaveHistory && ( MASK_CONTROL & mask ) )
+ {
+ if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.size() - 1 )
+ {
+ mText.assign( mLineHistory[ ++mCurrentHistoryLine ] );
+ setCursor(llmin((S32)mText.length(), getCursor()));
+ }
+ else
+ {
+ reportBadKeystroke();
+ }
+ handled = TRUE;
+ }
+ break;
+
+ case KEY_RETURN:
+ // store sent line in history
+ updateHistory();
+ break;
+
case KEY_ESCAPE:
if (mRevertOnEsc && mText.getString() != mPrevText)
{
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 27ae351d1f..b3eff3c8e2 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -16,6 +16,7 @@
// Clipboard (cut, copy, and paste)
// Horizontal scrolling to allow strings longer than widget size allows
// Pre-validation (limit which keys can be used)
+// Optional line history so previous entries can be recalled by CTRL UP/DOWN
#ifndef LL_LLLINEEDITOR_H
@@ -186,6 +187,10 @@ public:
static BOOL postvalidateFloat(const LLString &str);
+ // line history support:
+ void setEnableLineHistory( BOOL enabled ); // switches line history on or off
+ void updateHistory(); // stores current line in history
+
protected:
void removeChar();
void addChar(const llwchar c);
@@ -204,6 +209,11 @@ protected:
LLString mPrevText; // Saved string for 'ESC' revert
LLUIString mLabel; // text label that is visible when no user text provided
+ // line history support:
+ BOOL mHaveHistory; // flag for enabled line history
+ std::vector<LLString> mLineHistory; // line history storage
+ U32 mCurrentHistoryLine; // currently browsed history line
+
LLViewBorder* mBorder;
const LLFontGL* mGLFont;
S32 mMaxLengthChars; // Max number of characters
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 2b588cacce..9363415dc2 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -289,6 +289,9 @@ LLTextEditor::LLTextEditor(
{
mSourceID.generate();
+ // reset desired x cursor position
+ mDesiredXPixel = -1;
+
if (font)
{
mGLFont = font;
@@ -894,6 +897,8 @@ void LLTextEditor::setCursorPos(S32 offset)
{
mCursorPos = llclamp(offset, 0, (S32)getLength());
updateScrollFromCursor();
+ // reset desired x cursor position
+ mDesiredXPixel = -1;
}
@@ -3078,6 +3083,9 @@ void LLTextEditor::changePage( S32 delta )
S32 line, offset;
getLineAndOffset( mCursorPos, &line, &offset );
+ // get desired x position to remember previous position
+ S32 desired_x_pixel = mDesiredXPixel;
+
// allow one line overlap
S32 page_size = mScrollbar->getPageSize() - 1;
if( delta == -1 )
@@ -3092,6 +3100,10 @@ void LLTextEditor::changePage( S32 delta )
setCursorPos(getPos( line + page_size, offset ));
mScrollbar->setDocPos( mScrollbar->getDocPos() + page_size );
}
+
+ // put desired position into remember-buffer after setCursorPos()
+ mDesiredXPixel = desired_x_pixel;
+
if (mOnScrollEndCallback && mOnScrollEndData && (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()))
{
mOnScrollEndCallback(mOnScrollEndData);
@@ -3107,9 +3119,13 @@ void LLTextEditor::changeLine( S32 delta )
S32 line_start = getLineStart(line);
- S32 desired_x_pixel;
-
- desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems );
+ // set desired x position to remembered previous position
+ S32 desired_x_pixel = mDesiredXPixel;
+ // if remembered position was reset (thus -1), calculate new one here
+ if( desired_x_pixel == -1 )
+ {
+ desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems );
+ }
S32 new_line = 0;
if( (delta < 0) && (line > 0 ) )
@@ -3145,6 +3161,9 @@ void LLTextEditor::changeLine( S32 delta )
mAllowEmbeddedItems);
setCursorPos (getPos( new_line, new_offset ));
+
+ // put desired position into remember-buffer after setCursorPos()
+ mDesiredXPixel = desired_x_pixel;
unbindEmbeddedChars( mGLFont );
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index d95230f0dc..7454b192fd 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -339,6 +339,7 @@ protected:
undo_stack_t mUndoStack;
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
+ S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be
LLRect mTextRect; // The rect in which text is drawn. Excludes borders.
// List of offsets and segment index of the start of each line. Always has at least one node (0).
struct line_info
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index da5c77fc94..05c2247a35 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -176,6 +176,9 @@ LLView::~LLView()
(*itor).second->clearDispatchers();
delete (*itor).second;
}
+
+ std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
+ DeletePairedPointer());
}
// virtual