diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llui/llbutton.cpp | 17 | ||||
-rw-r--r-- | indra/llui/llflatlistview.cpp | 47 | ||||
-rw-r--r-- | indra/llui/llflatlistview.h | 5 | ||||
-rw-r--r-- | indra/llui/lllineeditor.cpp | 319 | ||||
-rw-r--r-- | indra/llui/lllineeditor.h | 38 | ||||
-rw-r--r-- | indra/llui/llmenugl.cpp | 1 | ||||
-rw-r--r-- | indra/llui/llmultisliderctrl.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llnotifications.h | 2 | ||||
-rw-r--r-- | indra/llui/llpanel.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llpanel.h | 2 | ||||
-rw-r--r-- | indra/llui/llsliderctrl.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llspinctrl.cpp | 2 | ||||
-rw-r--r-- | indra/llui/lltabcontainer.cpp | 147 | ||||
-rw-r--r-- | indra/llui/lltabcontainer.h | 18 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 31 | ||||
-rw-r--r-- | indra/llui/lltextbase.h | 6 | ||||
-rw-r--r-- | indra/llui/lltexteditor.cpp | 128 | ||||
-rw-r--r-- | indra/llui/lltexteditor.h | 11 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.cpp | 302 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.h | 63 | ||||
-rw-r--r-- | indra/llui/lltooltip.h | 3 | ||||
-rw-r--r-- | indra/llui/llurlentry.cpp | 2 |
23 files changed, 716 insertions, 436 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index ce068618e2..853f6f173d 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -90,6 +90,7 @@ set(llui_SOURCE_FILES lltextbox.cpp lltexteditor.cpp lltextparser.cpp + lltextvalidate.cpp lltransutil.cpp lltoggleablemenu.cpp lltooltip.cpp @@ -182,6 +183,7 @@ set(llui_HEADER_FILES lltextbox.h lltexteditor.h lltextparser.h + lltextvalidate.h lltoggleablemenu.h lltooltip.h lltransutil.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 4944ed4fe7..14b77925f2 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -771,12 +771,7 @@ void LLButton::draw() center_x++; } - S32 text_width_delta = overlay_width + 1; - // if image paddings set, they should participate in scaling process - S32 image_size_delta = mImageOverlayTopPad + mImageOverlayBottomPad; - overlay_width = overlay_width - image_size_delta; - overlay_height = overlay_height - image_size_delta; - + center_y += (mImageOverlayBottomPad - mImageOverlayTopPad); // fade out overlay images on disabled buttons LLColor4 overlay_color = mImageOverlayColor.get(); if (!enabled) @@ -788,10 +783,9 @@ void LLButton::draw() switch(mImageOverlayAlignment) { case LLFontGL::LEFT: - text_left += overlay_width + mImageOverlayRightPad + 1; - text_width -= text_width_delta; + text_left += overlay_width + 1; mImageOverlay->draw( - mLeftHPad, + mImageOverlayLeftPad, center_y - (overlay_height / 2), overlay_width, overlay_height, @@ -806,10 +800,9 @@ void LLButton::draw() overlay_color); break; case LLFontGL::RIGHT: - text_right -= overlay_width + mImageOverlayLeftPad+ 1; - text_width -= text_width_delta; + text_right -= overlay_width + 1; mImageOverlay->draw( - getRect().getWidth() - mRightHPad - overlay_width, + getRect().getWidth() - mImageOverlayRightPad - overlay_width, center_y - (overlay_height / 2), overlay_width, overlay_height, diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 92993650a7..2481249f91 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -42,8 +42,6 @@ static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("fl const LLSD SELECTED_EVENT = LLSD().with("selected", true); const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); -static const std::string COMMENT_TEXTBOX = "comment_text"; - //forward declaration bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2); @@ -51,7 +49,8 @@ LLFlatListView::Params::Params() : item_pad("item_pad"), allow_select("allow_select"), multi_select("multi_select"), - keep_one_selected("keep_one_selected") + keep_one_selected("keep_one_selected"), + no_items_text("no_items_text") {}; void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) @@ -295,19 +294,6 @@ void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) { - if (NULL == mNoItemsCommentTextbox) - { - LLRect comment_rect = getRect(); - comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); - comment_rect.stretch(-getBorderWidth()); - LLTextBox::Params text_p; - text_p.name(COMMENT_TEXTBOX); - text_p.border_visible(false); - text_p.rect(comment_rect); - text_p.follows.flags(FOLLOWS_ALL); - mNoItemsCommentTextbox = LLUICtrlFactory::create<LLTextBox>(text_p, this); - } - mNoItemsCommentTextbox->setValue(comment_text); } @@ -361,7 +347,6 @@ bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value) // PROTECTED STUFF ////////////////////////////////////////////////////////////////////////// - LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) : LLScrollContainer(p) , mItemComparator(NULL) @@ -398,6 +383,25 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) params.bevel_style(LLViewBorder::BEVEL_IN); mSelectedItemsBorder = LLUICtrlFactory::create<LLViewBorder> (params); mItemsPanel->addChild( mSelectedItemsBorder ); + + { + // create textbox for "No Items" comment text + LLTextBox::Params text_p = p.no_items_text; + if (!text_p.rect.isProvided()) + { + LLRect comment_rect = getRect(); + comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); + comment_rect.stretch(-getBorderWidth()); + text_p.rect(comment_rect); + } + text_p.border_visible(false); + + if (!text_p.follows.isProvided()) + { + text_p.follows.flags(FOLLOWS_ALL); + } + mNoItemsCommentTextbox = LLUICtrlFactory::create<LLTextBox>(text_p, this); + } }; // virtual @@ -861,7 +865,11 @@ void LLFlatListView::notifyParentItemsRectChanged() // take into account comment text height if exists if (mNoItemsCommentTextbox && mNoItemsCommentTextbox->getVisible()) { + // top text padding inside the textbox is included into the height comment_height = mNoItemsCommentTextbox->getTextPixelHeight(); + + // take into account a distance from parent's top border to textbox's top + comment_height += getRect().getHeight() - mNoItemsCommentTextbox->getRect().mTop; } LLRect req_rect = getItemsRect(); @@ -892,6 +900,10 @@ void LLFlatListView::setNoItemsCommentVisible(bool visible) const { if (visible) { +/* +// *NOTE: MA 2010-02-04 +// Deprecated after params of the comment text box were moved into widget (flat_list_view.xml) +// can be removed later if nothing happened. // We have to update child rect here because of issues with rect after reshaping while creating LLTextbox // It is possible to have invalid LLRect if Flat List is in LLAccordionTab LLRect comment_rect = getLocalRect(); @@ -903,6 +915,7 @@ void LLFlatListView::setNoItemsCommentVisible(bool visible) const LLViewBorder* scroll_border = getChild<LLViewBorder>("scroll border"); comment_rect.stretch(-scroll_border->getBorderWidth()); mNoItemsCommentTextbox->setRect(comment_rect); +*/ } mNoItemsCommentTextbox->setVisible(visible); } diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 949a731507..92cb40332e 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -35,8 +35,8 @@ #include "llpanel.h" #include "llscrollcontainer.h" +#include "lltextbox.h" -class LLTextBox; /** * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's. @@ -108,6 +108,9 @@ public: /** padding between items */ Optional<U32> item_pad; + /** textbox with info message when list is empty*/ + Optional<LLTextBox::Params> no_items_text; + Params(); }; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index eb2b4f7705..483a394bbd 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -55,6 +55,7 @@ #include "llui.h" #include "lluictrlfactory.h" #include "llclipboard.h" +#include "llmenugl.h" // // Imported globals @@ -82,19 +83,6 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>( // 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("ascii_printable_no_pipe", LLLineEditor::prevalidateASCIIPrintableNoPipe); - declare("ascii_printable_no_space", LLLineEditor::prevalidateASCIIPrintableNoSpace); -} - LLLineEditor::Params::Params() : max_length_bytes("max_length", 254), keystroke_callback("keystroke_callback"), @@ -164,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 ); @@ -191,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() @@ -422,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 > 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)(mTextRightEdge - mTextLeftEdge + width_chars_to_left))); - S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mTextRightEdge - mTextLeftEdge), mText.length(), getCursor()); + // 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)); @@ -663,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; @@ -1962,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) { @@ -2066,223 +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; -} - -// Used for most names of things stored on the server, due to old file-formats -// that used the pipe (|) for multiline text storage. Examples include -// inventory item names, parcel names, object names, etc. -// static -BOOL LLLineEditor::prevalidateASCIIPrintableNoPipe(const LLWString &str) -{ - BOOL rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || wc == '|') - { - rv = FALSE; - break; - } - if(!(wc == ' ' - || LLStringOps::isAlnum((char)wc) - || LLStringOps::isPunct((char)wc) ) ) - { - rv = FALSE; - break; - } - } - return rv; -} - - -// Used for avatar names -// static -BOOL LLLineEditor::prevalidateASCIIPrintableNoSpace(const LLWString &str) -{ - BOOL rv = TRUE; - S32 len = str.length(); - if(len == 0) return rv; - while(len--) - { - llwchar wc = str[len]; - if (wc < 0x20 - || wc > 0x7f - || LLStringOps::isSpace(wc)) - { - 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(); @@ -2560,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(); +} diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 49e9539b16..b62138426b 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -51,26 +51,18 @@ #include "llviewborder.h" #include "llpreeditor.h" -#include <boost/function.hpp> +#include "lltextvalidate.h" class LLFontGL; class LLLineEditorRollback; class LLButton; - -typedef boost::function<BOOL (const LLWString &wstr)> LLLinePrevalidateFunc; +class LLContextMenu; class LLLineEditor : public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor { public: - struct PrevalidateNamedFuncs - : public LLInitParam::TypeValuesHelper<LLLinePrevalidateFunc, PrevalidateNamedFuncs> - - { - static void declareValues(); - }; - typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t; struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> @@ -80,7 +72,7 @@ public: Optional<keystroke_callback_t> keystroke_callback; - Optional<LLLinePrevalidateFunc, PrevalidateNamedFuncs> prevalidate_callback; + Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; Optional<LLViewBorder::Params> border; @@ -113,6 +105,7 @@ protected: LLLineEditor(const Params&); friend class LLUICtrlFactory; friend class LLFloaterEditUI; + void showContextMenu(S32 x, S32 y); public: virtual ~LLLineEditor(); @@ -122,6 +115,7 @@ public: /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ void onMouseCaptureLost(); @@ -204,6 +198,8 @@ public: const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); } const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); } + const LLFontGL* getFont() const { return mGLFont; } + void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; } void setIgnoreTab(BOOL b) { mIgnoreTab = b; } void setPassDelete(BOOL b) { mPassDelete = b; } @@ -231,17 +227,7 @@ public: void setTextPadding(S32 left, S32 right); // Prevalidation controls which keystrokes can affect the editor - void setPrevalidate( LLLinePrevalidateFunc func ); - static BOOL prevalidateFloat(const LLWString &str ); - static BOOL prevalidateInt(const LLWString &str ); - static BOOL prevalidatePositiveS32(const LLWString &str); - static BOOL prevalidateNonNegativeS32(const LLWString &str); - static BOOL prevalidateAlphaNum(const LLWString &str ); - static BOOL prevalidateAlphaNumSpace(const LLWString &str ); - static BOOL prevalidateASCIIPrintableNoPipe(const LLWString &str); - static BOOL prevalidateASCIIPrintableNoSpace(const LLWString &str); - static BOOL prevalidateASCII(const LLWString &str); - + void setPrevalidate( LLTextValidate::validate_func_t func ); static BOOL postvalidateFloat(const std::string &str); // line history support: @@ -249,7 +235,9 @@ public: void updateHistory(); // stores current line in history void setReplaceNewlinesWithSpaces(BOOL replace); - + + void setContextMenu(LLContextMenu* new_context_menu); + private: // private helper methods @@ -319,7 +307,7 @@ protected: S32 mLastSelectionStart; S32 mLastSelectionEnd; - LLLinePrevalidateFunc mPrevalidateFunc; + LLTextValidate::validate_func_t mPrevalidateFunc; LLFrameTimer mKeystrokeTimer; LLTimer mTripleClickTimer; @@ -348,6 +336,8 @@ protected: std::vector<S32> mPreeditPositions; LLPreeditor::standouts_t mPreeditStandouts; + LLHandle<LLView> mContextMenuHandle; + private: // Instances that by default point to the statics but can be overidden in XML. LLPointer<LLUIImage> mBgImage; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7fa9a88059..d18abbfb2f 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3941,7 +3941,6 @@ BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu) item = LLUICtrlFactory::create<LLContextMenuBranch>(p); LLMenuGL::sMenuContainer->addChild(item->getBranch()); - item->setFont( LLFontGL::getFontSansSerif() ); return append( item ); } diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index f4434a0f78..cb81c39103 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -138,7 +138,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) params.font(p.font); params.max_length_bytes(MAX_STRING_LENGTH); params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit); - params.prevalidate_callback(&LLLineEditor::prevalidateFloat); + params.prevalidate_callback(&LLTextValidate::validateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index d55e0f4043..8d993b71d7 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -371,7 +371,7 @@ private: // this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT // for anything real! - LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mTemporaryResponder(false) {} + LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mPriority(NOTIFICATION_PRIORITY_UNSPECIFIED), mTemporaryResponder(false) {} void cancel(); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 7f23fe2671..7b406e090a 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -936,7 +936,7 @@ LLPanel *LLPanel::childGetVisiblePanelWithHelp() return ::childGetVisiblePanelWithHelp(this); } -void LLPanel::childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWString &) ) +void LLPanel::childSetPrevalidate(const std::string& id, bool (*func)(const LLWString &) ) { LLLineEditor* child = findChild<LLLineEditor>(id); if (child) diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 6de83fe3a7..4e53fd7ea3 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -226,7 +226,7 @@ public: std::string childGetText(const std::string& id) const { return childGetValue(id).asString(); } // LLLineEditor - void childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWString &) ); + void childSetPrevalidate(const std::string& id, bool (*func)(const LLWString &) ); // LLButton void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value = NULL); diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 01c274bb4e..80ee5d0984 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -141,7 +141,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) line_p.rect.setIfNotProvided(text_rect); line_p.font.setIfNotProvided(p.font); line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit); - line_p.prevalidate_callback(&LLLineEditor::prevalidateFloat); + line_p.prevalidate_callback(&LLTextValidate::validateFloat); mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index 28f3788817..491cd7b6f3 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -127,7 +127,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p) } params.max_length_bytes(MAX_STRING_LENGTH); params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2))); - params.prevalidate_callback(&LLLineEditor::prevalidateFloat); + params.prevalidate_callback(&LLTextValidate::validateFloat); params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); mEditor = LLUICtrlFactory::create<LLLineEditor> (params); mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 6be76605fd..19408989a5 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -35,7 +35,6 @@ #include "lltabcontainer.h" #include "llfocusmgr.h" -#include "llbutton.h" #include "lllocalcliprect.h" #include "llrect.h" #include "llresizehandle.h" @@ -96,6 +95,90 @@ public: //---------------------------------------------------------------------------- +//============================================================================ +/* + * @file lltabcontainer.cpp + * @brief class implements LLButton with LLIconCtrl on it + */ +class LLCustomButtonIconCtrl : public LLButton +{ +public: + struct Params + : public LLInitParam::Block<Params, LLButton::Params> + { + // LEFT, RIGHT, TOP, BOTTOM paddings of LLIconCtrl in this class has same value + Optional<S32> icon_ctrl_pad; + + Params(): + icon_ctrl_pad("icon_ctrl_pad", 1) + {} + }; + +protected: + friend class LLUICtrlFactory; + LLCustomButtonIconCtrl(const Params& p): + LLButton(p), + mIcon(NULL), + mIconCtrlPad(p.icon_ctrl_pad) + {} + +public: + + void updateLayout() + { + LLRect button_rect = getRect(); + LLRect icon_rect = mIcon->getRect(); + + S32 icon_size = button_rect.getHeight() - 2*mIconCtrlPad; + + switch(mIconAlignment) + { + case LLFontGL::LEFT: + icon_rect.setLeftTopAndSize(button_rect.mLeft + mIconCtrlPad, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setLeftHPad(icon_size + mIconCtrlPad * 2); + break; + case LLFontGL::HCENTER: + icon_rect.setLeftTopAndSize(button_rect.mRight - (button_rect.getWidth() + mIconCtrlPad - icon_size)/2, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setRightHPad(icon_size + mIconCtrlPad * 2); + break; + case LLFontGL::RIGHT: + icon_rect.setLeftTopAndSize(button_rect.mRight - mIconCtrlPad - icon_size, button_rect.mTop - mIconCtrlPad, + icon_size, icon_size); + setRightHPad(icon_size + mIconCtrlPad * 2); + break; + default: + break; + } + mIcon->setRect(icon_rect); + } + + void setIcon(LLIconCtrl* icon, LLFontGL::HAlign alignment = LLFontGL::LEFT) + { + if(icon) + { + if(mIcon) + { + removeChild(mIcon); + mIcon->die(); + } + mIcon = icon; + mIconAlignment = alignment; + + addChild(mIcon); + updateLayout(); + } + } + + +private: + LLIconCtrl* mIcon; + LLFontGL::HAlign mIconAlignment; + S32 mIconCtrlPad; +}; +//============================================================================ + struct LLPlaceHolderPanel : public LLPanel { // create dummy param block to register with "placeholder" nane @@ -127,7 +210,9 @@ LLTabContainer::Params::Params() tab_padding_right("tab_padding_right"), first_tab("first_tab"), middle_tab("middle_tab"), - last_tab("last_tab") + last_tab("last_tab"), + use_custom_icon_ctrl("use_custom_icon_ctrl", false), + tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0) { name(std::string("tab_container")); mouse_opaque = false; @@ -162,7 +247,9 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mFont(p.font), mFirstTabParams(p.first_tab), mMiddleTabParams(p.middle_tab), - mLastTabParams(p.last_tab) + mLastTabParams(p.last_tab), + mCustomIconCtrlUsed(p.use_custom_icon_ctrl), + mTabIconCtrlPad(p.tab_icon_ctrl_pad) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -905,6 +992,11 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) LLTextBox* textbox = NULL; LLButton* btn = NULL; + LLCustomButtonIconCtrl::Params custom_btn_params; + { + custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad); + } + LLButton::Params normal_btn_params; if (placeholder) { @@ -924,7 +1016,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) { if (mIsVertical) { - LLButton::Params p; + LLButton::Params& p = (mCustomIconCtrlUsed)? + custom_btn_params:normal_btn_params; + p.name(std::string("vert tab button")); p.rect(btn_rect); p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); @@ -942,11 +1036,22 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) { p.pad_left(indent); } - btn = LLUICtrlFactory::create<LLButton>(p); + + + if(mCustomIconCtrlUsed) + { + btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); + + } + else + { + btn = LLUICtrlFactory::create<LLButton>(p); + } } else { - LLButton::Params p; + LLButton::Params& p = (mCustomIconCtrlUsed)? + custom_btn_params:normal_btn_params; p.name(std::string(child->getName()) + " tab"); p.rect(btn_rect); p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); @@ -980,7 +1085,14 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM; } -++ btn = LLUICtrlFactory::create<LLButton>(p); + if(mCustomIconCtrlUsed) + { + btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); + } + else + { + btn = LLUICtrlFactory::create<LLButton>(p); + } } } @@ -1484,7 +1596,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L if( tuple ) { tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color); - reshape_tuple(tuple); + reshapeTuple(tuple); } } @@ -1494,11 +1606,26 @@ void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const L if( tuple ) { tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color); - reshape_tuple(tuple); + reshapeTuple(tuple); + } +} + +void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon) +{ + LLTabTuple* tuple = getTabByPanel(child); + LLCustomButtonIconCtrl* button; + + if(tuple) + { + button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); + if(button) + { + button->setIcon(icon); + } } } -void LLTabContainer::reshape_tuple(LLTabTuple* tuple) +void LLTabContainer::reshapeTuple(LLTabTuple* tuple) { static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); static LLUICachedControl<S32> image_left_padding ("UIButtonImageLeftPadding", 4); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 2a55877d3c..4b5d45fb73 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -36,6 +36,8 @@ #include "llpanel.h" #include "lltextbox.h" #include "llframetimer.h" +#include "lliconctrl.h" +#include "llbutton.h" class LLTabTuple; @@ -90,6 +92,16 @@ public: middle_tab, last_tab; + /** + * Use LLCustomButtonIconCtrl or LLButton in LLTabTuple + */ + Optional<bool> use_custom_icon_ctrl; + + /** + * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) + */ + Optional<S32> tab_icon_ctrl_pad; + Params(); }; @@ -173,6 +185,7 @@ public: void setTabPanelFlashing(LLPanel* child, BOOL state); void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); void setTabImage(LLPanel* child, const LLUUID& img_id, const LLColor4& color = LLColor4::white); + void setTabImage(LLPanel* child, LLIconCtrl* icon); void setTitle( const std::string& title ); const std::string getPanelTitle(S32 index); @@ -228,7 +241,7 @@ private: // updates tab button images given the tuple, tab position and the corresponding params void update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos); - void reshape_tuple(LLTabTuple* tuple); + void reshapeTuple(LLTabTuple* tuple); // Variables @@ -278,6 +291,9 @@ private: TabParams mFirstTabParams; TabParams mMiddleTabParams; TabParams mLastTabParams; + + bool mCustomIconCtrlUsed; + S32 mTabIconCtrlPad; }; #endif // LL_TABCONTAINER_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index b977e50bc1..a83cc19d36 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -185,7 +185,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mWriteableBgColor(p.bg_writeable_color), mReadOnlyBgColor(p.bg_readonly_color), mFocusBgColor(p.bg_focus_color), - mReflowNeeded(FALSE), + mReflowIndex(S32_MAX), mCursorPos( 0 ), mScrollNeeded(FALSE), mDesiredXPixel(-1), @@ -660,7 +660,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } onValueChange(pos, pos + insert_len); - needsReflow(); + needsReflow(pos); return insert_len; } @@ -720,7 +720,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) createDefaultSegment(); onValueChange(pos, pos); - needsReflow(); + needsReflow(pos); return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length } @@ -736,7 +736,7 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc) getViewModel()->setDisplay(text); onValueChange(pos, pos + 1); - needsReflow(); + needsReflow(pos); return 1; } @@ -762,15 +762,18 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) } segment_set_t::iterator cur_seg_iter = getSegIterContaining(segment_to_insert->getStart()); + S32 reflow_start_index = 0; if (cur_seg_iter == mSegments.end()) { mSegments.insert(segment_to_insert); segment_to_insert->linkToDocument(this); + reflow_start_index = segment_to_insert->getStart(); } else { LLTextSegmentPtr cur_segmentp = *cur_seg_iter; + reflow_start_index = cur_segmentp->getStart(); if (cur_segmentp->getStart() < segment_to_insert->getStart()) { S32 old_segment_end = cur_segmentp->getEnd(); @@ -829,7 +832,7 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) } // layout potentially changed - needsReflow(); + needsReflow(reflow_start_index); } BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) @@ -1084,15 +1087,16 @@ S32 LLTextBase::getLeftOffset(S32 width) static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow"); -void LLTextBase::reflow(S32 start_index) +void LLTextBase::reflow() { LLFastTimer ft(FTM_TEXT_REFLOW); updateSegments(); - while(mReflowNeeded) + while(mReflowIndex < S32_MAX) { - mReflowNeeded = false; + S32 start_index = mReflowIndex; + mReflowIndex = S32_MAX; // shrink document to minimum size (visible portion of text widget) // to force inlined widgets with follows set to shrink @@ -1133,6 +1137,7 @@ void LLTextBase::reflow(S32 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; + cur_top = iter->mRect.mTop; getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); mLineInfoList.erase(iter, mLineInfoList.end()); } @@ -1619,6 +1624,12 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c } } +void LLTextBase::needsReflow(S32 index) +{ + lldebugs << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << llendl; + mReflowIndex = llmin(mReflowIndex, index); +} + void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& style_params) { if (new_text.empty()) return; @@ -2260,7 +2271,7 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e LLUIImagePtr image = mStyle->getImage(); if (image.notNull()) { - mImageLoadedConnection = image->addLoadedCallback(boost::bind(&LLTextBase::needsReflow, &mEditor)); + mImageLoadedConnection = image->addLoadedCallback(boost::bind(&LLTextBase::needsReflow, &mEditor, start)); } } @@ -2323,8 +2334,6 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha; - font = mStyle->getFont(); - if( selection_start > seg_start ) { // Draw normally diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index ed2f239476..3dda6f4cc8 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -150,7 +150,7 @@ public: void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); // force reflow of text - void needsReflow() { mReflowNeeded = TRUE; } + void needsReflow(S32 index = 0); S32 getLength() const { return getWText().length(); } S32 getLineCount() const { return mLineInfoList.size(); } @@ -292,7 +292,7 @@ protected: S32 getFirstVisibleLine() const; std::pair<S32, S32> getVisibleLines(bool fully_visible = false); S32 getLeftOffset(S32 width); - void reflow(S32 start_index = 0); + void reflow(); // cursor void updateCursorXPos(); @@ -362,7 +362,7 @@ protected: class LLScrollContainer* mScroller; // transient state - bool mReflowNeeded; // need to reflow text because of change to text contents or display region + S32 mReflowIndex; // index at which to start reflow. S32_MAX indicates no reflow needed. bool mScrollNeeded; // need to change scroll region because of change to cursor position S32 mScrollIndex; // index of first character to keep visible in scroll region diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index e76fee9f17..ad9f066539 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -237,13 +237,17 @@ private: /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() : default_text("default_text"), + prevalidate_callback("prevalidate_callback"), embedded_items("embedded_items", false), ignore_tab("ignore_tab", true), handle_edit_keys_directly("handle_edit_keys_directly", false), show_line_numbers("show_line_numbers", false), default_color("default_color"), - commit_on_focus_lost("commit_on_focus_lost", false) -{} + commit_on_focus_lost("commit_on_focus_lost", false), + show_context_menu("show_context_menu") +{ + addSynonym(prevalidate_callback, "text_type"); +} LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : LLTextBase(p), @@ -258,7 +262,9 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mMouseDownX(0), mMouseDownY(0), mTabsToNextField(p.ignore_tab), - mContextMenu(NULL) + mPrevalidateFunc(p.prevalidate_callback()), + mContextMenu(NULL), + mShowContextMenu(p.show_context_menu) { mDefaultFont = p.font; @@ -318,6 +324,17 @@ LLTextEditor::~LLTextEditor() void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { + // validate incoming text if necessary + if (mPrevalidateFunc) + { + LLWString test_text = utf8str_to_wstring(utf8str); + if (!mPrevalidateFunc(test_text)) + { + // not valid text, nothing to do + return; + } + } + blockUndo(); deselect(); @@ -720,7 +737,10 @@ BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) } if (!LLTextBase::handleRightMouseDown(x, y, mask)) { - showContextMenu(x, y); + if(getChowContextMenu()) + { + showContextMenu(x, y); + } } return TRUE; } @@ -906,6 +926,21 @@ S32 LLTextEditor::execute( TextCmd* cmd ) // Push the new command is now on the top (front) of the undo stack. mUndoStack.push_front(cmd); mLastCmd = cmd; + + bool need_to_rollback = mPrevalidateFunc + && !mPrevalidateFunc(getViewModel()->getDisplay()); + if (need_to_rollback) + { + // get rid of this last command and clean up undo stack + undo(); + + // remove any evidence of this command from redo history + mUndoStack.pop_front(); + delete cmd; + + // failure, nothing changed + delta = 0; + } } else { @@ -1029,7 +1064,21 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) if (mLastCmd && mLastCmd->canExtend(pos)) { S32 delta = 0; + if (mPrevalidateFunc) + { + // get a copy of current text contents + LLWString test_string(getViewModel()->getDisplay()); + + // modify text contents as if this addChar succeeded + llassert(pos <= (S32)test_string.size()); + test_string.insert(pos, 1, wc); + if (!mPrevalidateFunc( test_string)) + { + return 0; + } + } mLastCmd->extendAndExecute(this, pos, wc, &delta); + return delta; } else @@ -1285,8 +1334,6 @@ void LLTextEditor::cut() gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID ); deleteSelection( FALSE ); - needsReflow(); - onKeyStroke(); } @@ -1391,8 +1438,6 @@ void LLTextEditor::pasteHelper(bool is_primary) setCursorPos(mCursorPos + insert(mCursorPos, clean_string, FALSE, LLTextSegmentPtr())); deselect(); - needsReflow(); - onKeyStroke(); } @@ -1787,8 +1832,6 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) if(text_may_have_changed) { - needsReflow(); - onKeyStroke(); } needsScroll(); @@ -1831,8 +1874,6 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) // Most keystrokes will make the selection box go away, but not all will. deselect(); - needsReflow(); - onKeyStroke(); } @@ -1891,8 +1932,6 @@ void LLTextEditor::doDelete() } onKeyStroke(); - - needsReflow(); } //---------------------------------------------------------------------------- @@ -1935,8 +1974,6 @@ void LLTextEditor::undo() setCursorPos(pos); - needsReflow(); - onKeyStroke(); } @@ -1979,8 +2016,6 @@ void LLTextEditor::redo() setCursorPos(pos); - needsReflow(); - onKeyStroke(); } @@ -2339,8 +2374,6 @@ void LLTextEditor::insertText(const std::string &new_text) setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - needsReflow(); - setEnabled( enabled ); } @@ -2363,8 +2396,6 @@ void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); insert(getLength(), widget_wide_text, FALSE, segment); - needsReflow(); - // Set the cursor and scroll position if( selection_start != selection_end ) { @@ -2389,52 +2420,6 @@ void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const } } - -void LLTextEditor::replaceUrlLabel(const std::string &url, - const std::string &label) -{ - // get the full (wide) text for the editor so we can change it - LLWString text = getWText(); - LLWString wlabel = utf8str_to_wstring(label); - bool modified = false; - S32 seg_start = 0; - - // iterate through each segment looking for ones styled as links - segment_set_t::iterator it; - for (it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *seg = *it; - LLStyleConstSP style = seg->getStyle(); - - // update segment start/end length in case we replaced text earlier - S32 seg_length = seg->getEnd() - seg->getStart(); - seg->setStart(seg_start); - seg->setEnd(seg_start + seg_length); - - // if we find a link with our Url, then replace the label - if (style->isLink() && style->getLinkHREF() == url) - { - S32 start = seg->getStart(); - S32 end = seg->getEnd(); - text = text.substr(0, start) + wlabel + text.substr(end, text.size() - end + 1); - seg->setEnd(start + wlabel.size()); - modified = true; - } - - // work out the character offset for the next segment - seg_start = seg->getEnd(); - } - - // update the editor with the new (wide) text string - if (modified) - { - getViewModel()->setDisplay(text); - deselect(); - setCursorPos(mCursorPos); - needsReflow(); - } -} - void LLTextEditor::removeTextFromEnd(S32 num_chars) { if (num_chars <= 0) return; @@ -2446,7 +2431,6 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars) mSelectionStart = llclamp(mSelectionStart, 0, len); mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsReflow(); needsScroll(); } @@ -2505,8 +2489,6 @@ BOOL LLTextEditor::tryToRevertToPristineState() i--; } } - - needsReflow(); } return isPristine(); // TRUE => success @@ -2574,7 +2556,7 @@ void LLTextEditor::updateLinkSegments() // then update the link's HREF to be the same as the label text. // This lets users edit Urls in-place. LLStyleConstSP style = segment->getStyle(); - LLStyle* new_style = new LLStyle(*style); + LLStyleSP new_style(new LLStyle(*style)); LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); if (LLUrlRegistry::instance().hasUrl(url_label)) { @@ -2681,7 +2663,6 @@ BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) startOfDoc(); deselect(); - needsReflow(); return success; } @@ -2785,7 +2766,6 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string, mPreeditStandouts = preedit_standouts; - needsReflow(); setCursorPos(insert_preedit_at + caret_position); // Update of the preedit should be caused by some key strokes. diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 043dda8fa6..00c6a8b68a 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -44,6 +44,7 @@ #include "lldarray.h" #include "llviewborder.h" // for params #include "lltextbase.h" +#include "lltextvalidate.h" #include "llpreeditor.h" #include "llcontrol.h" @@ -63,12 +64,14 @@ public: struct Params : public LLInitParam::Block<Params, LLTextBase::Params> { Optional<std::string> default_text; + Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; Optional<bool> embedded_items, ignore_tab, handle_edit_keys_directly, show_line_numbers, - commit_on_focus_lost; + commit_on_focus_lost, + show_context_menu; //colors Optional<LLUIColor> default_color; @@ -149,7 +152,6 @@ public: void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); - void replaceUrlLabel(const std::string &url, const std::string &label); // Undo/redo stack void blockUndo(); @@ -201,6 +203,9 @@ public: const LLTextSegmentPtr getPreviousSegment() const; void getSelectedSegments(segment_vec_t& segments) const; + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getChowContextMenu() const { return mShowContextMenu; } + protected: void showContextMenu(S32 x, S32 y); void drawPreeditMarker(); @@ -320,6 +325,7 @@ private: BOOL mTakesFocus; BOOL mAllowEmbeddedItems; + bool mShowContextMenu; LLUUID mSourceID; @@ -330,6 +336,7 @@ private: LLCoordGL mLastIMEPosition; // Last position of the IME editor keystroke_signal_t mKeystrokeSignal; + LLTextValidate::validate_func_t mPrevalidateFunc; LLContextMenu* mContextMenu; }; // end class LLTextEditor diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp new file mode 100644 index 0000000000..8b6bc5bd7d --- /dev/null +++ b/indra/llui/lltextvalidate.cpp @@ -0,0 +1,302 @@ +/** + * @file lltextvalidate.cpp + * @brief Text validation helper functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Text editor widget to let users enter a single line. + +#include "linden_common.h" + +#include "lltextvalidate.h" +#include "llresmgr.h" // for LLLocale + +namespace LLTextValidate +{ + void ValidateTextNamedFuncs::declareValues() + { + declare("ascii", validateASCII); + declare("float", validateFloat); + declare("int", validateInt); + declare("positive_s32", validatePositiveS32); + declare("non_negative_s32", validateNonNegativeS32); + declare("alpha_num", validateAlphaNum); + declare("alpha_num_space", validateAlphaNumSpace); + declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); + declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); + } + + // 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. + // + bool validateFloat(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; + } + + // 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. + // + bool validateInt(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; + } + + bool validatePositiveS32(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 validateNonNegativeS32(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 validateAlphaNum(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; + } + + bool validateAlphaNumSpace(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; + } + + // Used for most names of things stored on the server, due to old file-formats + // that used the pipe (|) for multiline text storage. Examples include + // inventory item names, parcel names, object names, etc. + bool validateASCIIPrintableNoPipe(const LLWString &str) + { + bool rv = TRUE; + S32 len = str.length(); + if(len == 0) return rv; + while(len--) + { + llwchar wc = str[len]; + if (wc < 0x20 + || wc > 0x7f + || wc == '|') + { + rv = FALSE; + break; + } + if(!(wc == ' ' + || LLStringOps::isAlnum((char)wc) + || LLStringOps::isPunct((char)wc) ) ) + { + rv = FALSE; + break; + } + } + return rv; + } + + + // Used for avatar names + bool validateASCIIPrintableNoSpace(const LLWString &str) + { + bool rv = TRUE; + S32 len = str.length(); + if(len == 0) return rv; + while(len--) + { + llwchar wc = str[len]; + if (wc < 0x20 + || wc > 0x7f + || LLStringOps::isSpace(wc)) + { + rv = FALSE; + break; + } + if( !(LLStringOps::isAlnum((char)str[len]) || + LLStringOps::isPunct((char)str[len]) ) ) + { + rv = FALSE; + break; + } + } + return rv; + } + + bool validateASCII(const LLWString &str) + { + bool rv = TRUE; + S32 len = str.length(); + while(len--) + { + if (str[len] < 0x20 || str[len] > 0x7f) + { + rv = FALSE; + break; + } + } + return rv; + } +} diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h new file mode 100644 index 0000000000..ffb4e85e7c --- /dev/null +++ b/indra/llui/lltextvalidate.h @@ -0,0 +1,63 @@ +/** + * @file lltextbase.h + * @author Martin Reddy + * @brief The base class of text box/editor, providing Url handling support + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXTVALIDATE_H +#define LL_LLTEXTVALIDATE_H + +#include "llstring.h" +#include "llinitparam.h" +#include <boost/function.hpp> + +namespace LLTextValidate +{ + typedef boost::function<BOOL (const LLWString &wstr)> validate_func_t; + + struct ValidateTextNamedFuncs + : public LLInitParam::TypeValuesHelper<validate_func_t, ValidateTextNamedFuncs> + { + static void declareValues(); + }; + + bool validateFloat(const LLWString &str ); + bool validateInt(const LLWString &str ); + bool validatePositiveS32(const LLWString &str); + bool validateNonNegativeS32(const LLWString &str); + bool validateAlphaNum(const LLWString &str ); + bool validateAlphaNumSpace(const LLWString &str ); + bool validateASCIIPrintableNoPipe(const LLWString &str); + bool validateASCIIPrintableNoSpace(const LLWString &str); + bool validateASCII(const LLWString &str); +} + + +#endif diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 7978b6a583..c0811c56c3 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -129,7 +129,8 @@ private: class LLInspector : public LLToolTip { public: - struct Params : public LLInitParam::Block<Params, LLToolTip::Params> {}; + struct Params : public LLInitParam::Block<Params, LLToolTip::Params> + {}; }; class LLToolTipMgr : public LLSingleton<LLToolTipMgr> diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index b20de914a0..92b7816bdd 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -232,7 +232,7 @@ std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const LLUrlEntrySLURL::LLUrlEntrySLURL() { // see http://slurl.com/about.php for details on the SLURL format - mPattern = boost::regex("http://slurl.com/secondlife/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", + mPattern = boost::regex("http://(maps.secondlife.com|slurl.com)/secondlife/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); |