diff options
Diffstat (limited to 'indra/llui')
28 files changed, 791 insertions, 431 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..1d4dc35cee 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -81,10 +81,9 @@ LLButton::Params::Params() image_pressed_selected("image_pressed_selected"), image_overlay("image_overlay"), image_overlay_alignment("image_overlay_alignment", std::string("center")), - image_left_pad("image_left_pad"), - image_right_pad("image_right_pad"), image_top_pad("image_top_pad"), image_bottom_pad("image_bottom_pad"), + imgoverlay_label_space("imgoverlay_label_space", 1), label_color("label_color"), label_color_selected("label_color_selected"), // requires is_toggle true label_color_disabled("label_color_disabled"), @@ -144,10 +143,9 @@ LLButton::LLButton(const LLButton::Params& p) mImageOverlay(p.image_overlay()), mImageOverlayColor(p.image_overlay_color()), mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), - mImageOverlayLeftPad(p.image_left_pad), - mImageOverlayRightPad(p.image_right_pad), mImageOverlayTopPad(p.image_top_pad), mImageOverlayBottomPad(p.image_bottom_pad), + mImgOverlayLabelSpace(p.imgoverlay_label_space), mIsToggle(p.is_toggle), mScaleImage(p.scale_image), mDropShadowedText(p.label_shadow), @@ -771,12 +769,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 +781,9 @@ void LLButton::draw() switch(mImageOverlayAlignment) { case LLFontGL::LEFT: - text_left += overlay_width + mImageOverlayRightPad + 1; - text_width -= text_width_delta; + text_left += overlay_width + mImgOverlayLabelSpace; mImageOverlay->draw( - mLeftHPad, + mLeftHPad, center_y - (overlay_height / 2), overlay_width, overlay_height, @@ -806,10 +798,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 + mImgOverlayLabelSpace; mImageOverlay->draw( - getRect().getWidth() - mRightHPad - overlay_width, + getRect().getWidth() - mRightHPad - overlay_width, center_y - (overlay_height / 2), overlay_width, overlay_height, diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 8e5f19602f..8f35db1007 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -107,11 +107,14 @@ public: Optional<S32> pad_bottom; // under text label //image overlay paddings - Optional<S32> image_left_pad; - Optional<S32> image_right_pad; Optional<S32> image_top_pad; Optional<S32> image_bottom_pad; + /** + * Space between image_overlay and label + */ + Optional<S32> imgoverlay_label_space; + // callbacks Optional<CommitCallbackParam> click_callback, // alias -> commit_callback mouse_down_callback, @@ -192,10 +195,6 @@ public: void setLeftHPad( S32 pad ) { mLeftHPad = pad; } void setRightHPad( S32 pad ) { mRightHPad = pad; } - void setImageOverlayLeftPad( S32 pad ) { mImageOverlayLeftPad = pad; } - S32 getImageOverlayLeftPad() const { return mImageOverlayLeftPad; } - void setImageOverlayRightPad( S32 pad ) { mImageOverlayRightPad = pad; } - S32 getImageOverlayRightPad() const { return mImageOverlayRightPad; } void setImageOverlayTopPad( S32 pad ) { mImageOverlayTopPad = pad; } S32 getImageOverlayTopPad() const { return mImageOverlayTopPad; } void setImageOverlayBottomPad( S32 pad ) { mImageOverlayBottomPad = pad; } @@ -328,11 +327,14 @@ private: S32 mRightHPad; S32 mBottomVPad; // under text label - S32 mImageOverlayLeftPad; - S32 mImageOverlayRightPad; S32 mImageOverlayTopPad; S32 mImageOverlayBottomPad; + /* + * Space between image_overlay and label + */ + S32 mImgOverlayLabelSpace; + F32 mHoverGlowStrength; F32 mCurGlowStrength; diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index 0237c80efa..a4f69e7ac1 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -244,23 +244,6 @@ void LLConsole::draw() } } -void LLConsole::addLine(const std::string& utf8line) -{ - LLWString wline = utf8str_to_wstring(utf8line); - addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f)); -} - -void LLConsole::addLine(const LLWString& wline) -{ - addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f)); -} - -void LLConsole::addLine(const std::string& utf8line, F32 size, const LLColor4 &color) -{ - LLWString wline = utf8str_to_wstring(utf8line); - addLine(wline, size, color); -} - //Generate highlight color segments for this paragraph. Pass in default color of paragraph. void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) { @@ -383,21 +366,45 @@ void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, b //Pass in the string and the default color for this block of text. LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width) - : mParagraphText(str), mAddTime(add_time), mMaxWidth(-1) +: mParagraphText(str), mAddTime(add_time), mMaxWidth(-1) { makeParagraphColorSegments(color); updateLines( screen_width, font ); } -void LLConsole::addLine(const LLWString& wline, F32 size, const LLColor4 &color) +// called once per frame regardless of console visibility +// static +void LLConsole::updateClass() { - Paragraph paragraph(wline, color, mTimer.getElapsedTimeF32(), mFont, (F32)getRect().getWidth() ); - - mParagraphs.push_back ( paragraph ); + LLInstanceTrackerScopedGuard guard; + + for (instance_iter it = guard.beginInstances(); it != guard.endInstances(); ++it) + { + it->update(); + } +} + +void LLConsole::update() +{ + { + LLMutexLock lock(&mMutex); + + while (!mLines.empty()) + { + mParagraphs.push_back( + Paragraph( mLines.front(), + LLColor4::white, + mTimer.getElapsedTimeF32(), + mFont, + (F32)getRect().getWidth())); + mLines.pop_front(); + } + } // remove old paragraphs which can't possibly be visible any more. ::draw() will do something similar but more conservative - we do this here because ::draw() isn't guaranteed to ever be called! (i.e. the console isn't visible) - while ((S32)mParagraphs.size() > llmax((S32)0, (S32)(mMaxLines))) - { - mParagraphs.pop_front(); - } + while ((S32)mParagraphs.size() > llmax((S32)0, (S32)(mMaxLines))) + { + mParagraphs.pop_front(); + } } + diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h index 4719950f28..f38e2bc9c2 100644 --- a/indra/llui/llconsole.h +++ b/indra/llui/llconsole.h @@ -40,7 +40,7 @@ class LLSD; -class LLConsole : public LLFixedBuffer, public LLUICtrl +class LLConsole : public LLFixedBuffer, public LLUICtrl, public LLInstanceTracker<LLConsole> { public: typedef enum e_font_size @@ -68,6 +68,9 @@ protected: friend class LLUICtrlFactory; public: + // call once per frame to pull data out of LLFixedBuffer + static void updateClass(); + //A paragraph color segment defines the color of text in a line //of text that was received for console display. It has no //notion of line wraps, screen position, or the text it contains. @@ -139,14 +142,12 @@ public: // -1 = monospace, 0 means small, font size = 1 means big void setFontSize(S32 size_index); - void addLine(const std::string& utf8line, F32 size, const LLColor4 &color); - void addLine(const LLWString& wline, F32 size, const LLColor4 &color); // Overrides /*virtual*/ void draw(); - /*virtual*/ void addLine(const std::string& utf8line); - /*virtual*/ void addLine(const LLWString& line); private: + void update(); + F32 mLinePersistTime; // Age at which to stop drawing. F32 mFadeTime; // Age at which to start fading const LLFontGL* mFont; 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/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 1aaba88c49..dc79550eb4 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -816,7 +816,10 @@ void LLLayoutStack::calcMinExtents() //static void LLLayoutStack::updateClass() { - for (LLLayoutStack::instance_iter it = beginInstances(); it != endInstances(); ++it) + LLInstanceTrackerScopedGuard guard; + for (LLLayoutStack::instance_iter it = guard.beginInstances(); + it != guard.endInstances(); + ++it) { it->updateLayout(); } 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/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 78738c826d..33d47a3f0e 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -92,14 +92,6 @@ void LLMultiFloater::draw() } else { - for (S32 i = 0; i < mTabContainer->getTabCount(); i++) - { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i); - if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i)) - { - mTabContainer->setPanelTitle(i, floaterp->getShortTitle()); - } - } LLFloater::draw(); } } diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index f4434a0f78..50942e55ca 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) ); @@ -331,6 +331,10 @@ void LLMultiSliderCtrl::updateText() void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata) { LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); + llassert(self); + if (!self) // cast failed - wrong type! :O + return; + if (!ctrl) return; 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..13340e7ded 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,91 @@ 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), + mIconAlignment(LLFontGL::HCENTER), + 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 +211,10 @@ 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), + use_ellipses("use_ellipses") { name(std::string("tab_container")); mouse_opaque = false; @@ -162,7 +249,10 @@ 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), + mUseTabEllipses(p.use_ellipses) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -905,6 +995,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 +1019,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 +1039,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 +1088,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); + } } } @@ -1373,8 +1488,8 @@ BOOL LLTabContainer::setTab(S32 which) { LLTabTuple* tuple = *iter; BOOL is_selected = ( tuple == selected_tuple ); - tuple->mButton->setUseEllipses(TRUE); - tuple->mButton->setHAlign(LLFontGL::LEFT); + tuple->mButton->setUseEllipses(mUseTabEllipses); + tuple->mButton->setHAlign(mFontHalign); tuple->mTabPanel->setVisible( is_selected ); // tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. tuple->mButton->setToggleState( is_selected ); @@ -1484,7 +1599,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,25 +1609,31 @@ 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::reshape_tuple(LLTabTuple* 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::reshapeTuple(LLTabTuple* tuple) { static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - static LLUICachedControl<S32> image_left_padding ("UIButtonImageLeftPadding", 4); - static LLUICachedControl<S32> image_right_padding ("UIButtonImageRightPadding", 4); - static LLUICachedControl<S32> image_top_padding ("UIButtonImageTopPadding", 2); - static LLUICachedControl<S32> image_bottom_padding ("UIButtonImageBottomPadding", 2); if (!mIsVertical) { - tuple->mButton->setImageOverlayLeftPad(image_left_padding); - tuple->mButton->setImageOverlayRightPad(image_right_padding); - tuple->mButton->setImageOverlayTopPad(image_top_padding); - tuple->mButton->setImageOverlayBottomPad(image_bottom_padding); - // remove current width from total tab strip width mTotalTabWidth -= tuple->mButton->getRect().getWidth(); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 2a55877d3c..50ec2679f6 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,26 @@ public: middle_tab, last_tab; + /** + * Tab label horizontal alignment + */ + Optional<LLFontGL::HAlign> font_halign; + + /** + * Tab label ellipses + */ + Optional<bool> use_ellipses; + + /** + * 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 +195,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 +251,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 +301,10 @@ private: TabParams mFirstTabParams; TabParams mMiddleTabParams; TabParams mLastTabParams; + + bool mCustomIconCtrlUsed; + S32 mTabIconCtrlPad; + bool mUseTabEllipses; }; #endif // LL_TABCONTAINER_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e923e60db4..ef422dbdc5 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1137,6 +1137,7 @@ void LLTextBase::reflow() 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()); } @@ -1577,7 +1578,7 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c // Text will be replaced during rendering with the icon, // but string cannot be empty or the segment won't be // added (or drawn). - appendAndHighlightText(" ", prepend_newline, part, icon); + appendAndHighlightText(" ", prepend_newline, part, icon); prepend_newline = false; } } @@ -2311,7 +2312,7 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec image->draw(draw_rect.mLeft, image_bottom, style_image_width, style_image_height, color); - const S32 IMAGE_HPAD = 2; + const S32 IMAGE_HPAD = 3; return draw_rect.mLeft + style_image_width + IMAGE_HPAD; } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 62aeb50011..ce5f1bd082 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(getShowContextMenu()) + { + 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 diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index a136f9ccce..71d937b2c4 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; @@ -200,6 +203,9 @@ public: const LLTextSegmentPtr getPreviousSegment() const; void getSelectedSegments(segment_vec_t& segments) const; + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } + protected: void showContextMenu(S32 x, S32 y); void drawPreeditMarker(); @@ -319,6 +325,7 @@ private: BOOL mTakesFocus; BOOL mAllowEmbeddedItems; + bool mShowContextMenu; LLUUID mSourceID; @@ -329,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/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 9be33483d0..1b64ef3abe 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -56,7 +56,7 @@ LLUIColorTable::Params::Params() { } -void LLUIColorTable::insertFromParams(const Params& p) +void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table) { // this map will contain all color references after the following loop typedef std::map<std::string, std::string> string_string_map_t; @@ -69,14 +69,7 @@ void LLUIColorTable::insertFromParams(const Params& p) ColorEntryParams color_entry = *it; if(color_entry.color.value.isChosen()) { - if(mUserSetColors.find(color_entry.name)!=mUserSetColors.end()) - { - setColor(color_entry.name, color_entry.color.value); - } - else - { - setColor(color_entry.name, color_entry.color.value, mLoadedColors); - } + setColor(color_entry.name, color_entry.color.value, table); } else { @@ -220,16 +213,16 @@ bool LLUIColorTable::loadFromSettings() bool result = false; std::string default_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "colors.xml"); - result |= loadFromFilename(default_filename); + result |= loadFromFilename(default_filename, mLoadedColors); std::string current_filename = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, "colors.xml"); if(current_filename != default_filename) { - result |= loadFromFilename(current_filename); + result |= loadFromFilename(current_filename, mLoadedColors); } std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - loadFromFilename(user_filename); + loadFromFilename(user_filename, mUserSetColors); return result; } @@ -299,7 +292,7 @@ void LLUIColorTable::setColor(const std::string& name, const LLColor4& color, st } } -bool LLUIColorTable::loadFromFilename(const std::string& filename) +bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_map_t& table) { LLXMLNodePtr root; @@ -320,7 +313,7 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename) if(params.validateBlock()) { - insertFromParams(params); + insertFromParams(params, table); } else { @@ -330,3 +323,11 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename) return true; } + +void LLUIColorTable::insertFromParams(const Params& p) +{ + insertFromParams(p, mUserSetColors); +} + +// EOF + diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index c87695f456..d401e5e724 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -45,6 +45,10 @@ class LLUIColor; class LLUIColorTable : public LLSingleton<LLUIColorTable> { LOG_CLASS(LLUIColorTable); + + // consider using sorted vector, can be much faster + typedef std::map<std::string, LLUIColor> string_color_map_t; + public: struct ColorParams : LLInitParam::Choice<ColorParams> { @@ -91,10 +95,9 @@ public: void saveUserSettings() const; private: - bool loadFromFilename(const std::string& filename); + bool loadFromFilename(const std::string& filename, string_color_map_t& table); - // consider using sorted vector, can be much faster - typedef std::map<std::string, LLUIColor> string_color_map_t; + void insertFromParams(const Params& p, string_color_map_t& table); void clearTable(string_color_map_t& table); void setColor(const std::string& name, const LLColor4& color, string_color_map_t& table); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index f1b08c380b..63e627ceb5 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1720,6 +1720,7 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { LLView* childp = *child_it; + llassert(childp); if (childp->getName() == name) { return childp; @@ -1731,6 +1732,7 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { LLView* childp = *child_it; + llassert(childp); LLView* viewp = childp->findChildView(name, recurse); if ( viewp ) { |