summaryrefslogtreecommitdiff
path: root/indra/llui/lllineeditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/lllineeditor.cpp')
-rw-r--r--indra/llui/lllineeditor.cpp388
1 files changed, 99 insertions, 289 deletions
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 75905d0927..483a394bbd 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -34,6 +34,7 @@
#include "linden_common.h"
+#define LLLINEEDITOR_CPP
#include "lllineeditor.h"
#include "lltexteditor.h"
@@ -54,6 +55,7 @@
#include "llui.h"
#include "lluictrlfactory.h"
#include "llclipboard.h"
+#include "llmenugl.h"
//
// Imported globals
@@ -69,25 +71,18 @@ const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing
const F32 AUTO_SCROLL_TIME = 0.05f;
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval?
+const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET
+
static LLDefaultChildRegistry::Register<LLLineEditor> r1("line_editor");
+// Compiler optimization, generate extern template
+template class LLLineEditor* LLView::getChild<class LLLineEditor>(
+ const std::string& name, BOOL recurse) const;
+
//
// Member functions
//
-void LLLineEditor::PrevalidateNamedFuncs::declareValues()
-{
- declare("ascii", LLLineEditor::prevalidateASCII);
- declare("float", LLLineEditor::prevalidateFloat);
- declare("int", LLLineEditor::prevalidateInt);
- declare("positive_s32", LLLineEditor::prevalidatePositiveS32);
- declare("non_negative_s32", LLLineEditor::prevalidateNonNegativeS32);
- declare("alpha_num", LLLineEditor::prevalidateAlphaNum);
- declare("alpha_num_space", LLLineEditor::prevalidateAlphaNumSpace);
- declare("printable_not_pipe", LLLineEditor::prevalidatePrintableNotPipe);
- declare("printable_no_space", LLLineEditor::prevalidatePrintableNoSpace);
-}
-
LLLineEditor::Params::Params()
: max_length_bytes("max_length", 254),
keystroke_callback("keystroke_callback"),
@@ -125,8 +120,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mScrollHPos( 0 ),
mTextPadLeft(p.text_pad_left),
mTextPadRight(p.text_pad_right),
- mMinHPixels(0), // computed in updateTextPadding() below
- mMaxHPixels(0), // computed in updateTextPadding() below
+ mTextLeftEdge(0), // computed in updateTextPadding() below
+ mTextRightEdge(0), // computed in updateTextPadding() below
mCommitOnFocusLost( p.commit_on_focus_lost ),
mRevertOnEsc( p.revert_on_esc ),
mKeystrokeCallback( p.keystroke_callback() ),
@@ -157,7 +152,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mTentativeFgColor(p.text_tentative_color()),
mHighlightColor(p.highlight_color()),
mPreeditBgColor(p.preedit_bg_color()),
- mGLFont(p.font)
+ mGLFont(p.font),
+ mContextMenuHandle()
{
llassert( mMaxLengthBytes > 0 );
@@ -184,6 +180,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
setCursor(mText.length());
setPrevalidate(p.prevalidate_callback());
+
+ LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>
+ ("menu_text_editor.xml",
+ LLMenuGL::sMenuContainer,
+ LLMenuHolderGL::child_registry_t::instance());
+ setContextMenu(menu);
}
LLLineEditor::~LLLineEditor()
@@ -323,11 +325,23 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
mMaxLengthBytes = max_len;
}
+void LLLineEditor::getTextPadding(S32 *left, S32 *right)
+{
+ *left = mTextPadLeft;
+ *right = mTextPadRight;
+}
+
+void LLLineEditor::setTextPadding(S32 left, S32 right)
+{
+ mTextPadLeft = left;
+ mTextPadRight = right;
+ updateTextPadding();
+}
+
void LLLineEditor::updateTextPadding()
{
- static LLUICachedControl<S32> line_editor_hpad ("UILineEditorHPad", 0);
- mMinHPixels = line_editor_hpad + llclamp(mTextPadLeft, 0, getRect().getWidth());;
- mMaxHPixels = getRect().getWidth() - mMinHPixels - llclamp(mTextPadRight, 0, getRect().getWidth());
+ mTextLeftEdge = llclamp(mTextPadLeft, 0, getRect().getWidth());
+ mTextRightEdge = getRect().getWidth() - llclamp(mTextPadRight, 0, getRect().getWidth());
}
@@ -384,7 +398,7 @@ void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x )
{
for (S32 i = 0; i < mText.length(); i++)
{
- asterix_text += '*';
+ asterix_text += utf8str_to_wstring(PASSWORD_ASTERISK);
}
wtext = asterix_text.c_str();
}
@@ -393,8 +407,8 @@ void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x )
mScrollHPos +
mGLFont->charFromPixelOffset(
wtext, mScrollHPos,
- (F32)(local_mouse_x - mMinHPixels),
- (F32)(mMaxHPixels - mMinHPixels + 1)); // min-max range is inclusive
+ (F32)(local_mouse_x - mTextLeftEdge),
+ (F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive
setCursor(cursor_pos);
}
@@ -403,12 +417,16 @@ void LLLineEditor::setCursor( S32 pos )
S32 old_cursor_pos = getCursor();
mCursorPos = llclamp( pos, 0, mText.length());
+ // position of end of next character after cursor
S32 pixels_after_scroll = findPixelNearestPos();
- if( pixels_after_scroll > mMaxHPixels )
+ if( pixels_after_scroll > mTextRightEdge )
{
S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos);
- S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left)));
- S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels), mText.length(), getCursor());
+ S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mTextRightEdge - mTextLeftEdge + width_chars_to_left)));
+ // character immediately to left of cursor should be last one visible (SCROLL_INCREMENT_ADD will scroll in more characters)
+ // or first character if cursor is at beginning
+ S32 new_last_visible_char = llmax(0, getCursor() - 1);
+ S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mTextRightEdge - mTextLeftEdge), mText.length(), new_last_visible_char);
if (old_cursor_pos == last_visible_char)
{
mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD));
@@ -626,7 +644,8 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
// delay cursor flashing
mKeystrokeTimer.reset();
- mMouseDownSignal(this,x,y,mask);
+ if (mMouseDownSignal)
+ (*mMouseDownSignal)(this,x,y,mask);
return TRUE;
}
@@ -643,6 +662,16 @@ BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
return TRUE;
}
+BOOL LLLineEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ setFocus(TRUE);
+ if (!LLUICtrl::handleRightMouseDown(x, y, mask))
+ {
+ showContextMenu(x, y);
+ }
+ return TRUE;
+}
+
BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
@@ -668,17 +697,17 @@ BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask)
S32 increment = llround(mScrollTimer.getElapsedTimeF32() / AUTO_SCROLL_TIME);
mScrollTimer.reset();
mScrollTimer.setTimerExpirySec(AUTO_SCROLL_TIME);
- if( (x < mMinHPixels) && (mScrollHPos > 0 ) )
+ if( (x < mTextLeftEdge) && (mScrollHPos > 0 ) )
{
// Scroll to the left
mScrollHPos = llclamp(mScrollHPos - increment, 0, mText.length());
}
else
- if( (x > mMaxHPixels) && (mCursorPos < (S32)mText.length()) )
+ if( (x > mTextRightEdge) && (mCursorPos < (S32)mText.length()) )
{
// If scrolling one pixel would make a difference...
S32 pixels_after_scrolling_one_char = findPixelNearestPos(1);
- if( pixels_after_scrolling_one_char >= mMaxHPixels )
+ if( pixels_after_scrolling_one_char >= mTextRightEdge )
{
// ...scroll to the right
mScrollHPos = llclamp(mScrollHPos + increment, 0, mText.length());
@@ -742,7 +771,8 @@ BOOL LLLineEditor::handleMouseUp(S32 x, S32 y, MASK mask)
}
// We won't call LLUICtrl::handleMouseUp to avoid double calls of childrenHandleMouseUp().Just invoke the signal manually.
- mMouseUpSignal(this,x,y, mask);
+ if (mMouseUpSignal)
+ (*mMouseUpSignal)(this,x,y, mask);
return handled;
}
@@ -1564,7 +1594,6 @@ void LLLineEditor::draw()
F32 alpha = getDrawContext().mAlpha;
S32 text_len = mText.length();
static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0);
- static LLUICachedControl<S32> lineeditor_v_pad ("UILineEditorVPad", 0);
static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0);
static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0);
@@ -1581,7 +1610,7 @@ void LLLineEditor::draw()
std::string text;
for (S32 i = 0; i < mText.length(); i++)
{
- text += '*';
+ text += PASSWORD_ASTERISK;
}
mText = text;
}
@@ -1590,6 +1619,8 @@ void LLLineEditor::draw()
LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 );
background.stretch( -mBorderThickness );
+ S32 lineeditor_v_pad = llround((background.getHeight() - mGLFont->getLineHeight())/2);
+
drawBackground();
// draw text
@@ -1656,7 +1687,7 @@ void LLLineEditor::draw()
}
S32 rendered_text = 0;
- F32 rendered_pixels_right = (F32)mMinHPixels;
+ F32 rendered_pixels_right = (F32)mTextLeftEdge;
F32 text_bottom = (F32)background.mBottom + (F32)lineeditor_v_pad;
if( (gFocusMgr.getKeyboardFocus() == this) && hasSelection() )
@@ -1685,17 +1716,17 @@ void LLLineEditor::draw()
0,
LLFontGL::NO_SHADOW,
select_left - mScrollHPos,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right);
}
- if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )
+ if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) )
{
LLColor4 color = mHighlightColor;
color.setAlpha(alpha);
// selected middle
S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text);
- width = llmin(width, mMaxHPixels - llround(rendered_pixels_right));
+ width = llmin(width, mTextRightEdge - llround(rendered_pixels_right));
gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color);
LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );
@@ -1707,11 +1738,11 @@ void LLLineEditor::draw()
0,
LLFontGL::NO_SHADOW,
select_right - mScrollHPos - rendered_text,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right);
}
- if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )
+ if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) )
{
// unselected, right side
mGLFont->render(
@@ -1722,7 +1753,7 @@ void LLLineEditor::draw()
0,
LLFontGL::NO_SHADOW,
S32_MAX,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right);
}
}
@@ -1736,7 +1767,7 @@ void LLLineEditor::draw()
0,
LLFontGL::NO_SHADOW,
S32_MAX,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right);
}
#if 1 // for when we're ready for image art.
@@ -1794,14 +1825,14 @@ void LLLineEditor::draw()
if (0 == mText.length() && mReadOnly)
{
mGLFont->render(mLabel.getWString(), 0,
- mMinHPixels, (F32)text_bottom,
+ mTextLeftEdge, (F32)text_bottom,
label_color,
LLFontGL::LEFT,
LLFontGL::BOTTOM,
0,
LLFontGL::NO_SHADOW,
S32_MAX,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right, FALSE);
}
@@ -1819,14 +1850,14 @@ void LLLineEditor::draw()
if (0 == mText.length())
{
mGLFont->render(mLabel.getWString(), 0,
- mMinHPixels, (F32)text_bottom,
+ mTextLeftEdge, (F32)text_bottom,
label_color,
LLFontGL::LEFT,
LLFontGL::BOTTOM,
0,
LLFontGL::NO_SHADOW,
S32_MAX,
- mMaxHPixels - llround(rendered_pixels_right),
+ mTextRightEdge - llround(rendered_pixels_right),
&rendered_pixels_right, FALSE);
}
// Draw children (border)
@@ -1844,7 +1875,7 @@ void LLLineEditor::draw()
S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const
{
S32 dpos = getCursor() - mScrollHPos + cursor_offset;
- S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mMinHPixels;
+ S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mTextLeftEdge;
return result;
}
@@ -1940,51 +1971,12 @@ void LLLineEditor::setRect(const LLRect& rect)
}
}
-void LLLineEditor::setPrevalidate(LLLinePrevalidateFunc func)
+void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func)
{
mPrevalidateFunc = func;
updateAllowingLanguageInput();
}
-// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
-// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
-// the simple reasons that intermediate states may be invalid even if the final result is valid.
-//
-// static
-BOOL LLLineEditor::prevalidateFloat(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- BOOL success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- // May be a comma or period, depending on the locale
- llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint();
-
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
-}
-
// static
BOOL LLLineEditor::postvalidateFloat(const std::string &str)
{
@@ -2044,210 +2036,6 @@ BOOL LLLineEditor::postvalidateFloat(const std::string &str)
return success;
}
-// Limits what characters can be used to [1234567890-] with [-] only valid in the first position.
-// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
-// the simple reasons that intermediate states may be invalid even if the final result is valid.
-//
-// static
-BOOL LLLineEditor::prevalidateInt(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- BOOL success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
-}
-
-// static
-BOOL LLLineEditor::prevalidatePositiveS32(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- BOOL success = TRUE;
- if(0 < len)
- {
- if(('-' == trimmed[0]) || ('0' == trimmed[0]))
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val <= 0)
- {
- success = FALSE;
- }
- }
- return success;
-}
-
-BOOL LLLineEditor::prevalidateNonNegativeS32(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- BOOL success = TRUE;
- if(0 < len)
- {
- if('-' == trimmed[0])
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val < 0)
- {
- success = FALSE;
- }
- }
- return success;
-}
-
-BOOL LLLineEditor::prevalidateAlphaNum(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- BOOL rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if( !LLStringOps::isAlnum((char)str[len]) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
-}
-
-// static
-BOOL LLLineEditor::prevalidateAlphaNumSpace(const LLWString &str)
-{
- LLLocale locale(LLLocale::USER_LOCALE);
-
- BOOL rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len])))
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
-}
-
-// static
-BOOL LLLineEditor::prevalidatePrintableNotPipe(const LLWString &str)
-{
- BOOL rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if('|' == str[len])
- {
- rv = FALSE;
- break;
- }
- if(!((' ' == str[len]) || LLStringOps::isAlnum((char)str[len]) || LLStringOps::isPunct((char)str[len])))
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
-}
-
-
-// static
-BOOL LLLineEditor::prevalidatePrintableNoSpace(const LLWString &str)
-{
- BOOL rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if(LLStringOps::isSpace(str[len]))
- {
- rv = FALSE;
- break;
- }
- if( !(LLStringOps::isAlnum((char)str[len]) ||
- LLStringOps::isPunct((char)str[len]) ) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
-}
-
-// static
-BOOL LLLineEditor::prevalidateASCII(const LLWString &str)
-{
- BOOL rv = TRUE;
- S32 len = str.length();
- while(len--)
- {
- if (str[len] < 0x20 || str[len] > 0x7f)
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
-}
-
void LLLineEditor::onMouseCaptureLost()
{
endSelection();
@@ -2525,3 +2313,25 @@ LLWString LLLineEditor::getConvertedText() const
}
return text;
}
+
+void LLLineEditor::showContextMenu(S32 x, S32 y)
+{
+ LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get());
+
+ if (menu)
+ {
+ gEditMenuHandler = this;
+
+ S32 screen_x, screen_y;
+ localPointToScreen(x, y, &screen_x, &screen_y);
+ menu->show(screen_x, screen_y);
+ }
+}
+
+void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu)
+{
+ if (new_context_menu)
+ mContextMenuHandle = new_context_menu->getHandle();
+ else
+ mContextMenuHandle.markDead();
+}