diff options
Diffstat (limited to 'indra/llui')
223 files changed, 62366 insertions, 62066 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 0a82bed896..3feb989ed5 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llaccordionctrl.cpp * @brief Accordion panel implementation * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,7 +45,7 @@ static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; // LLAccordionCtrl =================================================================| -static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion"); +static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion"); LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) , mFitParent(params.fit_parent) @@ -57,13 +57,13 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) , mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString()) , mSkipScrollToChild(false) { - initNoTabsWidget(params.no_matched_tabs_text); + initNoTabsWidget(params.no_matched_tabs_text); - mSingleExpansion = params.single_expansion; - if (mFitParent && !mSingleExpansion) - { - LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL; - } + mSingleExpansion = params.single_expansion; + if (mFitParent && !mSingleExpansion) + { + LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL; + } } LLAccordionCtrl::LLAccordionCtrl() : LLPanel() @@ -72,102 +72,102 @@ LLAccordionCtrl::LLAccordionCtrl() : LLPanel() , mSelectedTab( NULL ) , mNoVisibleTabsHelpText(NULL) { - initNoTabsWidget(LLTextBox::Params()); + initNoTabsWidget(LLTextBox::Params()); - mSingleExpansion = false; - mFitParent = false; - buildFromFile( "accordion_parent.xml"); + mSingleExpansion = false; + mFitParent = false; + buildFromFile( "accordion_parent.xml"); } //--------------------------------------------------------------------------------- void LLAccordionCtrl::draw() { - if (mAutoScrolling) - { - // add acceleration to autoscroll - mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE); - } - else - { - // reset to minimum for next time - mAutoScrollRate = MIN_AUTO_SCROLL_RATE; - } - // clear this flag to be set on next call to autoScroll - mAutoScrolling = false; - - LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - - LLLocalClipRect clip(local_rect); - - LLPanel::draw(); + if (mAutoScrolling) + { + // add acceleration to autoscroll + mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE); + } + else + { + // reset to minimum for next time + mAutoScrollRate = MIN_AUTO_SCROLL_RATE; + } + // clear this flag to be set on next call to autoScroll + mAutoScrolling = false; + + LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + + LLLocalClipRect clip(local_rect); + + LLPanel::draw(); } //--------------------------------------------------------------------------------- BOOL LLAccordionCtrl::postBuild() { - static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); - - LLRect scroll_rect; - scroll_rect.setOriginAndSize( - getRect().getWidth() - scrollbar_size, - 1, - scrollbar_size, - getRect().getHeight() - 1); - - LLScrollbar::Params sbparams; - sbparams.name("scrollable vertical"); - sbparams.rect(scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(mInnerRect.getHeight()); - sbparams.doc_pos(0); - sbparams.page_size(mInnerRect.getHeight()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2)); - - mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams); - LLView::addChild(mScrollbar); - mScrollbar->setVisible(FALSE); - mScrollbar->setFollowsRight(); - mScrollbar->setFollowsTop(); - mScrollbar->setFollowsBottom(); - - //if it was created from xml... - std::vector<LLUICtrl*> accordion_tabs; - for (child_list_const_iter_t it = getChildList()->begin(); - getChildList()->end() != it; ++it) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it); - if (accordion_tab == NULL) - continue; - if (std::find(mAccordionTabs.begin(), mAccordionTabs.end(), accordion_tab) == mAccordionTabs.end()) - { - accordion_tabs.push_back(accordion_tab); - } - } - - for (std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin(); - it < accordion_tabs.rend(); ++it) - { - addCollapsibleCtrl(*it); - } - - arrange(); - - if (mSingleExpansion) - { - if (!mAccordionTabs[0]->getDisplayChildren()) - mAccordionTabs[0]->setDisplayChildren(true); - for (size_t i = 1; i < mAccordionTabs.size(); ++i) - { - if (mAccordionTabs[i]->getDisplayChildren()) - mAccordionTabs[i]->setDisplayChildren(false); - } - } - - updateNoTabsHelpTextVisibility(); - - return TRUE; + static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + LLScrollbar::Params sbparams; + sbparams.name("scrollable vertical"); + sbparams.rect(scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(mInnerRect.getHeight()); + sbparams.doc_pos(0); + sbparams.page_size(mInnerRect.getHeight()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2)); + + mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams); + LLView::addChild(mScrollbar); + mScrollbar->setVisible(FALSE); + mScrollbar->setFollowsRight(); + mScrollbar->setFollowsTop(); + mScrollbar->setFollowsBottom(); + + //if it was created from xml... + std::vector<LLUICtrl*> accordion_tabs; + for (child_list_const_iter_t it = getChildList()->begin(); + getChildList()->end() != it; ++it) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it); + if (accordion_tab == NULL) + continue; + if (std::find(mAccordionTabs.begin(), mAccordionTabs.end(), accordion_tab) == mAccordionTabs.end()) + { + accordion_tabs.push_back(accordion_tab); + } + } + + for (std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin(); + it < accordion_tabs.rend(); ++it) + { + addCollapsibleCtrl(*it); + } + + arrange(); + + if (mSingleExpansion) + { + if (!mAccordionTabs[0]->getDisplayChildren()) + mAccordionTabs[0]->setDisplayChildren(true); + for (size_t i = 1; i < mAccordionTabs.size(); ++i) + { + if (mAccordionTabs[i]->getDisplayChildren()) + mAccordionTabs[i]->setDisplayChildren(false); + } + } + + updateNoTabsHelpTextVisibility(); + + return TRUE; } @@ -181,478 +181,478 @@ LLAccordionCtrl::~LLAccordionCtrl() void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { - // adjust our rectangle - LLRect rcLocal = getRect(); - rcLocal.mRight = rcLocal.mLeft + width; - rcLocal.mTop = rcLocal.mBottom + height; + // adjust our rectangle + LLRect rcLocal = getRect(); + rcLocal.mRight = rcLocal.mLeft + width; + rcLocal.mTop = rcLocal.mBottom + height; - // get textbox a chance to reshape its content - mNoVisibleTabsHelpText->reshape(width, height, called_from_parent); + // get textbox a chance to reshape its content + mNoVisibleTabsHelpText->reshape(width, height, called_from_parent); - setRect(rcLocal); + setRect(rcLocal); - // assume that help text is always fit accordion. - // necessary text paddings can be set via h_pad and v_pad - mNoVisibleTabsHelpText->setRect(getLocalRect()); + // assume that help text is always fit accordion. + // necessary text paddings can be set via h_pad and v_pad + mNoVisibleTabsHelpText->setRect(getLocalRect()); - arrange(); + arrange(); } //--------------------------------------------------------------------------------- BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) { - return LLPanel::handleRightMouseDown(x, y, mask); + return LLPanel::handleRightMouseDown(x, y, mask); } //--------------------------------------------------------------------------------- void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta) { - for (size_t i = panel_num; i < mAccordionTabs.size(); ++i) - { - ctrlShiftVertical(mAccordionTabs[i],delta); - } + for (size_t i = panel_num; i < mAccordionTabs.size(); ++i) + { + ctrlShiftVertical(mAccordionTabs[i],delta); + } } //--------------------------------------------------------------------------------- -void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num) +void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num) { - if (mSingleExpansion) - { - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - if (i == panel_num) - continue; - if (mAccordionTabs[i]->getDisplayChildren()) - mAccordionTabs[i]->setDisplayChildren(false); - } + if (mSingleExpansion) + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + if (i == panel_num) + continue; + if (mAccordionTabs[i]->getDisplayChildren()) + mAccordionTabs[i]->setDisplayChildren(false); + } - } - arrange(); + } + arrange(); } void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height) { - calcRecuiredHeight(); - if (getRecuiredHeight() > height) - showScrollbar(width, height); - else - hideScrollbar(width, height); + calcRecuiredHeight(); + if (getRecuiredHeight() > height) + showScrollbar(width, height); + else + hideScrollbar(width, height); } void LLAccordionCtrl::showScrollbar(S32 width, S32 height) { - bool was_visible = mScrollbar->getVisible(); + bool was_visible = mScrollbar->getVisible(); + + mScrollbar->setVisible(TRUE); - mScrollbar->setVisible(TRUE); - - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - ctrlSetLeftTopAndSize(mScrollbar - , width - scrollbar_size - PARENT_BORDER_MARGIN / 2 - , height - PARENT_BORDER_MARGIN - , scrollbar_size - , height - PARENT_BORDER_MARGIN * 2); - - mScrollbar->setPageSize(height); - mScrollbar->setDocParams(mInnerRect.getHeight(), mScrollbar->getDocPos()); + ctrlSetLeftTopAndSize(mScrollbar + , width - scrollbar_size - PARENT_BORDER_MARGIN / 2 + , height - PARENT_BORDER_MARGIN + , scrollbar_size + , height - PARENT_BORDER_MARGIN * 2); - if (was_visible) - { - S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); - mScrollbar->setDocPos(scroll_pos); - } + mScrollbar->setPageSize(height); + mScrollbar->setDocParams(mInnerRect.getHeight(), mScrollbar->getDocPos()); + + if (was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); + mScrollbar->setDocPos(scroll_pos); + } } void LLAccordionCtrl::hideScrollbar(S32 width, S32 height) { - if (mScrollbar->getVisible() == FALSE) - return; - mScrollbar->setVisible(FALSE); + if (mScrollbar->getVisible() == FALSE) + return; + mScrollbar->setVisible(FALSE); - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - S32 panel_width = width - 2*BORDER_MARGIN; + S32 panel_width = width - 2*BORDER_MARGIN; - // Reshape all accordions and shift all draggers - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLRect panel_rect = mAccordionTabs[i]->getRect(); - ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_rect.mTop, panel_width, panel_rect.getHeight()); - } + // Reshape all accordions and shift all draggers + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLRect panel_rect = mAccordionTabs[i]->getRect(); + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_rect.mTop, panel_width, panel_rect.getHeight()); + } - mScrollbar->setDocPos(0); + mScrollbar->setDocPos(0); - if (!mAccordionTabs.empty()) - { - S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel - S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop; - shiftAccordionTabs(0, diff); - } + if (!mAccordionTabs.empty()) + { + S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel + S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop; + shiftAccordionTabs(0, diff); + } } //--------------------------------------------------------------------------------- S32 LLAccordionCtrl::calcRecuiredHeight() { - S32 rec_height = 0; - - std::vector<LLAccordionCtrlTab*>::iterator panel; - for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*panel); - if(accordion_tab && accordion_tab->getVisible()) - { - rec_height += accordion_tab->getRect().getHeight(); - } - } + S32 rec_height = 0; - mInnerRect.setLeftTopAndSize(0, rec_height + BORDER_MARGIN * 2, getRect().getWidth(), rec_height + BORDER_MARGIN); + std::vector<LLAccordionCtrlTab*>::iterator panel; + for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*panel); + if(accordion_tab && accordion_tab->getVisible()) + { + rec_height += accordion_tab->getRect().getHeight(); + } + } - return mInnerRect.getHeight(); + mInnerRect.setLeftTopAndSize(0, rec_height + BORDER_MARGIN * 2, getRect().getWidth(), rec_height + BORDER_MARGIN); + + return mInnerRect.getHeight(); } //--------------------------------------------------------------------------------- void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) { - if (!panel) - return; - LLRect panel_rect = panel->getRect(); - panel_rect.setLeftTopAndSize( left, top, width, height); - panel->reshape( width, height, 1); - panel->setRect(panel_rect); + if (!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize( left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); } void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta) { - if (!panel) - return; - panel->translate(0,delta); + if (!panel) + return; + panel->translate(0,delta); } //--------------------------------------------------------------------------------- void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); - if (!accordion_tab) - return; - if (std::find(beginChild(), endChild(), accordion_tab) == endChild()) - addChild(accordion_tab); - mAccordionTabs.push_back(accordion_tab); + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); + if (!accordion_tab) + return; + if (std::find(beginChild(), endChild(), accordion_tab) == endChild()) + addChild(accordion_tab); + mAccordionTabs.push_back(accordion_tab); - accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) ); - arrange(); + accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) ); + arrange(); } void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view) { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); - if(!accordion_tab) - return; + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); + if(!accordion_tab) + return; - if(std::find(beginChild(), endChild(), accordion_tab) != endChild()) - removeChild(accordion_tab); + if(std::find(beginChild(), endChild(), accordion_tab) != endChild()) + removeChild(accordion_tab); - for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin(); - iter != mAccordionTabs.end(); ++iter) - { - if (accordion_tab == (*iter)) - { - mAccordionTabs.erase(iter); - break; - } - } + for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin(); + iter != mAccordionTabs.end(); ++iter) + { + if (accordion_tab == (*iter)) + { + mAccordionTabs.erase(iter); + break; + } + } - // if removed is selected - reset selection - if (mSelectedTab == view) - { - mSelectedTab = NULL; - } + // if removed is selected - reset selection + if (mSelectedTab == view) + { + mSelectedTab = NULL; + } } void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params) { - LLTextBox::Params tp = tb_params; - tp.rect(getLocalRect()); - mNoMatchedTabsOrigString = tp.initial_value().asString(); - mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this); + LLTextBox::Params tp = tb_params; + tp.rect(getLocalRect()); + mNoMatchedTabsOrigString = tp.initial_value().asString(); + mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this); } void LLAccordionCtrl::updateNoTabsHelpTextVisibility() { - bool visible_exists = false; - std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin(); - const std::vector<LLAccordionCtrlTab*>::const_iterator it_end = mAccordionTabs.end(); - while (it < it_end) - { - if ((*(it++))->getVisible()) - { - visible_exists = true; - break; - } - } + bool visible_exists = false; + std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin(); + const std::vector<LLAccordionCtrlTab*>::const_iterator it_end = mAccordionTabs.end(); + while (it < it_end) + { + if ((*(it++))->getVisible()) + { + visible_exists = true; + break; + } + } - mNoVisibleTabsHelpText->setVisible(visible_exists ? FALSE : TRUE); + mNoVisibleTabsHelpText->setVisible(visible_exists ? FALSE : TRUE); } void LLAccordionCtrl::arrangeSingle() { - S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; - S32 panel_height; - - S32 collapsed_height = 0; - - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - - if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs - continue; - if (!accordion_tab->isExpanded() ) - { - collapsed_height+=mAccordionTabs[i]->getRect().getHeight(); - } - } - - S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height; - - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - - if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs - continue; - if (!accordion_tab->isExpanded() ) - { - panel_height = accordion_tab->getRect().getHeight(); - } - else - { - if (mFitParent) - { - panel_height = expanded_height; - } - else - { - if (accordion_tab->getAccordionView()) - { - panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + - accordion_tab->getHeaderHeight() + BORDER_MARGIN * 2; - } - else - { - panel_height = accordion_tab->getRect().getHeight(); - } - } - } - - // make sure at least header is shown - panel_height = llmax(panel_height, accordion_tab->getHeaderHeight()); - - ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); - panel_top -= mAccordionTabs[i]->getRect().getHeight(); - } - - show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); - updateLayout(getRect().getWidth(), getRect().getHeight()); + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; + S32 panel_height; + + S32 collapsed_height = 0; + + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs + continue; + if (!accordion_tab->isExpanded() ) + { + collapsed_height+=mAccordionTabs[i]->getRect().getHeight(); + } + } + + S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height; + + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs + continue; + if (!accordion_tab->isExpanded() ) + { + panel_height = accordion_tab->getRect().getHeight(); + } + else + { + if (mFitParent) + { + panel_height = expanded_height; + } + else + { + if (accordion_tab->getAccordionView()) + { + panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + + accordion_tab->getHeaderHeight() + BORDER_MARGIN * 2; + } + else + { + panel_height = accordion_tab->getRect().getHeight(); + } + } + } + + // make sure at least header is shown + panel_height = llmax(panel_height, accordion_tab->getHeaderHeight()); + + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); + panel_top -= mAccordionTabs[i]->getRect().getHeight(); + } + + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); } void LLAccordionCtrl::arrangeMultiple() { - S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; - - //Calculate params - for (size_t i = 0; i < mAccordionTabs.size(); i++ ) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - - if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs - continue; - - if (!accordion_tab->isExpanded() ) - { - ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight()); - panel_top -= mAccordionTabs[i]->getRect().getHeight(); - } - else - { - S32 panel_height = accordion_tab->getRect().getHeight(); - - if (mFitParent) - { - // All expanded tabs will have equal height - panel_height = calcExpandedTabHeight(i, panel_top); - ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height); - - // Try to make accordion tab fit accordion view height. - // Accordion View should implement getRequiredRect() and provide valid height - S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight(); - optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN; - if (optimal_height < panel_height) - { - panel_height = optimal_height; - } - - // minimum tab height is equal to header height - if (mAccordionTabs[i]->getHeaderHeight() > panel_height) - { - panel_height = mAccordionTabs[i]->getHeaderHeight(); - } - } - - ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); - panel_top -= panel_height; - - } - } - - show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); - - updateLayout(getRect().getWidth(), getRect().getHeight()); + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; + + //Calculate params + for (size_t i = 0; i < mAccordionTabs.size(); i++ ) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs + continue; + + if (!accordion_tab->isExpanded() ) + { + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight()); + panel_top -= mAccordionTabs[i]->getRect().getHeight(); + } + else + { + S32 panel_height = accordion_tab->getRect().getHeight(); + + if (mFitParent) + { + // All expanded tabs will have equal height + panel_height = calcExpandedTabHeight(i, panel_top); + ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height); + + // Try to make accordion tab fit accordion view height. + // Accordion View should implement getRequiredRect() and provide valid height + S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight(); + optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN; + if (optimal_height < panel_height) + { + panel_height = optimal_height; + } + + // minimum tab height is equal to header height + if (mAccordionTabs[i]->getHeaderHeight() > panel_height) + { + panel_height = mAccordionTabs[i]->getHeaderHeight(); + } + } + + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); + panel_top -= panel_height; + + } + } + + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); + + updateLayout(getRect().getWidth(), getRect().getHeight()); } void LLAccordionCtrl::arrange() { - updateNoTabsHelpTextVisibility(); - - if (mAccordionTabs.empty()) - { - // Nothing to arrange - return; - } - - if (mAccordionTabs.size() == 1) - { - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; - - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]); - - LLRect panel_rect = accordion_tab->getRect(); - - S32 panel_height = getRect().getHeight() - BORDER_MARGIN * 2; - if (accordion_tab->getFitParent()) - panel_height = accordion_tab->getRect().getHeight(); - - ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_height); - - show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); - return; - } - - if (mSingleExpansion) - arrangeSingle(); - else - arrangeMultiple(); + updateNoTabsHelpTextVisibility(); + + if (mAccordionTabs.empty()) + { + // Nothing to arrange + return; + } + + if (mAccordionTabs.size() == 1) + { + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; + + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]); + + LLRect panel_rect = accordion_tab->getRect(); + + S32 panel_height = getRect().getHeight() - BORDER_MARGIN * 2; + if (accordion_tab->getFitParent()) + panel_height = accordion_tab->getRect().getHeight(); + + ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_height); + + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); + return; + } + + if (mSingleExpansion) + arrangeSingle(); + else + arrangeMultiple(); } //--------------------------------------------------------------------------------- BOOL LLAccordionCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if (LLPanel::handleScrollWheel(x, y, clicks)) - return TRUE; - if (mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) - return TRUE; - return FALSE; + if (LLPanel::handleScrollWheel(x, y, clicks)) + return TRUE; + if (mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) + return TRUE; + return FALSE; } BOOL LLAccordionCtrl::handleKeyHere(KEY key, MASK mask) { - if (mScrollbar->getVisible() && mScrollbar->handleKeyHere(key, mask)) - return TRUE; - return LLPanel::handleKeyHere(key, mask); + if (mScrollbar->getVisible() && mScrollbar->handleKeyHere(key, mask)) + return TRUE; + return LLPanel::handleKeyHere(key, mask); } BOOL LLAccordionCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - // Scroll folder view if needed. Never accepts a drag or drop. - *accept = ACCEPT_NO; - BOOL handled = autoScroll(x, y); + // Scroll folder view if needed. Never accepts a drag or drop. + *accept = ACCEPT_NO; + BOOL handled = autoScroll(x, y); - if (!handled) - { - handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg) != NULL; - } - return TRUE; + if (!handled) + { + handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg) != NULL; + } + return TRUE; } BOOL LLAccordionCtrl::autoScroll(S32 x, S32 y) { - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - bool scrolling = false; - if (mScrollbar->getVisible()) - { - LLRect rect_local(0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0); - LLRect screen_local_extents; + bool scrolling = false; + if (mScrollbar->getVisible()) + { + LLRect rect_local(0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0); + LLRect screen_local_extents; - // clip rect against root view - screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); - rect_local.intersectWith(screen_local_extents); + // clip rect against root view + screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); + rect_local.intersectWith(screen_local_extents); - // autoscroll region should take up no more than one third of visible scroller area - S32 auto_scroll_region_height = llmin(rect_local.getHeight() / 3, 10); - S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); + // autoscroll region should take up no more than one third of visible scroller area + S32 auto_scroll_region_height = llmin(rect_local.getHeight() / 3, 10); + S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); - LLRect bottom_scroll_rect = screen_local_extents; - bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height; - if (bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax())) - { - mScrollbar->setDocPos(mScrollbar->getDocPos() + auto_scroll_speed); - mAutoScrolling = true; - scrolling = true; - } + LLRect bottom_scroll_rect = screen_local_extents; + bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height; + if (bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax())) + { + mScrollbar->setDocPos(mScrollbar->getDocPos() + auto_scroll_speed); + mAutoScrolling = true; + scrolling = true; + } - LLRect top_scroll_rect = screen_local_extents; - top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height; - if (top_scroll_rect.pointInRect(x, y) && (mScrollbar->getDocPos() > 0)) - { - mScrollbar->setDocPos(mScrollbar->getDocPos() - auto_scroll_speed); - mAutoScrolling = true; - scrolling = true; - } - } + LLRect top_scroll_rect = screen_local_extents; + top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height; + if (top_scroll_rect.pointInRect(x, y) && (mScrollbar->getDocPos() > 0)) + { + mScrollbar->setDocPos(mScrollbar->getDocPos() - auto_scroll_speed); + mAutoScrolling = true; + scrolling = true; + } + } - return scrolling ? TRUE : FALSE; + return scrolling ? TRUE : FALSE; } void LLAccordionCtrl::updateLayout(S32 width, S32 height) { - S32 panel_top = height - BORDER_MARGIN ; - if (mScrollbar->getVisible()) - panel_top += mScrollbar->getDocPos(); + S32 panel_top = height - BORDER_MARGIN ; + if (mScrollbar->getVisible()) + panel_top += mScrollbar->getDocPos(); - S32 panel_width = width - BORDER_MARGIN * 2; + S32 panel_width = width - BORDER_MARGIN * 2; - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - if (mScrollbar->getVisible()) - panel_width -= scrollbar_size; + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + if (mScrollbar->getVisible()) + panel_width -= scrollbar_size; - // set sizes for first panels and dragbars - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - if (!mAccordionTabs[i]->getVisible()) - continue; - LLRect panel_rect = mAccordionTabs[i]->getRect(); - ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); - panel_top -= panel_rect.getHeight(); - } + // set sizes for first panels and dragbars + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + if (!mAccordionTabs[i]->getVisible()) + continue; + LLRect panel_rect = mAccordionTabs[i]->getRect(); + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); + panel_top -= panel_rect.getHeight(); + } } void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) { - updateLayout(getRect().getWidth(), getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); } // virtual @@ -676,7 +676,7 @@ void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl) S32 scroll_pos = llclamp(mScrollbar->getDocPos(), bottom, // min vertical scroll - top); // max vertical scroll + top); // max vertical scroll mScrollbar->setDocPos(scroll_pos); } @@ -687,252 +687,269 @@ void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl) void LLAccordionCtrl::onOpen(const LLSD& key) { - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView()); - if (panel != NULL) - { - panel->onOpen(key); - } - } -} - -S32 LLAccordionCtrl::notifyParent(const LLSD& info) -{ - if (info.has("action")) - { - std::string str_action = info["action"]; - if (str_action == "size_changes") - { - // - arrange(); - return 1; - } - if (str_action == "select_next") - { - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - if (accordion_tab->hasFocus()) - { - while (++i < mAccordionTabs.size()) - { - if (mAccordionTabs[i]->getVisible()) - break; - } - if (i < mAccordionTabs.size()) - { - accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - accordion_tab->notify(LLSD().with("action","select_first")); - return 1; - } - break; - } - } - return 0; - } - if (str_action == "select_prev") - { - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - if (accordion_tab->hasFocus() && i > 0) - { - bool prev_visible_tab_found = false; - while (i > 0) - { - if (mAccordionTabs[--i]->getVisible()) - { - prev_visible_tab_found = true; - break; - } - } - - if (prev_visible_tab_found) - { - accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); - accordion_tab->notify(LLSD().with("action","select_last")); - return 1; - } - break; - } - } - return 0; - } - if (str_action == "select_current") - { - for (size_t i = 0; i < mAccordionTabs.size(); ++i) - { - // Set selection to the currently focused tab. - if (mAccordionTabs[i]->hasFocus()) - { - if (mAccordionTabs[i] != mSelectedTab) - { - if (mSelectedTab) - { - mSelectedTab->setSelected(false); - } - mSelectedTab = mAccordionTabs[i]; - mSelectedTab->setSelected(true); - } - - return 1; - } - } - return 0; - } - if (str_action == "deselect_current") - { - // Reset selection to the currently selected tab. - if (mSelectedTab) - { - mSelectedTab->setSelected(false); - mSelectedTab = NULL; - return 1; - } - return 0; - } - } - else if (info.has("scrollToShowRect")) - { - LLRect screen_rc, local_rc; - screen_rc.setValue(info["scrollToShowRect"]); - screenRectToLocal(screen_rc, &local_rc); - - // Translate to parent coordinatess to check if we are in visible rectangle - local_rc.translate(getRect().mLeft, getRect().mBottom); - - if (!getRect().contains (local_rc)) - { - // Back to local coords and calculate position for scroller - S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom; - S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop; - - S32 scroll_pos = llclamp(mScrollbar->getDocPos(), - bottom, // min vertical scroll - top); // max vertical scroll - - mScrollbar->setDocPos(scroll_pos); - } - return 1; - } - else if (info.has("child_visibility_change")) - { - BOOL new_visibility = info["child_visibility_change"]; - if (new_visibility) - { - // there is at least one visible tab - mNoVisibleTabsHelpText->setVisible(FALSE); - } - else - { - // it could be the latest visible tab, check all of them - updateNoTabsHelpTextVisibility(); - } - } - return LLPanel::notifyParent(info); + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView()); + if (panel != NULL) + { + panel->onOpen(key); + } + } +} + +S32 LLAccordionCtrl::notifyParent(const LLSD& info) +{ + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "size_changes") + { + // + arrange(); + return 1; + } + if (str_action == "select_next") + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + if (accordion_tab->hasFocus()) + { + while (++i < mAccordionTabs.size()) + { + if (mAccordionTabs[i]->getVisible()) + break; + } + if (i < mAccordionTabs.size()) + { + accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + accordion_tab->notify(LLSD().with("action","select_first")); + return 1; + } + break; + } + } + return 0; + } + if (str_action == "select_prev") + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + if (accordion_tab->hasFocus() && i > 0) + { + bool prev_visible_tab_found = false; + while (i > 0) + { + if (mAccordionTabs[--i]->getVisible()) + { + prev_visible_tab_found = true; + break; + } + } + + if (prev_visible_tab_found) + { + accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]); + accordion_tab->notify(LLSD().with("action","select_last")); + return 1; + } + break; + } + } + return 0; + } + if (str_action == "select_current") + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + // Set selection to the currently focused tab. + if (mAccordionTabs[i]->hasFocus()) + { + if (mAccordionTabs[i] != mSelectedTab) + { + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + } + mSelectedTab = mAccordionTabs[i]; + mSelectedTab->setSelected(true); + } + + return 1; + } + } + return 0; + } + if (str_action == "deselect_current") + { + // Reset selection to the currently selected tab. + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + mSelectedTab = NULL; + return 1; + } + return 0; + } + } + else if (info.has("scrollToShowRect")) + { + LLRect screen_rc, local_rc; + screen_rc.setValue(info["scrollToShowRect"]); + screenRectToLocal(screen_rc, &local_rc); + + // Translate to parent coordinatess to check if we are in visible rectangle + local_rc.translate(getRect().mLeft, getRect().mBottom); + + if (!getRect().contains (local_rc)) + { + // Back to local coords and calculate position for scroller + S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom; + S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop; + + S32 scroll_pos = llclamp(mScrollbar->getDocPos(), + bottom, // min vertical scroll + top); // max vertical scroll + + mScrollbar->setDocPos(scroll_pos); + } + return 1; + } + else if (info.has("child_visibility_change")) + { + BOOL new_visibility = info["child_visibility_change"]; + if (new_visibility) + { + // there is at least one visible tab + mNoVisibleTabsHelpText->setVisible(FALSE); + } + else + { + // it could be the latest visible tab, check all of them + updateNoTabsHelpTextVisibility(); + } + } + return LLPanel::notifyParent(info); } void LLAccordionCtrl::reset() { - if (mScrollbar) - mScrollbar->setDocPos(0); + if (mScrollbar) + mScrollbar->setDocPos(0); } void LLAccordionCtrl::expandDefaultTab() { - if (!mAccordionTabs.empty()) - { - LLAccordionCtrlTab* tab = mAccordionTabs.front(); + if (!mAccordionTabs.empty()) + { + LLAccordionCtrlTab* tab = mAccordionTabs.front(); - if (!tab->getDisplayChildren()) - { - tab->setDisplayChildren(true); - } + if (!tab->getDisplayChildren()) + { + tab->setDisplayChildren(true); + } - for (size_t i = 1; i < mAccordionTabs.size(); ++i) - { - tab = mAccordionTabs[i]; + for (size_t i = 1; i < mAccordionTabs.size(); ++i) + { + tab = mAccordionTabs[i]; - if (tab->getDisplayChildren()) - { - tab->setDisplayChildren(false); - } - } + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } - arrange(); - } + arrange(); + } } void LLAccordionCtrl::sort() { - if (!mTabComparator) - { - LL_WARNS() << "No comparator specified for sorting accordion tabs." << LL_ENDL; - return; - } + if (!mTabComparator) + { + LL_WARNS() << "No comparator specified for sorting accordion tabs." << LL_ENDL; + return; + } - std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator)); - arrange(); + std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator)); + arrange(); } void LLAccordionCtrl::setFilterSubString(const std::string& filter_string) { - LLStringUtil::format_map_t args; - args["[SEARCH_TERM]"] = LLURI::escape(filter_string); - std::string text = filter_string.empty() ? mNoVisibleTabsOrigString : mNoMatchedTabsOrigString; - LLStringUtil::format(text, args); + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = filter_string.empty() ? mNoVisibleTabsOrigString : mNoMatchedTabsOrigString; + LLStringUtil::format(text, args); - mNoVisibleTabsHelpText->setValue(text); + mNoVisibleTabsHelpText->setValue(text); } const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const { - typedef std::vector<LLAccordionCtrlTab*>::const_iterator tabs_const_iterator; + typedef std::vector<LLAccordionCtrlTab*>::const_iterator tabs_const_iterator; - const LLAccordionCtrlTab* result = 0; + const LLAccordionCtrlTab* result = 0; - for (tabs_const_iterator i = mAccordionTabs.begin(); i != mAccordionTabs.end(); ++i) - { - if ((*i)->isExpanded()) - { - result = *i; - break; - } - } + for (tabs_const_iterator i = mAccordionTabs.begin(); i != mAccordionTabs.end(); ++i) + { + if ((*i)->isExpanded()) + { + result = *i; + break; + } + } - return result; + return result; } S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */) { - if (tab_index < 0) - { - return available_height; - } - - S32 collapsed_tabs_height = 0; - S32 num_expanded = 0; - - for (size_t n = tab_index; n < mAccordionTabs.size(); ++n) - { - if (!mAccordionTabs[n]->isExpanded()) - { - collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight(); - } - else - { - ++num_expanded; - } - } - - if (0 == num_expanded) - { - return available_height; - } - - S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN - expanded_tab_height /= num_expanded; - return expanded_tab_height; + if (tab_index < 0) + { + return available_height; + } + + S32 collapsed_tabs_height = 0; + S32 num_expanded = 0; + + for (size_t n = tab_index; n < mAccordionTabs.size(); ++n) + { + if (!mAccordionTabs[n]->isExpanded()) + { + collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight(); + } + else + { + ++num_expanded; + } + } + + if (0 == num_expanded) + { + return available_height; + } + + S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN + expanded_tab_height /= num_expanded; + return expanded_tab_height; +} + +void LLAccordionCtrl::collapseAllTabs() +{ + if (mAccordionTabs.size() > 0) + { + for (size_t i = 0; i < mAccordionTabs.size(); ++i) + { + LLAccordionCtrlTab *tab = mAccordionTabs[i]; + + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } + arrange(); + } } diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 6a1989afba..2741db24e8 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file LLAccordionCtrl.h * @brief Accordion Panel implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,157 +41,159 @@ class LLAccordionCtrl: public LLPanel { private: - std::vector<LLAccordionCtrlTab*> mAccordionTabs; + std::vector<LLAccordionCtrlTab*> mAccordionTabs; - void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height); - void ctrlShiftVertical(LLView* panel,S32 delta); - - void onCollapseCtrlCloseOpen(S16 panel_num); - void shiftAccordionTabs(S16 panel_num, S32 delta); + void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height); + void ctrlShiftVertical(LLView* panel,S32 delta); + + void onCollapseCtrlCloseOpen(S16 panel_num); + void shiftAccordionTabs(S16 panel_num, S32 delta); public: - /** - * Abstract comparator for accordion tabs. - */ - class LLTabComparator - { - public: - LLTabComparator() {}; - virtual ~LLTabComparator() {}; - - /** Returns true if tab1 < tab2, false otherwise */ - virtual bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const = 0; - }; - - struct Params - : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<bool> single_expansion, - fit_parent; /* Accordion will fit its parent size, controls that are placed into - accordion tabs are responsible for scrolling their content. - *NOTE fit_parent works best when combined with single_expansion. - Accordion view should implement getRequiredRect() and provide valid height*/ - Optional<LLTextBox::Params> no_matched_tabs_text; - Optional<LLTextBox::Params> no_visible_tabs_text; - - Params() - : single_expansion("single_expansion",false) - , fit_parent("fit_parent", false) - , no_matched_tabs_text("no_matched_tabs_text") - , no_visible_tabs_text("no_visible_tabs_text") - {}; - }; - - LLAccordionCtrl(const Params& params); + /** + * Abstract comparator for accordion tabs. + */ + class LLTabComparator + { + public: + LLTabComparator() {}; + virtual ~LLTabComparator() {}; + + /** Returns true if tab1 < tab2, false otherwise */ + virtual bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const = 0; + }; + + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<bool> single_expansion, + fit_parent; /* Accordion will fit its parent size, controls that are placed into + accordion tabs are responsible for scrolling their content. + *NOTE fit_parent works best when combined with single_expansion. + Accordion view should implement getRequiredRect() and provide valid height*/ + Optional<LLTextBox::Params> no_matched_tabs_text; + Optional<LLTextBox::Params> no_visible_tabs_text; + + Params() + : single_expansion("single_expansion",false) + , fit_parent("fit_parent", false) + , no_matched_tabs_text("no_matched_tabs_text") + , no_visible_tabs_text("no_visible_tabs_text") + {}; + }; + + LLAccordionCtrl(const Params& params); LLAccordionCtrl(); virtual ~LLAccordionCtrl(); - virtual BOOL postBuild(); - - virtual BOOL handleRightMouseDown ( S32 x, S32 y, MASK mask); - virtual BOOL handleScrollWheel ( S32 x, S32 y, S32 clicks ); - virtual BOOL handleKeyHere (KEY key, MASK mask); - virtual BOOL handleDragAndDrop (S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - // + virtual BOOL postBuild(); + + virtual BOOL handleRightMouseDown ( S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel ( S32 x, S32 y, S32 clicks ); + virtual BOOL handleKeyHere (KEY key, MASK mask); + virtual BOOL handleDragAndDrop (S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + // + + // Call reshape after changing splitter's size + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + void addCollapsibleCtrl(LLView* view); + void removeCollapsibleCtrl(LLView* view); + void arrange(); - // Call reshape after changing splitter's size - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void addCollapsibleCtrl(LLView* view); - void removeCollapsibleCtrl(LLView* view); - void arrange(); + void draw(); + void onScrollPosChangeCallback(S32, LLScrollbar*); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); - void draw(); - - void onScrollPosChangeCallback(S32, LLScrollbar*); - virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); + void onOpen (const LLSD& key); + S32 notifyParent(const LLSD& info); - void onOpen (const LLSD& key); - S32 notifyParent(const LLSD& info); + void reset (); + void expandDefaultTab(); - void reset (); - void expandDefaultTab(); + void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } + void sort(); - void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } - void sort(); + void collapseAllTabs(); - /** - * Sets filter substring as a search_term for help text when there are no any visible tabs. - */ - void setFilterSubString(const std::string& filter_string); + /** + * Sets filter substring as a search_term for help text when there are no any visible tabs. + */ + void setFilterSubString(const std::string& filter_string); - /** - * This method returns the first expanded accordion tab. - * It is expected to be called for accordion which doesn't allow multiple - * tabs to be expanded. Use with care. - */ - const LLAccordionCtrlTab* getExpandedTab() const; + /** + * This method returns the first expanded accordion tab. + * It is expected to be called for accordion which doesn't allow multiple + * tabs to be expanded. Use with care. + */ + const LLAccordionCtrlTab* getExpandedTab() const; - LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } + LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } - bool getFitParent() const {return mFitParent;} + bool getFitParent() const {return mFitParent;} - void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; } + void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; } private: - void initNoTabsWidget(const LLTextBox::Params& tb_params); - void updateNoTabsHelpTextVisibility(); + void initNoTabsWidget(const LLTextBox::Params& tb_params); + void updateNoTabsHelpTextVisibility(); - void arrangeSingle(); - void arrangeMultiple(); + void arrangeSingle(); + void arrangeMultiple(); - // Calc Splitter's height that is necessary to display all child content - S32 calcRecuiredHeight(); - S32 getRecuiredHeight() const { return mInnerRect.getHeight(); } - S32 calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0); + // Calc Splitter's height that is necessary to display all child content + S32 calcRecuiredHeight(); + S32 getRecuiredHeight() const { return mInnerRect.getHeight(); } + S32 calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0); - void updateLayout (S32 width, S32 height); + void updateLayout (S32 width, S32 height); - void show_hide_scrollbar (S32 width, S32 height); + void show_hide_scrollbar (S32 width, S32 height); - void showScrollbar (S32 width, S32 height); - void hideScrollbar (S32 width, S32 height); + void showScrollbar (S32 width, S32 height); + void hideScrollbar (S32 width, S32 height); - BOOL autoScroll (S32 x, S32 y); + BOOL autoScroll (S32 x, S32 y); - /** - * An adaptor for LLTabComparator - */ - struct LLComparatorAdaptor - { - LLComparatorAdaptor(const LLTabComparator& comparator) : mComparator(comparator) {}; + /** + * An adaptor for LLTabComparator + */ + struct LLComparatorAdaptor + { + LLComparatorAdaptor(const LLTabComparator& comparator) : mComparator(comparator) {}; - bool operator()(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) - { - return mComparator.compare(tab1, tab2); - } + bool operator()(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) + { + return mComparator.compare(tab1, tab2); + } - const LLTabComparator& mComparator; - }; + const LLTabComparator& mComparator; + }; private: - LLRect mInnerRect; - LLScrollbar* mScrollbar; - bool mSingleExpansion; - bool mFitParent; - bool mAutoScrolling; - F32 mAutoScrollRate; - LLTextBox* mNoVisibleTabsHelpText; + LLRect mInnerRect; + LLScrollbar* mScrollbar; + bool mSingleExpansion; + bool mFitParent; + bool mAutoScrolling; + F32 mAutoScrollRate; + LLTextBox* mNoVisibleTabsHelpText; - bool mSkipScrollToChild; + bool mSkipScrollToChild; - std::string mNoMatchedTabsOrigString; - std::string mNoVisibleTabsOrigString; + std::string mNoMatchedTabsOrigString; + std::string mNoVisibleTabsOrigString; - LLAccordionCtrlTab* mSelectedTab; - const LLTabComparator* mTabComparator; + LLAccordionCtrlTab* mSelectedTab; + const LLTabComparator* mTabComparator; }; diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 20da568746..52893e530f 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -1,25 +1,25 @@ -/** +/** * @file LLAccordionCtrlTab.cpp * @brief Collapsible control implementation * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,65 +51,65 @@ static LLDefaultChildRegistry::Register<LLAccordionCtrlTab> t1("accordion_tab"); class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl { public: - friend class LLUICtrlFactory; + friend class LLUICtrlFactory; - struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params> - { - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params> + { + Params(); + }; + + LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p); - LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p); - - virtual ~LLAccordionCtrlTabHeader(); + virtual ~LLAccordionCtrlTabHeader(); - virtual void draw(); + virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual BOOL postBuild(); + virtual BOOL postBuild(); - std::string getTitle(); - void setTitle(const std::string& title, const std::string& hl); + std::string getTitle(); + void setTitle(const std::string& title, const std::string& hl); - void setTitleFontStyle(std::string style); + void setTitleFontStyle(std::string style); - void setTitleColor(LLUIColor); + void setTitleColor(LLUIColor); - void setSelected(bool is_selected) { mIsSelected = is_selected; } + void setSelected(bool is_selected) { mIsSelected = is_selected; } - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); private: - LLTextBox* mHeaderTextbox; + LLTextBox* mHeaderTextbox; - // Overlay images (arrows) - LLPointer<LLUIImage> mImageCollapsed; - LLPointer<LLUIImage> mImageExpanded; - LLPointer<LLUIImage> mImageCollapsedPressed; - LLPointer<LLUIImage> mImageExpandedPressed; + // Overlay images (arrows) + LLPointer<LLUIImage> mImageCollapsed; + LLPointer<LLUIImage> mImageExpanded; + LLPointer<LLUIImage> mImageCollapsedPressed; + LLPointer<LLUIImage> mImageExpandedPressed; - // Background images - LLPointer<LLUIImage> mImageHeader; - LLPointer<LLUIImage> mImageHeaderOver; - LLPointer<LLUIImage> mImageHeaderPressed; - LLPointer<LLUIImage> mImageHeaderFocused; + // Background images + LLPointer<LLUIImage> mImageHeader; + LLPointer<LLUIImage> mImageHeaderOver; + LLPointer<LLUIImage> mImageHeaderPressed; + LLPointer<LLUIImage> mImageHeaderFocused; - // style saved when applying it in setTitleFontStyle - LLStyle::Params mStyleParams; + // style saved when applying it in setTitleFontStyle + LLStyle::Params mStyleParams; - LLUIColor mHeaderBGColor; + LLUIColor mHeaderBGColor; - bool mNeedsHighlight; - bool mIsSelected; + bool mNeedsHighlight; + bool mIsSelected; - LLFrameTimer mAutoOpenTimer; + LLFrameTimer mAutoOpenTimer; }; LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params() @@ -117,33 +117,33 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params() } LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader( - const LLAccordionCtrlTabHeader::Params& p) + const LLAccordionCtrlTabHeader::Params& p) : LLUICtrl(p) , mHeaderBGColor(p.header_bg_color()) , mNeedsHighlight(false) , mIsSelected(false), - mImageCollapsed(p.header_collapse_img), - mImageCollapsedPressed(p.header_collapse_img_pressed), - mImageExpanded(p.header_expand_img), - mImageExpandedPressed(p.header_expand_img_pressed), - mImageHeader(p.header_image), - mImageHeaderOver(p.header_image_over), - mImageHeaderPressed(p.header_image_pressed), - mImageHeaderFocused(p.header_image_focused) + mImageCollapsed(p.header_collapse_img), + mImageCollapsedPressed(p.header_collapse_img_pressed), + mImageExpanded(p.header_expand_img), + mImageExpandedPressed(p.header_expand_img_pressed), + mImageHeader(p.header_image), + mImageHeaderOver(p.header_image_over), + mImageHeaderPressed(p.header_image_pressed), + mImageHeaderFocused(p.header_image_focused) { - LLTextBox::Params textboxParams; - textboxParams.name(DD_TEXTBOX_NAME); - textboxParams.initial_value(p.title()); - textboxParams.text_color(p.header_text_color()); - textboxParams.follows.flags(FOLLOWS_NONE); - textboxParams.font( p.font() ); - textboxParams.font_shadow(LLFontGL::NO_SHADOW); - textboxParams.use_ellipses = true; - textboxParams.bg_visible = false; - textboxParams.mouse_opaque = false; - textboxParams.parse_urls = false; - mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams); - addChild(mHeaderTextbox); + LLTextBox::Params textboxParams; + textboxParams.name(DD_TEXTBOX_NAME); + textboxParams.initial_value(p.title()); + textboxParams.text_color(p.header_text_color()); + textboxParams.follows.flags(FOLLOWS_NONE); + textboxParams.font( p.font() ); + textboxParams.font_shadow(LLFontGL::NO_SHADOW); + textboxParams.use_ellipses = true; + textboxParams.bg_visible = false; + textboxParams.mouse_opaque = false; + textboxParams.parse_urls = false; + mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams); + addChild(mHeaderTextbox); } LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader() @@ -152,235 +152,235 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader() BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild() { - return TRUE; + return TRUE; } std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle() { - if (mHeaderTextbox) - { - return mHeaderTextbox->getText(); - } + if (mHeaderTextbox) + { + return mHeaderTextbox->getText(); + } - return LLStringUtil::null; + return LLStringUtil::null; } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl) { - if (mHeaderTextbox) - { - LLTextUtil::textboxSetHighlightedVal( - mHeaderTextbox, - mStyleParams, - title, - hl); - } + if (mHeaderTextbox) + { + LLTextUtil::textboxSetHighlightedVal( + mHeaderTextbox, + mStyleParams, + title, + hl); + } } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string style) { - if (mHeaderTextbox) - { - std::string text = mHeaderTextbox->getText(); - mStyleParams.font(mHeaderTextbox->getFont()); - mStyleParams.font.style(style); - mHeaderTextbox->setText(text, mStyleParams); - } + if (mHeaderTextbox) + { + std::string text = mHeaderTextbox->getText(); + mStyleParams.font(mHeaderTextbox->getFont()); + mStyleParams.font.style(style); + mHeaderTextbox->setText(text, mStyleParams); + } } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleColor(LLUIColor color) { - if (mHeaderTextbox) - { - mHeaderTextbox->setColor(color); - } + if (mHeaderTextbox) + { + mHeaderTextbox->setColor(color); + } } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() { - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); - - F32 alpha = getCurrentTransparency(); - gl_rect_2d(0, 0, width - 1, height - 1, mHeaderBGColor.get() % alpha, TRUE); - - LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent()); - bool collapsible = parent && parent->getCollapsible(); - bool expanded = parent && parent->getDisplayChildren(); - - // Handle overlay images, if needed - // Only show green "focus" background image if the accordion is open, - // because the user's mental model of focus is that it goes away after - // the accordion is closed. - if (getParent()->hasFocus() || mIsSelected - /*&& !(collapsible && !expanded)*/ // WHY?? - ) - { - mImageHeaderFocused->draw(0, 0, width, height); - } - else - { - mImageHeader->draw(0, 0, width, height); - } - - if (mNeedsHighlight) - { - mImageHeaderOver->draw(0, 0, width, height); - } - - if (collapsible) - { - LLPointer<LLUIImage> overlay_image; - if (expanded) - { - overlay_image = mImageExpanded; - } - else - { - overlay_image = mImageCollapsed; - } - overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, (height - overlay_image->getHeight()) / 2); - } - - LLUICtrl::draw(); + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + F32 alpha = getCurrentTransparency(); + gl_rect_2d(0, 0, width - 1, height - 1, mHeaderBGColor.get() % alpha, TRUE); + + LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent()); + bool collapsible = parent && parent->getCollapsible(); + bool expanded = parent && parent->getDisplayChildren(); + + // Handle overlay images, if needed + // Only show green "focus" background image if the accordion is open, + // because the user's mental model of focus is that it goes away after + // the accordion is closed. + if (getParent()->hasFocus() || mIsSelected + /*&& !(collapsible && !expanded)*/ // WHY?? + ) + { + mImageHeaderFocused->draw(0, 0, width, height); + } + else + { + mImageHeader->draw(0, 0, width, height); + } + + if (mNeedsHighlight) + { + mImageHeaderOver->draw(0, 0, width, height); + } + + if (collapsible) + { + LLPointer<LLUIImage> overlay_image; + if (expanded) + { + overlay_image = mImageExpanded; + } + else + { + overlay_image = mImageCollapsed; + } + overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, (height - overlay_image->getHeight()) / 2); + } + + LLUICtrl::draw(); } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { - S32 header_height = mHeaderTextbox->getTextPixelHeight(); - - LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2); - mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); - mHeaderTextbox->setRect(textboxRect); - - if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth()) - { - setToolTip(mHeaderTextbox->getText()); - } - else - { - setToolTip(LLStringUtil::null); - } + S32 header_height = mHeaderTextbox->getTextPixelHeight(); + + LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2); + mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); + mHeaderTextbox->setRect(textboxRect); + + if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth()) + { + setToolTip(mHeaderTextbox->getText()); + } + else + { + setToolTip(LLStringUtil::null); + } } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask) { - LLUICtrl::onMouseEnter(x, y, mask); - mNeedsHighlight = true; + LLUICtrl::onMouseEnter(x, y, mask); + mNeedsHighlight = true; } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask) { - LLUICtrl::onMouseLeave(x, y, mask); - mNeedsHighlight = false; - mAutoOpenTimer.stop(); + LLUICtrl::onMouseLeave(x, y, mask); + mNeedsHighlight = false; + mAutoOpenTimer.stop(); } BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if ((key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) - { - return getParent()->handleKey(key, mask, called_from_parent); - } + if ((key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) + { + return getParent()->handleKey(key, mask, called_from_parent); + } - return LLUICtrl::handleKey(key, mask, called_from_parent); + return LLUICtrl::handleKey(key, mask, called_from_parent); } BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent()); - - if (parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose()) - { - if (mAutoOpenTimer.getStarted()) - { - if (mAutoOpenTimer.getElapsedTimeF32() > AUTO_OPEN_TIME) - { - parent->changeOpenClose(false); - mAutoOpenTimer.stop(); - return TRUE; - } - } - else - { - mAutoOpenTimer.start(); - } - } - - return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg); + LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent()); + + if (parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose()) + { + if (mAutoOpenTimer.getStarted()) + { + if (mAutoOpenTimer.getElapsedTimeF32() > AUTO_OPEN_TIME) + { + parent->changeOpenClose(false); + mAutoOpenTimer.stop(); + return TRUE; + } + } + else + { + mAutoOpenTimer.start(); + } + } + + return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg); } LLAccordionCtrlTab::Params::Params() - : title("title") - ,display_children("expanded", true) - ,header_height("header_height", HEADER_HEIGHT), - min_width("min_width", 0), - min_height("min_height", 0) - ,collapsible("collapsible", true) - ,header_bg_color("header_bg_color") - ,dropdown_bg_color("dropdown_bg_color") - ,header_visible("header_visible",true) - ,padding_left("padding_left",2) - ,padding_right("padding_right",2) - ,padding_top("padding_top",2) - ,padding_bottom("padding_bottom",2) - ,header_expand_img("header_expand_img") - ,header_expand_img_pressed("header_expand_img_pressed") - ,header_collapse_img("header_collapse_img") - ,header_collapse_img_pressed("header_collapse_img_pressed") - ,header_image("header_image") - ,header_image_over("header_image_over") - ,header_image_pressed("header_image_pressed") - ,header_image_focused("header_image_focused") - ,header_text_color("header_text_color") - ,fit_panel("fit_panel",true) - ,selection_enabled("selection_enabled", false) + : title("title") + ,display_children("expanded", true) + ,header_height("header_height", HEADER_HEIGHT), + min_width("min_width", 0), + min_height("min_height", 0) + ,collapsible("collapsible", true) + ,header_bg_color("header_bg_color") + ,dropdown_bg_color("dropdown_bg_color") + ,header_visible("header_visible",true) + ,padding_left("padding_left",2) + ,padding_right("padding_right",2) + ,padding_top("padding_top",2) + ,padding_bottom("padding_bottom",2) + ,header_expand_img("header_expand_img") + ,header_expand_img_pressed("header_expand_img_pressed") + ,header_collapse_img("header_collapse_img") + ,header_collapse_img_pressed("header_collapse_img_pressed") + ,header_image("header_image") + ,header_image_over("header_image_over") + ,header_image_pressed("header_image_pressed") + ,header_image_focused("header_image_focused") + ,header_text_color("header_text_color") + ,fit_panel("fit_panel",true) + ,selection_enabled("selection_enabled", false) { - changeDefault(mouse_opaque, false); + changeDefault(mouse_opaque, false); } LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) - : LLUICtrl(p) - ,mDisplayChildren(p.display_children) - ,mCollapsible(p.collapsible) - ,mExpandedHeight(0) - ,mDropdownBGColor(p.dropdown_bg_color()) - ,mHeaderVisible(p.header_visible) - ,mPaddingLeft(p.padding_left) - ,mPaddingRight(p.padding_right) - ,mPaddingTop(p.padding_top) - ,mPaddingBottom(p.padding_bottom) - ,mCanOpenClose(true) - ,mFitPanel(p.fit_panel) - ,mSelectionEnabled(p.selection_enabled) - ,mContainerPanel(NULL) - ,mScrollbar(NULL) + : LLUICtrl(p) + ,mDisplayChildren(p.display_children) + ,mCollapsible(p.collapsible) + ,mExpandedHeight(0) + ,mDropdownBGColor(p.dropdown_bg_color()) + ,mHeaderVisible(p.header_visible) + ,mPaddingLeft(p.padding_left) + ,mPaddingRight(p.padding_right) + ,mPaddingTop(p.padding_top) + ,mPaddingBottom(p.padding_bottom) + ,mCanOpenClose(true) + ,mFitPanel(p.fit_panel) + ,mSelectionEnabled(p.selection_enabled) + ,mContainerPanel(NULL) + ,mScrollbar(NULL) { - mStoredOpenCloseState = false; - mWasStateStored = false; - mSkipChangesOnNotifyParent = false; - - mDropdownBGColor = LLColor4::white; - LLAccordionCtrlTabHeader::Params headerParams; - headerParams.name(DD_HEADER_NAME); - headerParams.title(p.title); - mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams); - addChild(mHeader, 1); - - LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); - - if (!p.selection_enabled) - { - LLFocusableElement::setFocusLostCallback(boost::bind(&LLAccordionCtrlTab::deselectOnFocusLost, this)); - } - - reshape(100, 200,FALSE); + mStoredOpenCloseState = false; + mWasStateStored = false; + mSkipChangesOnNotifyParent = false; + + mDropdownBGColor = LLColor4::white; + LLAccordionCtrlTabHeader::Params headerParams; + headerParams.name(DD_HEADER_NAME); + headerParams.title(p.title); + mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams); + addChild(mHeader, 1); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); + + if (!p.selection_enabled) + { + LLFocusableElement::setFocusLostCallback(boost::bind(&LLAccordionCtrlTab::deselectOnFocusLost, this)); + } + + reshape(100, 200,FALSE); } LLAccordionCtrlTab::~LLAccordionCtrlTab() @@ -389,68 +389,68 @@ LLAccordionCtrlTab::~LLAccordionCtrlTab() void LLAccordionCtrlTab::setDisplayChildren(bool display) { - mDisplayChildren = display; - LLRect rect = getRect(); - - rect.mBottom = rect.mTop - (getDisplayChildren() ? mExpandedHeight : HEADER_HEIGHT); - setRect(rect); - - if (mContainerPanel) - { - mContainerPanel->setVisible(getDisplayChildren()); - } - - if (mDisplayChildren) - { - adjustContainerPanel(); - } - else - { - if (mScrollbar) - mScrollbar->setVisible(FALSE); - } + mDisplayChildren = display; + LLRect rect = getRect(); + + rect.mBottom = rect.mTop - (getDisplayChildren() ? mExpandedHeight : HEADER_HEIGHT); + setRect(rect); + + if (mContainerPanel) + { + mContainerPanel->setVisible(getDisplayChildren()); + } + + if (mDisplayChildren) + { + adjustContainerPanel(); + } + else + { + if (mScrollbar) + mScrollbar->setVisible(FALSE); + } } void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { - LLRect headerRect; + LLRect headerRect; - headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT); - mHeader->setRect(headerRect); - mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); + headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT); + mHeader->setRect(headerRect); + mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); - if (!mDisplayChildren) - return; + if (!mDisplayChildren) + return; - LLRect childRect; + LLRect childRect; - childRect.setLeftTopAndSize( - getPaddingLeft(), - height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), - height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + childRect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); - adjustContainerPanel(childRect); + adjustContainerPanel(childRect); } void LLAccordionCtrlTab::changeOpenClose(bool is_open) { - if (is_open) - mExpandedHeight = getRect().getHeight(); - - setDisplayChildren(!is_open); - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); - if (mCommitSignal) - { - (*mCommitSignal)(this, getDisplayChildren()); - } + if (is_open) + mExpandedHeight = getRect().getHeight(); + + setDisplayChildren(!is_open); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + if (mCommitSignal) + { + (*mCommitSignal)(this, getDisplayChildren()); + } } void LLAccordionCtrlTab::onVisibilityChange(BOOL new_visibility) { - LLUICtrl::onVisibilityChange(new_visibility); + LLUICtrl::onVisibilityChange(new_visibility); - notifyParent(LLSD().with("child_visibility_change", new_visibility)); + notifyParent(LLSD().with("child_visibility_change", new_visibility)); } // virtual @@ -473,7 +473,7 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl) S32 scroll_pos = llclamp(mScrollbar->getDocPos(), bottom, // min vertical scroll - top); // max vertical scroll + top); // max vertical scroll mScrollbar->setDocPos(scroll_pos); } @@ -484,643 +484,643 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl) BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask) { - if (mCollapsible && mHeaderVisible && mCanOpenClose) - { - if (y >= (getRect().getHeight() - HEADER_HEIGHT)) - { - mHeader->setFocus(true); - changeOpenClose(getDisplayChildren()); - - // Reset stored state - mWasStateStored = false; - return TRUE; - } - } - return LLUICtrl::handleMouseDown(x,y,mask); + if (mCollapsible && mHeaderVisible && mCanOpenClose) + { + if (y >= (getRect().getHeight() - HEADER_HEIGHT)) + { + mHeader->setFocus(true); + changeOpenClose(getDisplayChildren()); + + // Reset stored state + mWasStateStored = false; + return TRUE; + } + } + return LLUICtrl::handleMouseDown(x,y,mask); } BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask) { - return LLUICtrl::handleMouseUp(x,y,mask); + return LLUICtrl::handleMouseUp(x,y,mask); } boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb) { - return setCommitCallback(cb); + return setCommitCallback(cb); } bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) { - if (DD_HEADER_NAME != child->getName()) - { - reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT ); - mExpandedHeight = getRect().getHeight(); - } - - bool res = LLUICtrl::addChild(child, tab_group); - - if (DD_HEADER_NAME != child->getName()) - { - if (!mCollapsible) - setDisplayChildren(true); - else - setDisplayChildren(getDisplayChildren()); - } - - if (!mContainerPanel) - mContainerPanel = findContainerView(); - - return res; + if (DD_HEADER_NAME != child->getName()) + { + reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT ); + mExpandedHeight = getRect().getHeight(); + } + + bool res = LLUICtrl::addChild(child, tab_group); + + if (DD_HEADER_NAME != child->getName()) + { + if (!mCollapsible) + setDisplayChildren(true); + else + setDisplayChildren(getDisplayChildren()); + } + + if (!mContainerPanel) + mContainerPanel = findContainerView(); + + return res; } void LLAccordionCtrlTab::setAccordionView(LLView* panel) { - addChild(panel, 0); + addChild(panel, 0); } std::string LLAccordionCtrlTab::getTitle() const { - if (mHeader) - { - return mHeader->getTitle(); - } + if (mHeader) + { + return mHeader->getTitle(); + } - return LLStringUtil::null; + return LLStringUtil::null; } void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl) { - if (mHeader) - { - mHeader->setTitle(title, hl); - } + if (mHeader) + { + mHeader->setTitle(title, hl); + } } void LLAccordionCtrlTab::setTitleFontStyle(std::string style) { - if (mHeader) - { - mHeader->setTitleFontStyle(style); - } + if (mHeader) + { + mHeader->setTitleFontStyle(style); + } } void LLAccordionCtrlTab::setTitleColor(LLUIColor color) { - if (mHeader) - { - mHeader->setTitleColor(color); - } + if (mHeader) + { + mHeader->setTitleColor(color); + } } boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb) { - if (mHeader) - { - return mHeader->setFocusReceivedCallback(cb); - } + if (mHeader) + { + return mHeader->setFocusReceivedCallback(cb); + } - return boost::signals2::connection(); + return boost::signals2::connection(); } boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb) { - if (mHeader) - { - return mHeader->setFocusLostCallback(cb); - } + if (mHeader) + { + return mHeader->setFocusLostCallback(cb); + } - return boost::signals2::connection(); + return boost::signals2::connection(); } void LLAccordionCtrlTab::setSelected(bool is_selected) { - if (mHeader) - { - mHeader->setSelected(is_selected); - } + if (mHeader) + { + mHeader->setSelected(is_selected); + } } -LLView* LLAccordionCtrlTab::findContainerView() +LLView* LLAccordionCtrlTab::findContainerView() { - child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end(); - while (it != it_end) - { - LLView* child = *(it++); - if (DD_HEADER_NAME != child->getName() && child->getVisible()) - return child; - } - - return NULL; + child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end(); + while (it != it_end) + { + LLView* child = *(it++); + if (DD_HEADER_NAME != child->getName() && child->getVisible()) + return child; + } + + return NULL; } void LLAccordionCtrlTab::selectOnFocusReceived() { - if (getParent()) // A parent may not be set if tabs are added dynamically. - { - getParent()->notifyParent(LLSD().with("action", "select_current")); - } + if (getParent()) // A parent may not be set if tabs are added dynamically. + { + getParent()->notifyParent(LLSD().with("action", "select_current")); + } } void LLAccordionCtrlTab::deselectOnFocusLost() { - if (getParent()) // A parent may not be set if tabs are added dynamically. - { - getParent()->notifyParent(LLSD().with("action", "deselect_current")); - } + if (getParent()) // A parent may not be set if tabs are added dynamically. + { + getParent()->notifyParent(LLSD().with("action", "deselect_current")); + } } S32 LLAccordionCtrlTab::getHeaderHeight() { - return mHeaderVisible ? HEADER_HEIGHT : 0; + return mHeaderVisible ? HEADER_HEIGHT : 0; } void LLAccordionCtrlTab::setHeaderVisible(bool value) { - if (mHeaderVisible == value) - return; + if (mHeaderVisible == value) + return; - mHeaderVisible = value; + mHeaderVisible = value; - if (mHeader) - { - mHeader->setVisible(value ? TRUE : FALSE); - } + if (mHeader) + { + mHeader->setVisible(value ? TRUE : FALSE); + } - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); }; //virtual BOOL LLAccordionCtrlTab::postBuild() { - if (mHeader) - { - mHeader->setVisible(mHeaderVisible); - } - - static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); - - LLRect scroll_rect; - scroll_rect.setOriginAndSize( - getRect().getWidth() - scrollbar_size, - 1, - scrollbar_size, - getRect().getHeight() - 1); - - mContainerPanel = findContainerView(); - - if (!mFitPanel) - { - LLScrollbar::Params sbparams; - sbparams.name("scrollable vertical"); - sbparams.rect(scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(getRect().getHeight()); - sbparams.doc_pos(0); - sbparams.page_size(getRect().getHeight()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.change_callback(boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2)); - - mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams); - LLView::addChild(mScrollbar); - mScrollbar->setFollowsRight(); - mScrollbar->setFollowsTop(); - mScrollbar->setFollowsBottom(); - - mScrollbar->setVisible(false); - } - - if (mContainerPanel) - { - mContainerPanel->setVisible(mDisplayChildren); - } - - return LLUICtrl::postBuild(); + if (mHeader) + { + mHeader->setVisible(mHeaderVisible); + } + + static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + mContainerPanel = findContainerView(); + + if (!mFitPanel) + { + LLScrollbar::Params sbparams; + sbparams.name("scrollable vertical"); + sbparams.rect(scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(getRect().getHeight()); + sbparams.doc_pos(0); + sbparams.page_size(getRect().getHeight()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.change_callback(boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2)); + + mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams); + LLView::addChild(mScrollbar); + mScrollbar->setFollowsRight(); + mScrollbar->setFollowsTop(); + mScrollbar->setFollowsBottom(); + + mScrollbar->setVisible(false); + } + + if (mContainerPanel) + { + mContainerPanel->setVisible(mDisplayChildren); + } + + return LLUICtrl::postBuild(); } -bool LLAccordionCtrlTab::notifyChildren (const LLSD& info) +bool LLAccordionCtrlTab::notifyChildren (const LLSD& info) { - if (info.has("action")) - { - std::string str_action = info["action"]; - if (str_action == "store_state") - { - storeOpenCloseState(); - return true; - } - - if (str_action == "restore_state") - { - restoreOpenCloseState(); - return true; - } - } - - return LLUICtrl::notifyChildren(info); + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "store_state") + { + storeOpenCloseState(); + return true; + } + + if (str_action == "restore_state") + { + restoreOpenCloseState(); + return true; + } + } + + return LLUICtrl::notifyChildren(info); } -S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) +S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) { - if (info.has("action")) - { - std::string str_action = info["action"]; - if (str_action == "size_changes") - { - S32 height = info["height"]; - height = llmax(height, 10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); - - mExpandedHeight = height; - - if (isExpanded() && !mSkipChangesOnNotifyParent) - { - LLRect panel_rect = getRect(); - panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height); - reshape(getRect().getWidth(),height); - setRect(panel_rect); - } - - // LLAccordionCtrl should rearrange accordion tab if one of accordions changed its size - if (getParent()) // A parent may not be set if tabs are added dynamically. - getParent()->notifyParent(info); - return 1; - } - - if (str_action == "select_prev") - { - showAndFocusHeader(); - return 1; - } - } - else if (info.has("scrollToShowRect")) - { - LLAccordionCtrl* parent = dynamic_cast<LLAccordionCtrl*>(getParent()); - if (parent && parent->getFitParent()) - { - // EXT-8285 ('No attachments worn' text appears at the bottom of blank 'Attachments' accordion) - // The problem was in passing message "scrollToShowRect" IN LLAccordionCtrlTab::notifyParent - // FROM child LLScrollContainer TO parent LLAccordionCtrl with "it_parent" set to true. - - // It is wrong notification for parent accordion which leads to recursive call of adjustContainerPanel - // As the result of recursive call of adjustContainerPanel we got LLAccordionCtrlTab - // that reshaped and re-sized with different rectangles. - - // LLAccordionCtrl has own scrollContainer and LLAccordionCtrlTab has own scrollContainer - // both should handle own scroll container's event. - // So, if parent accordion "fit_parent" accordion tab should handle its scroll container events itself. - - return 1; - } - - if (!getDisplayChildren()) - { - // Don't pass scrolling event further if our contents are invisible (STORM-298). - return 1; - } - } - - return LLUICtrl::notifyParent(info); + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "size_changes") + { + S32 height = info["height"]; + height = llmax(height, 10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); + + mExpandedHeight = height; + + if (isExpanded() && !mSkipChangesOnNotifyParent) + { + LLRect panel_rect = getRect(); + panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height); + reshape(getRect().getWidth(),height); + setRect(panel_rect); + } + + // LLAccordionCtrl should rearrange accordion tab if one of accordions changed its size + if (getParent()) // A parent may not be set if tabs are added dynamically. + getParent()->notifyParent(info); + return 1; + } + + if (str_action == "select_prev") + { + showAndFocusHeader(); + return 1; + } + } + else if (info.has("scrollToShowRect")) + { + LLAccordionCtrl* parent = dynamic_cast<LLAccordionCtrl*>(getParent()); + if (parent && parent->getFitParent()) + { + // EXT-8285 ('No attachments worn' text appears at the bottom of blank 'Attachments' accordion) + // The problem was in passing message "scrollToShowRect" IN LLAccordionCtrlTab::notifyParent + // FROM child LLScrollContainer TO parent LLAccordionCtrl with "it_parent" set to true. + + // It is wrong notification for parent accordion which leads to recursive call of adjustContainerPanel + // As the result of recursive call of adjustContainerPanel we got LLAccordionCtrlTab + // that reshaped and re-sized with different rectangles. + + // LLAccordionCtrl has own scrollContainer and LLAccordionCtrlTab has own scrollContainer + // both should handle own scroll container's event. + // So, if parent accordion "fit_parent" accordion tab should handle its scroll container events itself. + + return 1; + } + + if (!getDisplayChildren()) + { + // Don't pass scrolling event further if our contents are invisible (STORM-298). + return 1; + } + } + + return LLUICtrl::notifyParent(info); } S32 LLAccordionCtrlTab::notify(const LLSD& info) { - if (info.has("action")) - { - std::string str_action = info["action"]; - if (str_action == "select_first") - { - showAndFocusHeader(); - return 1; - } - - if (str_action == "select_last") - { - if (!getDisplayChildren()) - { - showAndFocusHeader(); - } - else - { - LLView* view = getAccordionView(); - if (view) - { - view->notify(LLSD().with("action", "select_last")); - } - } - } - } - - return 0; + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "select_first") + { + showAndFocusHeader(); + return 1; + } + + if (str_action == "select_last") + { + if (!getDisplayChildren()) + { + showAndFocusHeader(); + } + else + { + LLView* view = getAccordionView(); + if (view) + { + view->notify(LLSD().with("action", "select_last")); + } + } + } + } + + return 0; } BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if (!mHeader->hasFocus()) - return LLUICtrl::handleKey(key, mask, called_from_parent); - - if ((key == KEY_RETURN) && mask == MASK_NONE) - { - changeOpenClose(getDisplayChildren()); - return TRUE; - } - - if ((key == KEY_ADD || key == KEY_RIGHT) && mask == MASK_NONE) - { - if (!getDisplayChildren()) - { - changeOpenClose(getDisplayChildren()); - return TRUE; - } - } - - if ((key == KEY_SUBTRACT || key == KEY_LEFT) && mask == MASK_NONE) - { - if (getDisplayChildren()) - { - changeOpenClose(getDisplayChildren()); - return TRUE; - } - } - - if (key == KEY_DOWN && mask == MASK_NONE) - { - // if collapsed go to the next accordion - if (!getDisplayChildren()) - { - // we're processing notifyParent so let call parent directly - getParent()->notifyParent(LLSD().with("action", "select_next")); - } - else - { - getAccordionView()->notify(LLSD().with("action", "select_first")); - } - return TRUE; - } - - if (key == KEY_UP && mask == MASK_NONE) - { - // go to the previous accordion - - // we're processing notifyParent so let call parent directly - getParent()->notifyParent(LLSD().with("action", "select_prev")); - return TRUE; - } - - return LLUICtrl::handleKey(key, mask, called_from_parent); + if (!mHeader->hasFocus()) + return LLUICtrl::handleKey(key, mask, called_from_parent); + + if ((key == KEY_RETURN) && mask == MASK_NONE) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + + if ((key == KEY_ADD || key == KEY_RIGHT) && mask == MASK_NONE) + { + if (!getDisplayChildren()) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + } + + if ((key == KEY_SUBTRACT || key == KEY_LEFT) && mask == MASK_NONE) + { + if (getDisplayChildren()) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + } + + if (key == KEY_DOWN && mask == MASK_NONE) + { + // if collapsed go to the next accordion + if (!getDisplayChildren()) + { + // we're processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action", "select_next")); + } + else + { + getAccordionView()->notify(LLSD().with("action", "select_first")); + } + return TRUE; + } + + if (key == KEY_UP && mask == MASK_NONE) + { + // go to the previous accordion + + // we're processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action", "select_prev")); + return TRUE; + } + + return LLUICtrl::handleKey(key, mask, called_from_parent); } void LLAccordionCtrlTab::showAndFocusHeader() { - if (!mHeader) - { - return; - } - - mHeader->setFocus(true); - mHeader->setSelected(mSelectionEnabled); - - LLRect screen_rc; - LLRect selected_rc = mHeader->getRect(); - localRectToScreen(selected_rc, &screen_rc); - - // This call to notifyParent() is intended to deliver "scrollToShowRect" command - // to the parent LLAccordionCtrl so by calling it from the direct parent of this - // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain - // is shortened and messages from inside the collapsed tabs are avoided. - // See STORM-536. - getParent()->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); + if (!mHeader) + { + return; + } + + mHeader->setFocus(true); + mHeader->setSelected(mSelectionEnabled); + + LLRect screen_rc; + LLRect selected_rc = mHeader->getRect(); + localRectToScreen(selected_rc, &screen_rc); + + // This call to notifyParent() is intended to deliver "scrollToShowRect" command + // to the parent LLAccordionCtrl so by calling it from the direct parent of this + // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain + // is shortened and messages from inside the collapsed tabs are avoided. + // See STORM-536. + getParent()->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); } void LLAccordionCtrlTab::storeOpenCloseState() { - if (mWasStateStored) - return; - mStoredOpenCloseState = getDisplayChildren(); - mWasStateStored = true; + if (mWasStateStored) + return; + mStoredOpenCloseState = getDisplayChildren(); + mWasStateStored = true; } void LLAccordionCtrlTab::restoreOpenCloseState() { - if (!mWasStateStored) - return; - if (getDisplayChildren() != mStoredOpenCloseState) - { - changeOpenClose(getDisplayChildren()); - } - mWasStateStored = false; + if (!mWasStateStored) + return; + if (getDisplayChildren() != mStoredOpenCloseState) + { + changeOpenClose(getDisplayChildren()); + } + mWasStateStored = false; } void LLAccordionCtrlTab::adjustContainerPanel() { - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); - LLRect child_rect; - child_rect.setLeftTopAndSize( - getPaddingLeft(), - height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), - height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + LLRect child_rect; + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); - adjustContainerPanel(child_rect); + adjustContainerPanel(child_rect); } void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect) { - if (!mContainerPanel) - return; - - if (!mFitPanel) - { - show_hide_scrollbar(child_rect); - updateLayout(child_rect); - } - else - { - mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight()); - mContainerPanel->setRect(child_rect); - } + if (!mContainerPanel) + return; + + if (!mFitPanel) + { + show_hide_scrollbar(child_rect); + updateLayout(child_rect); + } + else + { + mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight()); + mContainerPanel->setRect(child_rect); + } } S32 LLAccordionCtrlTab::getChildViewHeight() { - if (!mContainerPanel) - return 0; - return mContainerPanel->getRect().getHeight(); + if (!mContainerPanel) + return 0; + return mContainerPanel->getRect().getHeight(); } void LLAccordionCtrlTab::show_hide_scrollbar(const LLRect& child_rect) { - if (getChildViewHeight() > child_rect.getHeight()) - showScrollbar(child_rect); - else - hideScrollbar(child_rect); + if (getChildViewHeight() > child_rect.getHeight()) + showScrollbar(child_rect); + else + hideScrollbar(child_rect); } void LLAccordionCtrlTab::showScrollbar(const LLRect& child_rect) { - if (!mContainerPanel || !mScrollbar) - return; - bool was_visible = mScrollbar->getVisible(); - mScrollbar->setVisible(true); - - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - - ctrlSetLeftTopAndSize(mScrollbar, - child_rect.getWidth() - scrollbar_size, - child_rect.getHeight() - PARENT_BORDER_MARGIN, - scrollbar_size, - child_rect.getHeight() - PARENT_BORDER_MARGIN * 2); - - LLRect orig_rect = mContainerPanel->getRect(); - - mScrollbar->setPageSize(child_rect.getHeight()); - mScrollbar->setDocParams(orig_rect.getHeight(), mScrollbar->getDocPos()); - - if (was_visible) - { - S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1); - mScrollbar->setDocPos(scroll_pos); - } - else // Shrink child panel - { - updateLayout(child_rect); - } + if (!mContainerPanel || !mScrollbar) + return; + bool was_visible = mScrollbar->getVisible(); + mScrollbar->setVisible(true); + + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + ctrlSetLeftTopAndSize(mScrollbar, + child_rect.getWidth() - scrollbar_size, + child_rect.getHeight() - PARENT_BORDER_MARGIN, + scrollbar_size, + child_rect.getHeight() - PARENT_BORDER_MARGIN * 2); + + LLRect orig_rect = mContainerPanel->getRect(); + + mScrollbar->setPageSize(child_rect.getHeight()); + mScrollbar->setDocParams(orig_rect.getHeight(), mScrollbar->getDocPos()); + + if (was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1); + mScrollbar->setDocPos(scroll_pos); + } + else // Shrink child panel + { + updateLayout(child_rect); + } } void LLAccordionCtrlTab::hideScrollbar(const LLRect& child_rect) { - if (!mContainerPanel || !mScrollbar) - return; + if (!mContainerPanel || !mScrollbar) + return; - if (mScrollbar->getVisible() == FALSE) - return; + if (mScrollbar->getVisible() == FALSE) + return; - mScrollbar->setVisible(FALSE); - mScrollbar->setDocPos(0); + mScrollbar->setVisible(FALSE); + mScrollbar->setDocPos(0); - //shrink child panel - updateLayout(child_rect); + //shrink child panel + updateLayout(child_rect); } void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*) { - LLRect child_rect; + LLRect child_rect; - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); - child_rect.setLeftTopAndSize( - getPaddingLeft(), - height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), - height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); - updateLayout(child_rect); + updateLayout(child_rect); } void LLAccordionCtrlTab::drawChild(const LLRect& root_rect, LLView* child) { - if (child && child->getVisible() && child->getRect().isValid()) - { - LLRect screen_rect; - localRectToScreen(child->getRect(), &screen_rect); - - if (root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) - { - gGL.matrixMode(LLRender::MM_MODELVIEW); - LLUI::pushMatrix(); - { - LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom); - child->draw(); - } - LLUI::popMatrix(); - } - } + if (child && child->getVisible() && child->getRect().isValid()) + { + LLRect screen_rect; + localRectToScreen(child->getRect(), &screen_rect); + + if (root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) + { + gGL.matrixMode(LLRender::MM_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom); + child->draw(); + } + LLUI::popMatrix(); + } + } } void LLAccordionCtrlTab::draw() { - if (mFitPanel) - { - LLUICtrl::draw(); - } - else - { - LLRect root_rect(getRootView()->getRect()); - drawChild(root_rect, mHeader); - drawChild(root_rect, mScrollbar); - - LLRect child_rect; - - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); - - child_rect.setLeftTopAndSize( - getPaddingLeft(), - height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), - height - getHeaderHeight() - getPaddingTop() - getPaddingBottom()); - - LLLocalClipRect clip(child_rect); - drawChild(root_rect,mContainerPanel); - } + if (mFitPanel) + { + LLUICtrl::draw(); + } + else + { + LLRect root_rect(getRootView()->getRect()); + drawChild(root_rect, mHeader); + drawChild(root_rect, mScrollbar); + + LLRect child_rect; + + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom()); + + LLLocalClipRect clip(child_rect); + drawChild(root_rect,mContainerPanel); + } } void LLAccordionCtrlTab::updateLayout(const LLRect& child_rect) { - LLView* child = getAccordionView(); - if (!mContainerPanel) - return; - - S32 panel_top = child_rect.getHeight(); - S32 panel_width = child_rect.getWidth(); - - static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); - if (mScrollbar && mScrollbar->getVisible()) - { - panel_top += mScrollbar->getDocPos(); - panel_width -= scrollbar_size; - } - - // Set sizes for first panels and dragbars - LLRect panel_rect = child->getRect(); - ctrlSetLeftTopAndSize(mContainerPanel, child_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); + LLView* child = getAccordionView(); + if (!mContainerPanel) + return; + + S32 panel_top = child_rect.getHeight(); + S32 panel_width = child_rect.getWidth(); + + static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0); + if (mScrollbar && mScrollbar->getVisible()) + { + panel_top += mScrollbar->getDocPos(); + panel_width -= scrollbar_size; + } + + // Set sizes for first panels and dragbars + LLRect panel_rect = child->getRect(); + ctrlSetLeftTopAndSize(mContainerPanel, child_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); } void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) { - if (!panel) - return; - LLRect panel_rect = panel->getRect(); - panel_rect.setLeftTopAndSize(left, top, width, height); - panel->reshape( width, height, 1); - panel->setRect(panel_rect); + if (!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize(left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); } BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) { - //header may be not the first child but we need to process it first - if (y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT / 2)) - { - //inside tab header - //fix for EXT-6619 - mHeader->handleToolTip(x, y, mask); - return TRUE; - } - return LLUICtrl::handleToolTip(x, y, mask); + //header may be not the first child but we need to process it first + if (y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT / 2)) + { + //inside tab header + //fix for EXT-6619 + mHeader->handleToolTip(x, y, mask); + return TRUE; + } + return LLUICtrl::handleToolTip(x, y, mask); } BOOL LLAccordionCtrlTab::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if (LLUICtrl::handleScrollWheel(x, y, clicks)) - { - return TRUE; - } + if (LLUICtrl::handleScrollWheel(x, y, clicks)) + { + return TRUE; + } - if (mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) - { - return TRUE; - } + if (mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) + { + return TRUE; + } - return FALSE; + return FALSE; } diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 496c34c38b..f01fff2519 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -1,25 +1,25 @@ -/** +/** * @file LLAccordionCtrlTab.h * @brief Collapsible box control implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,7 +41,7 @@ class LLScrollbar; -// LLAccordionCtrlTab is a container for other controls. +// LLAccordionCtrlTab is a container for other controls. // It has a Header, by clicking on which hosted controls are shown or hidden. // When hosted controls are show - LLAccordionCtrlTab is expanded. // When hosted controls are hidden - LLAccordionCtrlTab is collapsed. @@ -51,201 +51,201 @@ class LLAccordionCtrlTab : public LLUICtrl // Interface public: - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> display_children, //expanded or collapsed after initialization - collapsible; + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> display_children, //expanded or collapsed after initialization + collapsible; + + Optional<std::string> title; - Optional<std::string> title; + Optional<S32> header_height, + min_width, + min_height; - Optional<S32> header_height, - min_width, - min_height; + // Overlay images (arrows on the left) + Mandatory<LLUIImage*> header_expand_img, + header_expand_img_pressed, + header_collapse_img, + header_collapse_img_pressed; - // Overlay images (arrows on the left) - Mandatory<LLUIImage*> header_expand_img, - header_expand_img_pressed, - header_collapse_img, - header_collapse_img_pressed; + // Background images for the accordion tabs + Mandatory<LLUIImage*> header_image, + header_image_over, + header_image_pressed, + header_image_focused; - // Background images for the accordion tabs - Mandatory<LLUIImage*> header_image, - header_image_over, - header_image_pressed, - header_image_focused; + Optional<LLUIColor> header_bg_color, + header_text_color, + dropdown_bg_color; - Optional<LLUIColor> header_bg_color, - header_text_color, - dropdown_bg_color; + Optional<bool> header_visible; - Optional<bool> header_visible; + Optional<bool> fit_panel; - Optional<bool> fit_panel; + Optional<bool> selection_enabled; - Optional<bool> selection_enabled; + Optional<S32> padding_left, + padding_right, + padding_top, + padding_bottom; - Optional<S32> padding_left, - padding_right, - padding_top, - padding_bottom; + Params(); + }; - Params(); - }; + typedef LLDefaultChildRegistry child_registry_t; - typedef LLDefaultChildRegistry child_registry_t; + virtual ~LLAccordionCtrlTab(); - virtual ~LLAccordionCtrlTab(); - - // Registers callback for expand/collapse events. - boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb); + // Registers callback for expand/collapse events. + boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb); - // Changes expand/collapse state - virtual void setDisplayChildren(bool display); + // Changes expand/collapse state + virtual void setDisplayChildren(bool display); - // Returns expand/collapse state - virtual bool getDisplayChildren() const { return mDisplayChildren; }; + // Returns expand/collapse state + virtual bool getDisplayChildren() const { return mDisplayChildren; }; - //set LLAccordionCtrlTab panel - void setAccordionView(LLView* panel); - LLView* getAccordionView() { return mContainerPanel; }; + //set LLAccordionCtrlTab panel + void setAccordionView(LLView* panel); + LLView* getAccordionView() { return mContainerPanel; }; - std::string getTitle() const; + std::string getTitle() const; - // Set text and highlight substring in LLAccordionCtrlTabHeader - void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null); + // Set text and highlight substring in LLAccordionCtrlTabHeader + void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null); - // Set text font style in LLAccordionCtrlTabHeader - void setTitleFontStyle(std::string style); + // Set text font style in LLAccordionCtrlTabHeader + void setTitleFontStyle(std::string style); - // Set text color in LLAccordionCtrlTabHeader - void setTitleColor(LLUIColor color); + // Set text color in LLAccordionCtrlTabHeader + void setTitleColor(LLUIColor color); - boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); - boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb); - void setSelected(bool is_selected); + void setSelected(bool is_selected); - bool getCollapsible() { return mCollapsible; }; + bool getCollapsible() { return mCollapsible; }; - void setCollapsible(bool collapsible) { mCollapsible = collapsible; }; - void changeOpenClose(bool is_open); + void setCollapsible(bool collapsible) { mCollapsible = collapsible; }; + void changeOpenClose(bool is_open); - void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; }; - bool canOpenClose() const { return mCanOpenClose; }; + void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; }; + bool canOpenClose() const { return mCanOpenClose; }; - virtual BOOL postBuild(); + virtual BOOL postBuild(); - S32 notifyParent(const LLSD& info); - S32 notify(const LLSD& info); - bool notifyChildren(const LLSD& info); + S32 notifyParent(const LLSD& info); + S32 notify(const LLSD& info); + bool notifyChildren(const LLSD& info); - void draw(); + void draw(); - void storeOpenCloseState(); - void restoreOpenCloseState(); + void storeOpenCloseState(); + void restoreOpenCloseState(); protected: - LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); - friend class LLUICtrlFactory; + LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); + friend class LLUICtrlFactory; // Overrides public: - // Call reshape after changing size - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + // Call reshape after changing size + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /** - * Raises notifyParent event with "child_visibility_change" = new_visibility - */ - void onVisibilityChange(BOOL new_visibility); - virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); + /** + * Raises notifyParent event with "child_visibility_change" = new_visibility + */ + void onVisibilityChange(BOOL new_visibility); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); - // Changes expand/collapse state and triggers expand/collapse callbacks - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + // Changes expand/collapse state and triggers expand/collapse callbacks + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - virtual bool addChild(LLView* child, S32 tab_group = 0 ); + virtual bool addChild(LLView* child, S32 tab_group = 0 ); - bool isExpanded() const { return mDisplayChildren; } + bool isExpanded() const { return mDisplayChildren; } - S32 getHeaderHeight(); + S32 getHeaderHeight(); - // Min size functions + // Min size functions - void setHeaderVisible(bool value); + void setHeaderVisible(bool value); - bool getHeaderVisible() { return mHeaderVisible;} + bool getHeaderVisible() { return mHeaderVisible;} - S32 mExpandedHeight; // Height of expanded ctrl. - // Used to restore height after expand. + S32 mExpandedHeight; // Height of expanded ctrl. + // Used to restore height after expand. - S32 getPaddingLeft() const { return mPaddingLeft;} - S32 getPaddingRight() const { return mPaddingRight;} - S32 getPaddingTop() const { return mPaddingTop;} - S32 getPaddingBottom() const { return mPaddingBottom;} + S32 getPaddingLeft() const { return mPaddingLeft;} + S32 getPaddingRight() const { return mPaddingRight;} + S32 getPaddingTop() const { return mPaddingTop;} + S32 getPaddingBottom() const { return mPaddingBottom;} - void showAndFocusHeader(); + void showAndFocusHeader(); - void setFitPanel( bool fit ) { mFitPanel = true; } - bool getFitParent() const { return mFitPanel; } + void setFitPanel( bool fit ) { mFitPanel = true; } + bool getFitParent() const { return mFitPanel; } - void setIgnoreResizeNotification(bool ignore) { mSkipChangesOnNotifyParent = ignore;} + void setIgnoreResizeNotification(bool ignore) { mSkipChangesOnNotifyParent = ignore;} protected: - void adjustContainerPanel (const LLRect& child_rect); - void adjustContainerPanel (); - S32 getChildViewHeight (); + void adjustContainerPanel (const LLRect& child_rect); + void adjustContainerPanel (); + S32 getChildViewHeight (); - void onScrollPosChangeCallback(S32, LLScrollbar*); + void onScrollPosChangeCallback(S32, LLScrollbar*); - void show_hide_scrollbar (const LLRect& child_rect); - void showScrollbar (const LLRect& child_rect); - void hideScrollbar (const LLRect& child_rect); + void show_hide_scrollbar (const LLRect& child_rect); + void showScrollbar (const LLRect& child_rect); + void hideScrollbar (const LLRect& child_rect); - void updateLayout ( const LLRect& child_rect ); - void ctrlSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); + void updateLayout ( const LLRect& child_rect ); + void ctrlSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); - void drawChild(const LLRect& root_rect,LLView* child); + void drawChild(const LLRect& root_rect,LLView* child); - LLView* findContainerView (); + LLView* findContainerView (); - void selectOnFocusReceived(); - void deselectOnFocusLost(); + void selectOnFocusReceived(); + void deselectOnFocusLost(); private: - class LLAccordionCtrlTabHeader; - LLAccordionCtrlTabHeader* mHeader; //Header + class LLAccordionCtrlTabHeader; + LLAccordionCtrlTabHeader* mHeader; //Header - bool mDisplayChildren; //Expanded/collapsed - bool mCollapsible; - bool mHeaderVisible; + bool mDisplayChildren; //Expanded/collapsed + bool mCollapsible; + bool mHeaderVisible; - bool mCanOpenClose; - bool mFitPanel; + bool mCanOpenClose; + bool mFitPanel; - S32 mPaddingLeft; - S32 mPaddingRight; - S32 mPaddingTop; - S32 mPaddingBottom; + S32 mPaddingLeft; + S32 mPaddingRight; + S32 mPaddingTop; + S32 mPaddingBottom; - bool mStoredOpenCloseState; - bool mWasStateStored; - bool mSkipChangesOnNotifyParent; + bool mStoredOpenCloseState; + bool mWasStateStored; + bool mSkipChangesOnNotifyParent; - bool mSelectionEnabled; + bool mSelectionEnabled; - LLScrollbar* mScrollbar; - LLView* mContainerPanel; + LLScrollbar* mScrollbar; + LLView* mContainerPanel; - LLUIColor mDropdownBGColor; + LLUIColor mDropdownBGColor; }; #endif diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index 589b75ab5b..f2b1f5720f 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llbadge.cpp * @brief Implementation for badges * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,115 +40,115 @@ template class LLBadge* LLView::getChild<class LLBadge>(const std::string& name, LLBadge::Params::Params() - : image("image") - , border_image("border_image") - , border_color("border_color") - , image_color("image_color") - , label("label") - , label_color("label_color") - , label_offset_horiz("label_offset_horiz") - , label_offset_vert("label_offset_vert") - , location("location", LLRelPos::TOP_LEFT) - , location_offset_hcenter("location_offset_hcenter") - , location_offset_vcenter("location_offset_vcenter") - , location_percent_hcenter("location_percent_hcenter") - , location_percent_vcenter("location_percent_vcenter") - , padding_horiz("padding_horiz") - , padding_vert("padding_vert") + : image("image") + , border_image("border_image") + , border_color("border_color") + , image_color("image_color") + , label("label") + , label_color("label_color") + , label_offset_horiz("label_offset_horiz") + , label_offset_vert("label_offset_vert") + , location("location", LLRelPos::TOP_LEFT) + , location_offset_hcenter("location_offset_hcenter") + , location_offset_vcenter("location_offset_vcenter") + , location_percent_hcenter("location_percent_hcenter") + , location_percent_vcenter("location_percent_vcenter") + , padding_horiz("padding_horiz") + , padding_vert("padding_vert") {} bool LLBadge::Params::equals(const Params& a) const { - bool comp = true; - - // skip owner in comparison on purpose - - comp &= (border_image() == a.border_image()); - comp &= (border_color() == a.border_color()); - comp &= (image() == a.image()); - comp &= (image_color() == a.image_color()); - comp &= (label() == a.label()); - comp &= (label_color() == a.label_color()); - comp &= (label_offset_horiz() == a.label_offset_horiz()); - comp &= (label_offset_vert() == a.label_offset_vert()); - comp &= (location() == a.location()); - comp &= (location_offset_hcenter() == a.location_offset_hcenter()); - comp &= (location_offset_vcenter() == a.location_offset_vcenter()); - comp &= (location_percent_hcenter() == a.location_percent_hcenter()); - comp &= (location_percent_vcenter() == a.location_percent_vcenter()); - comp &= (padding_horiz() == a.padding_horiz()); - comp &= (padding_vert() == a.padding_vert()); - - return comp; + bool comp = true; + + // skip owner in comparison on purpose + + comp &= (border_image() == a.border_image()); + comp &= (border_color() == a.border_color()); + comp &= (image() == a.image()); + comp &= (image_color() == a.image_color()); + comp &= (label() == a.label()); + comp &= (label_color() == a.label_color()); + comp &= (label_offset_horiz() == a.label_offset_horiz()); + comp &= (label_offset_vert() == a.label_offset_vert()); + comp &= (location() == a.location()); + comp &= (location_offset_hcenter() == a.location_offset_hcenter()); + comp &= (location_offset_vcenter() == a.location_offset_vcenter()); + comp &= (location_percent_hcenter() == a.location_percent_hcenter()); + comp &= (location_percent_vcenter() == a.location_percent_vcenter()); + comp &= (padding_horiz() == a.padding_horiz()); + comp &= (padding_vert() == a.padding_vert()); + + return comp; } LLBadge::LLBadge(const LLBadge::Params& p) - : LLUICtrl(p) - , mOwner(p.owner) - , mBorderImage(p.border_image) - , mBorderColor(p.border_color) - , mGLFont(p.font) - , mImage(p.image) - , mImageColor(p.image_color) - , mLabel(p.label) - , mLabelColor(p.label_color) - , mLabelOffsetHoriz(p.label_offset_horiz) - , mLabelOffsetVert(p.label_offset_vert) - , mLocation(p.location) - , mLocationOffsetHCenter(BADGE_OFFSET_NOT_SPECIFIED) - , mLocationOffsetVCenter(BADGE_OFFSET_NOT_SPECIFIED) - , mLocationPercentHCenter(0.5f) - , mLocationPercentVCenter(0.5f) - , mPaddingHoriz(p.padding_horiz) - , mPaddingVert(p.padding_vert) - , mParentScroller(NULL) - , mDrawAtParentTop(false) + : LLUICtrl(p) + , mOwner(p.owner) + , mBorderImage(p.border_image) + , mBorderColor(p.border_color) + , mGLFont(p.font) + , mImage(p.image) + , mImageColor(p.image_color) + , mLabel(p.label) + , mLabelColor(p.label_color) + , mLabelOffsetHoriz(p.label_offset_horiz) + , mLabelOffsetVert(p.label_offset_vert) + , mLocation(p.location) + , mLocationOffsetHCenter(BADGE_OFFSET_NOT_SPECIFIED) + , mLocationOffsetVCenter(BADGE_OFFSET_NOT_SPECIFIED) + , mLocationPercentHCenter(0.5f) + , mLocationPercentVCenter(0.5f) + , mPaddingHoriz(p.padding_horiz) + , mPaddingVert(p.padding_vert) + , mParentScroller(NULL) + , mDrawAtParentTop(false) { - if (mImage.isNull()) - { - LL_WARNS() << "Badge: " << getName() << " with no image!" << LL_ENDL; - } - - if (p.location_offset_hcenter.isProvided()) - { - mLocationOffsetHCenter = p.location_offset_hcenter(); - } - - if (p.location_offset_vcenter.isProvided()) - { - mLocationOffsetVCenter = p.location_offset_vcenter(); - } - - // - // The following logic is to set the mLocationPercentHCenter and mLocationPercentVCenter - // based on the Location enum and our horizontal and vertical location percentages. The - // draw code then uses this on the owner rectangle to compute the screen location for - // the badge. - // - - if (!LLRelPos::IsCenter(mLocation)) - { - F32 h_center = p.location_percent_hcenter * 0.01f; - F32 v_center = p.location_percent_vcenter * 0.01f; - - if (LLRelPos::IsRight(mLocation)) - { - mLocationPercentHCenter = 0.5f * (1.0f + h_center); - } - else if (LLRelPos::IsLeft(mLocation)) - { - mLocationPercentHCenter = 0.5f * (1.0f - h_center); - } - - if (LLRelPos::IsTop(mLocation)) - { - mLocationPercentVCenter = 0.5f * (1.0f + v_center); - } - else if (LLRelPos::IsBottom(mLocation)) - { - mLocationPercentVCenter = 0.5f * (1.0f - v_center); - } - } + if (mImage.isNull()) + { + LL_WARNS() << "Badge: " << getName() << " with no image!" << LL_ENDL; + } + + if (p.location_offset_hcenter.isProvided()) + { + mLocationOffsetHCenter = p.location_offset_hcenter(); + } + + if (p.location_offset_vcenter.isProvided()) + { + mLocationOffsetVCenter = p.location_offset_vcenter(); + } + + // + // The following logic is to set the mLocationPercentHCenter and mLocationPercentVCenter + // based on the Location enum and our horizontal and vertical location percentages. The + // draw code then uses this on the owner rectangle to compute the screen location for + // the badge. + // + + if (!LLRelPos::IsCenter(mLocation)) + { + F32 h_center = p.location_percent_hcenter * 0.01f; + F32 v_center = p.location_percent_vcenter * 0.01f; + + if (LLRelPos::IsRight(mLocation)) + { + mLocationPercentHCenter = 0.5f * (1.0f + h_center); + } + else if (LLRelPos::IsLeft(mLocation)) + { + mLocationPercentHCenter = 0.5f * (1.0f - h_center); + } + + if (LLRelPos::IsTop(mLocation)) + { + mLocationPercentVCenter = 0.5f * (1.0f + v_center); + } + else if (LLRelPos::IsBottom(mLocation)) + { + mLocationPercentVCenter = 0.5f * (1.0f - v_center); + } + } } LLBadge::~LLBadge() @@ -157,28 +157,28 @@ LLBadge::~LLBadge() bool LLBadge::addToView(LLView * view) { - bool child_added = view->addChild(this); + bool child_added = view->addChild(this); - if (child_added) - { - setShape(view->getLocalRect()); + if (child_added) + { + setShape(view->getLocalRect()); - // Find a parent scroll container, if there is one in case we need it for positioning + // Find a parent scroll container, if there is one in case we need it for positioning - LLView * parent = mOwner.get(); + LLView * parent = mOwner.get(); - while ((parent != NULL) && ((mParentScroller = dynamic_cast<LLScrollContainer *>(parent)) == NULL)) - { - parent = parent->getParent(); - } - } + while ((parent != NULL) && ((mParentScroller = dynamic_cast<LLScrollContainer *>(parent)) == NULL)) + { + parent = parent->getParent(); + } + } - return child_added; + return child_added; } void LLBadge::setLabel(const LLStringExplicit& label) { - mLabel = label; + mLabel = label; } // @@ -186,203 +186,203 @@ void LLBadge::setLabel(const LLStringExplicit& label) // void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, const LLColor4U &color) { - gGL.pushUIMatrix(); - gGL.loadUIIdentity(); - gGL.setSceneBlendType(LLRender::BT_REPLACE); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - gGL.color4ubv(color.mV); - gGL.texCoord2i(0, 0); - - F32 x = LLFontGL::sCurOrigin.mX + centerX - width * 0.5f; - F32 y = LLFontGL::sCurOrigin.mY + centerY - height * 0.5f; - - LLRectf screen_rect(ll_round(x), - ll_round(y), - ll_round(x) + width, - ll_round(y) + height); - - LLVector3 vertices[4]; - vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f); - vertices[1] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f); - vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f); - vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f); - - gGL.begin(LLRender::QUADS); - { - gGL.vertexBatchPreTransformed(vertices, 4); - } - gGL.end(); - - gGL.popUIMatrix(); + gGL.pushUIMatrix(); + gGL.loadUIIdentity(); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.color4ubv(color.mV); + gGL.texCoord2i(0, 0); + + F32 x = LLFontGL::sCurOrigin.mX + centerX - width * 0.5f; + F32 y = LLFontGL::sCurOrigin.mY + centerY - height * 0.5f; + + LLRectf screen_rect(ll_round(x), + ll_round(y), + ll_round(x) + width, + ll_round(y) + height); + + LLVector3 vertices[4]; + vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f); + vertices[1] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f); + vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f); + vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f); + + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, 4); + } + gGL.end(); + + gGL.popUIMatrix(); } // virtual void LLBadge::draw() { - if (!mLabel.empty()) - { - LLView* owner_view = mOwner.get(); - - if (owner_view && owner_view->isInVisibleChain()) - { - // - // Calculate badge size based on label text - // - - LLWString badge_label_wstring = mLabel; - - S32 badge_label_begin_offset = 0; - S32 badge_char_length = S32_MAX; - S32 badge_pixel_length = S32_MAX; - F32 *right_position_out = NULL; - BOOL do_not_use_ellipses = false; - - F32 badge_width = (2.0f * mPaddingHoriz) + - mGLFont->getWidthF32(badge_label_wstring.c_str(), badge_label_begin_offset, badge_char_length); - - F32 badge_height = (2.0f * mPaddingVert) + mGLFont->getLineHeight(); - - // - // Calculate badge position based on owner - // - - LLRect owner_rect; - owner_view->localRectToOtherView(owner_view->getLocalRect(), & owner_rect, this); - - S32 location_offset_horiz = mLocationOffsetHCenter; - S32 location_offset_vert = mLocationOffsetVCenter; - - // If we're in a scroll container, do some math to keep us in the same place on screen if applicable - if (mParentScroller != NULL) - { - LLRect visibleRect = mParentScroller->getVisibleContentRect(); - - if (mLocationOffsetHCenter != BADGE_OFFSET_NOT_SPECIFIED) - { - if (LLRelPos::IsRight(mLocation)) - { - location_offset_horiz += visibleRect.mRight; - } - else if (LLRelPos::IsLeft(mLocation)) - { - location_offset_horiz += visibleRect.mLeft; - } - else // center - { - location_offset_horiz += (visibleRect.mLeft + visibleRect.mRight) / 2; - } - } - - if (mLocationOffsetVCenter != BADGE_OFFSET_NOT_SPECIFIED) - { - if (LLRelPos::IsTop(mLocation)) - { - location_offset_vert += visibleRect.mTop; - } - else if (LLRelPos::IsBottom(mLocation)) - { - location_offset_vert += visibleRect.mBottom; - } - else // center - { - location_offset_vert += (visibleRect.mBottom + visibleRect.mTop) / 2; - } - } - } - - F32 badge_center_x; - F32 badge_center_y; - - // Compute x position - if (mLocationOffsetHCenter == BADGE_OFFSET_NOT_SPECIFIED) - { - badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter; - } - else - { - badge_center_x = location_offset_horiz; - } - - // Compute y position - if (mLocationOffsetVCenter == BADGE_OFFSET_NOT_SPECIFIED) - { - if(mDrawAtParentTop) - { - badge_center_y = owner_rect.mTop - badge_height * 0.5f - 1; - } - else - { - badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter; - } - } - else - { - badge_center_y = location_offset_vert; - } - - // - // Draw button image, if available. - // Otherwise draw basic rectangular button. - // - - F32 alpha = getDrawContext().mAlpha; - - if (!mImage.isNull()) - { - F32 badge_x = badge_center_x - badge_width * 0.5f; - F32 badge_y = badge_center_y - badge_height * 0.5f; - - mImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mImageColor % alpha); - - if (!mBorderImage.isNull()) - { - mBorderImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mBorderColor % alpha); - } - } - else - { - LL_DEBUGS() << "No image for badge " << getName() << " on owner " << owner_view->getName() << LL_ENDL; - - renderBadgeBackground(badge_center_x, badge_center_y, - badge_width, badge_height, - mImageColor % alpha); - } - - // - // Draw the label - // - - mGLFont->render(badge_label_wstring, - badge_label_begin_offset, - badge_center_x + mLabelOffsetHoriz, - badge_center_y + mLabelOffsetVert, - mLabelColor % alpha, - LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position - LLFontGL::NORMAL, // normal text (not bold, italics, etc.) - LLFontGL::DROP_SHADOW_SOFT, - badge_char_length, badge_pixel_length, - right_position_out, do_not_use_ellipses); - } - } + if (!mLabel.empty()) + { + LLView* owner_view = mOwner.get(); + + if (owner_view && owner_view->isInVisibleChain()) + { + // + // Calculate badge size based on label text + // + + LLWString badge_label_wstring = mLabel; + + S32 badge_label_begin_offset = 0; + S32 badge_char_length = S32_MAX; + S32 badge_pixel_length = S32_MAX; + F32 *right_position_out = NULL; + BOOL do_not_use_ellipses = false; + + F32 badge_width = (2.0f * mPaddingHoriz) + + mGLFont->getWidthF32(badge_label_wstring.c_str(), badge_label_begin_offset, badge_char_length); + + F32 badge_height = (2.0f * mPaddingVert) + mGLFont->getLineHeight(); + + // + // Calculate badge position based on owner + // + + LLRect owner_rect; + owner_view->localRectToOtherView(owner_view->getLocalRect(), & owner_rect, this); + + S32 location_offset_horiz = mLocationOffsetHCenter; + S32 location_offset_vert = mLocationOffsetVCenter; + + // If we're in a scroll container, do some math to keep us in the same place on screen if applicable + if (mParentScroller != NULL) + { + LLRect visibleRect = mParentScroller->getVisibleContentRect(); + + if (mLocationOffsetHCenter != BADGE_OFFSET_NOT_SPECIFIED) + { + if (LLRelPos::IsRight(mLocation)) + { + location_offset_horiz += visibleRect.mRight; + } + else if (LLRelPos::IsLeft(mLocation)) + { + location_offset_horiz += visibleRect.mLeft; + } + else // center + { + location_offset_horiz += (visibleRect.mLeft + visibleRect.mRight) / 2; + } + } + + if (mLocationOffsetVCenter != BADGE_OFFSET_NOT_SPECIFIED) + { + if (LLRelPos::IsTop(mLocation)) + { + location_offset_vert += visibleRect.mTop; + } + else if (LLRelPos::IsBottom(mLocation)) + { + location_offset_vert += visibleRect.mBottom; + } + else // center + { + location_offset_vert += (visibleRect.mBottom + visibleRect.mTop) / 2; + } + } + } + + F32 badge_center_x; + F32 badge_center_y; + + // Compute x position + if (mLocationOffsetHCenter == BADGE_OFFSET_NOT_SPECIFIED) + { + badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter; + } + else + { + badge_center_x = location_offset_horiz; + } + + // Compute y position + if (mLocationOffsetVCenter == BADGE_OFFSET_NOT_SPECIFIED) + { + if(mDrawAtParentTop) + { + badge_center_y = owner_rect.mTop - badge_height * 0.5f - 1; + } + else + { + badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter; + } + } + else + { + badge_center_y = location_offset_vert; + } + + // + // Draw button image, if available. + // Otherwise draw basic rectangular button. + // + + F32 alpha = getDrawContext().mAlpha; + + if (!mImage.isNull()) + { + F32 badge_x = badge_center_x - badge_width * 0.5f; + F32 badge_y = badge_center_y - badge_height * 0.5f; + + mImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mImageColor % alpha); + + if (!mBorderImage.isNull()) + { + mBorderImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mBorderColor % alpha); + } + } + else + { + LL_DEBUGS() << "No image for badge " << getName() << " on owner " << owner_view->getName() << LL_ENDL; + + renderBadgeBackground(badge_center_x, badge_center_y, + badge_width, badge_height, + mImageColor % alpha); + } + + // + // Draw the label + // + + mGLFont->render(badge_label_wstring, + badge_label_begin_offset, + badge_center_x + mLabelOffsetHoriz, + badge_center_y + mLabelOffsetVert, + mLabelColor % alpha, + LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position + LLFontGL::NORMAL, // normal text (not bold, italics, etc.) + LLFontGL::DROP_SHADOW_SOFT, + badge_char_length, badge_pixel_length, + right_position_out, do_not_use_ellipses); + } + } } namespace LLInitParam { - void TypeValues<LLRelPos::Location>::declareValues() - { - declare("bottom", LLRelPos::BOTTOM); - declare("bottom_left", LLRelPos::BOTTOM_LEFT); - declare("bottom_right", LLRelPos::BOTTOM_RIGHT); - declare("center", LLRelPos::CENTER); - declare("left", LLRelPos::LEFT); - declare("right", LLRelPos::RIGHT); - declare("top", LLRelPos::TOP); - declare("top_left", LLRelPos::TOP_LEFT); - declare("top_right", LLRelPos::TOP_RIGHT); - } + void TypeValues<LLRelPos::Location>::declareValues() + { + declare("bottom", LLRelPos::BOTTOM); + declare("bottom_left", LLRelPos::BOTTOM_LEFT); + declare("bottom_right", LLRelPos::BOTTOM_RIGHT); + declare("center", LLRelPos::CENTER); + declare("left", LLRelPos::LEFT); + declare("right", LLRelPos::RIGHT); + declare("top", LLRelPos::TOP); + declare("top_left", LLRelPos::TOP_LEFT); + declare("top_right", LLRelPos::TOP_RIGHT); + } } diff --git a/indra/llui/llbadge.h b/indra/llui/llbadge.h index 55f92e6e34..59296ffe86 100644 --- a/indra/llui/llbadge.h +++ b/indra/llui/llbadge.h @@ -1,25 +1,25 @@ -/** +/** * @file llbadge.h * @brief Header for badges * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,38 +49,38 @@ class LLUICtrlFactory; namespace LLRelPos { - enum Location - { - CENTER = 0, + enum Location + { + CENTER = 0, - LEFT = (1 << 0), - RIGHT = (1 << 1), + LEFT = (1 << 0), + RIGHT = (1 << 1), - TOP = (1 << 2), - BOTTOM = (1 << 3), + TOP = (1 << 2), + BOTTOM = (1 << 3), - BOTTOM_LEFT = (BOTTOM | LEFT), - BOTTOM_RIGHT = (BOTTOM | RIGHT), + BOTTOM_LEFT = (BOTTOM | LEFT), + BOTTOM_RIGHT = (BOTTOM | RIGHT), - TOP_LEFT = (TOP | LEFT), - TOP_RIGHT = (TOP | RIGHT), - }; + TOP_LEFT = (TOP | LEFT), + TOP_RIGHT = (TOP | RIGHT), + }; - inline bool IsBottom(Location relPos) { return (relPos & BOTTOM) == BOTTOM; } - inline bool IsCenter(Location relPos) { return (relPos == CENTER); } - inline bool IsLeft(Location relPos) { return (relPos & LEFT) == LEFT; } - inline bool IsRight(Location relPos) { return (relPos & RIGHT) == RIGHT; } - inline bool IsTop(Location relPos) { return (relPos & TOP) == TOP; } + inline bool IsBottom(Location relPos) { return (relPos & BOTTOM) == BOTTOM; } + inline bool IsCenter(Location relPos) { return (relPos == CENTER); } + inline bool IsLeft(Location relPos) { return (relPos & LEFT) == LEFT; } + inline bool IsRight(Location relPos) { return (relPos & RIGHT) == RIGHT; } + inline bool IsTop(Location relPos) { return (relPos & TOP) == TOP; } } // NOTE: This needs to occur before Optional<LLRelPos::Location> declaration for proper compilation. namespace LLInitParam { - template<> - struct TypeValues<LLRelPos::Location> : public TypeValuesHelper<LLRelPos::Location> - { - static void declareValues(); - }; + template<> + struct TypeValues<LLRelPos::Location> : public TypeValuesHelper<LLRelPos::Location> + { + static void declareValues(); + }; } // @@ -91,82 +91,82 @@ class LLBadge : public LLUICtrl { public: - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional< LLHandle<LLView> > owner; // Mandatory in code but not in xml - - Optional< LLUIImage* > border_image; - Optional< LLUIColor > border_color; - - Optional< LLUIImage* > image; - Optional< LLUIColor > image_color; - - Optional< std::string > label; - Optional< LLUIColor > label_color; - - Optional< S32 > label_offset_horiz; - Optional< S32 > label_offset_vert; - - Optional< LLRelPos::Location > location; - Optional< S32 > location_offset_hcenter; - Optional< S32 > location_offset_vcenter; - Optional< U32 > location_percent_hcenter; - Optional< U32 > location_percent_vcenter; - - Optional< F32 > padding_horiz; - Optional< F32 > padding_vert; - - Params(); - - bool equals(const Params&) const; - }; - + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional< LLHandle<LLView> > owner; // Mandatory in code but not in xml + + Optional< LLUIImage* > border_image; + Optional< LLUIColor > border_color; + + Optional< LLUIImage* > image; + Optional< LLUIColor > image_color; + + Optional< std::string > label; + Optional< LLUIColor > label_color; + + Optional< S32 > label_offset_horiz; + Optional< S32 > label_offset_vert; + + Optional< LLRelPos::Location > location; + Optional< S32 > location_offset_hcenter; + Optional< S32 > location_offset_vcenter; + Optional< U32 > location_percent_hcenter; + Optional< U32 > location_percent_vcenter; + + Optional< F32 > padding_horiz; + Optional< F32 > padding_vert; + + Params(); + + bool equals(const Params&) const; + }; + protected: - friend class LLUICtrlFactory; - LLBadge(const Params& p); + friend class LLUICtrlFactory; + LLBadge(const Params& p); public: - ~LLBadge(); + ~LLBadge(); - bool addToView(LLView * view); + bool addToView(LLView * view); - virtual void draw(); + virtual void draw(); - const std::string getLabel() const { return wstring_to_utf8str(mLabel); } - void setLabel( const LLStringExplicit& label); + const std::string getLabel() const { return wstring_to_utf8str(mLabel); } + void setLabel( const LLStringExplicit& label); - void setDrawAtParentTop(bool draw_at_top) { mDrawAtParentTop = draw_at_top;} + void setDrawAtParentTop(bool draw_at_top) { mDrawAtParentTop = draw_at_top;} private: - LLPointer< LLUIImage > mBorderImage; - LLUIColor mBorderColor; - - const LLFontGL* mGLFont; - - LLPointer< LLUIImage > mImage; - LLUIColor mImageColor; - - LLUIString mLabel; - LLUIColor mLabelColor; - - S32 mLabelOffsetHoriz; - S32 mLabelOffsetVert; - - LLRelPos::Location mLocation; - S32 mLocationOffsetHCenter; - S32 mLocationOffsetVCenter; - F32 mLocationPercentHCenter; - F32 mLocationPercentVCenter; - - LLHandle< LLView > mOwner; - - F32 mPaddingHoriz; - F32 mPaddingVert; - - LLScrollContainer* mParentScroller; - bool mDrawAtParentTop; + LLPointer< LLUIImage > mBorderImage; + LLUIColor mBorderColor; + + const LLFontGL* mGLFont; + + LLPointer< LLUIImage > mImage; + LLUIColor mImageColor; + + LLUIString mLabel; + LLUIColor mLabelColor; + + S32 mLabelOffsetHoriz; + S32 mLabelOffsetVert; + + LLRelPos::Location mLocation; + S32 mLocationOffsetHCenter; + S32 mLocationOffsetVCenter; + F32 mLocationPercentHCenter; + F32 mLocationPercentVCenter; + + LLHandle< LLView > mOwner; + + F32 mPaddingHoriz; + F32 mPaddingVert; + + LLScrollContainer* mParentScroller; + bool mDrawAtParentTop; }; // Build time optimization, generate once in .cpp file diff --git a/indra/llui/llbadgeholder.cpp b/indra/llui/llbadgeholder.cpp index 1f786f36ae..bc22969ab4 100644 --- a/indra/llui/llbadgeholder.cpp +++ b/indra/llui/llbadgeholder.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llbadgeholder.cpp * @brief Source for badge holders * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,14 +32,14 @@ bool LLBadgeHolder::addBadge(LLBadge * badge) { - bool badge_added = false; + bool badge_added = false; - LLView * this_view = dynamic_cast<LLView *>(this); + LLView * this_view = dynamic_cast<LLView *>(this); - if (this_view && mAcceptsBadge) - { - badge_added = badge->addToView(this_view); - } + if (this_view && mAcceptsBadge) + { + badge_added = badge->addToView(this_view); + } - return badge_added; + return badge_added; } diff --git a/indra/llui/llbadgeholder.h b/indra/llui/llbadgeholder.h index 2538eaae91..470baf7a9a 100644 --- a/indra/llui/llbadgeholder.h +++ b/indra/llui/llbadgeholder.h @@ -1,25 +1,25 @@ -/** +/** * @file llbadgeholder.h * @brief Header for badge holders * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,19 +37,19 @@ class LLBadgeHolder { public: - LLBadgeHolder(bool acceptsBadge) - : mAcceptsBadge(acceptsBadge) - { - } + LLBadgeHolder(bool acceptsBadge) + : mAcceptsBadge(acceptsBadge) + { + } - void setAcceptsBadge(bool acceptsBadge) { mAcceptsBadge = acceptsBadge; } - bool acceptsBadge() const { return mAcceptsBadge; } + void setAcceptsBadge(bool acceptsBadge) { mAcceptsBadge = acceptsBadge; } + bool acceptsBadge() const { return mAcceptsBadge; } - virtual bool addBadge(LLBadge * badge); + virtual bool addBadge(LLBadge * badge); private: - bool mAcceptsBadge; + bool mAcceptsBadge; }; diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp index 5f11c383ef..3194a4b56f 100644 --- a/indra/llui/llbadgeowner.cpp +++ b/indra/llui/llbadgeowner.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llbadgeowner.cpp * @brief Class to manage badges attached to a UI control * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,86 +35,86 @@ // LLBadgeOwner::LLBadgeOwner(LLHandle< LLView > viewHandle) - : mHasBadgeHolderParent(false), - mBadge(NULL), - mBadgeOwnerView(viewHandle) + : mHasBadgeHolderParent(false), + mBadge(NULL), + mBadgeOwnerView(viewHandle) { } void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p) { - if (!p.equals(LLUICtrlFactory::getDefaultParams<LLBadge>())) - { - mBadge = createBadge(p); - mHasBadgeHolderParent = false; - - LLView * owner_view = mBadgeOwnerView.get(); - if (owner_view) - { - mBadge->addToView(owner_view); - } - } + if (!p.equals(LLUICtrlFactory::getDefaultParams<LLBadge>())) + { + mBadge = createBadge(p); + mHasBadgeHolderParent = false; + + LLView * owner_view = mBadgeOwnerView.get(); + if (owner_view) + { + mBadge->addToView(owner_view); + } + } } void LLBadgeOwner::reshapeBadge(const LLRect& new_rect) { - if (mBadge) - { - mBadge->setShape(new_rect); - } + if (mBadge) + { + mBadge->setShape(new_rect); + } } void LLBadgeOwner::setBadgeVisibility(bool visible) { - if (mBadge) - { - mBadge->setVisible(visible); - } + if (mBadge) + { + mBadge->setVisible(visible); + } } void LLBadgeOwner::setDrawBadgeAtTop(bool draw_at_top) { - if (mBadge) - { - mBadge->setDrawAtParentTop(draw_at_top); - } + if (mBadge) + { + mBadge->setDrawAtParentTop(draw_at_top); + } } void LLBadgeOwner::addBadgeToParentHolder() { - LLView * owner_view = mBadgeOwnerView.get(); - - if (mBadge && owner_view) - { - LLBadgeHolder * badge_holder = NULL; - - // Find the appropriate holder for the badge - LLView * parent = owner_view->getParent(); - - while (parent) - { - LLBadgeHolder * badge_holder_panel = dynamic_cast<LLBadgeHolder *>(parent); - - if (badge_holder_panel && badge_holder_panel->acceptsBadge()) - { - badge_holder = badge_holder_panel; - break; - } - - parent = parent->getParent(); - } - - if (badge_holder) - { - mHasBadgeHolderParent = badge_holder->addBadge(mBadge); - } - } + LLView * owner_view = mBadgeOwnerView.get(); + + if (mBadge && owner_view) + { + LLBadgeHolder * badge_holder = NULL; + + // Find the appropriate holder for the badge + LLView * parent = owner_view->getParent(); + + while (parent) + { + LLBadgeHolder * badge_holder_panel = dynamic_cast<LLBadgeHolder *>(parent); + + if (badge_holder_panel && badge_holder_panel->acceptsBadge()) + { + badge_holder = badge_holder_panel; + break; + } + + parent = parent->getParent(); + } + + if (badge_holder) + { + mHasBadgeHolderParent = badge_holder->addBadge(mBadge); + } + } } LLBadge* LLBadgeOwner::createBadge(const LLBadge::Params& p) { - LLBadge::Params badge_params(p); - badge_params.owner = mBadgeOwnerView; + LLBadge::Params badge_params(p); + badge_params.owner = mBadgeOwnerView; - return LLUICtrlFactory::create<LLBadge>(badge_params); + return LLUICtrlFactory::create<LLBadge>(badge_params); } diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h index 4ce208fa0d..d2ac17cef0 100644 --- a/indra/llui/llbadgeowner.h +++ b/indra/llui/llbadgeowner.h @@ -1,25 +1,25 @@ -/** +/** * @file llbadgeowner.h * @brief Header for badge owners * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,24 +38,24 @@ class LLBadgeOwner { public: - LLBadgeOwner(LLHandle< LLView > viewHandle); + LLBadgeOwner(LLHandle< LLView > viewHandle); + + void initBadgeParams(const LLBadge::Params& p); + void addBadgeToParentHolder(); - void initBadgeParams(const LLBadge::Params& p); - void addBadgeToParentHolder(); - - bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; }; - void setBadgeVisibility(bool visible); - void setDrawBadgeAtTop(bool draw_at_top); - void reshapeBadge(const LLRect& new_rect); + bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; }; + void setBadgeVisibility(bool visible); + void setDrawBadgeAtTop(bool draw_at_top); + void reshapeBadge(const LLRect& new_rect); private: - LLBadge* createBadge(const LLBadge::Params& p); + LLBadge* createBadge(const LLBadge::Params& p); private: - bool mHasBadgeHolderParent; - LLBadge* mBadge; - LLHandle< LLView > mBadgeOwnerView; + bool mHasBadgeHolderParent; + LLBadge* mBadge; + LLHandle< LLView > mBadgeOwnerView; }; #endif // LL_LLBADGEOWNER_H diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 9ef019840a..16b58dcc5b 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llbutton.cpp * @brief LLButton base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -56,931 +56,932 @@ static LLDefaultChildRegistry::Register<LLButton> r("button"); // Compiler optimization, generate extern template template class LLButton* LLView::getChild<class LLButton>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; -// globals loaded from settings.xml -S32 LLBUTTON_H_PAD = 0; -S32 BTN_HEIGHT_SMALL= 0; -S32 BTN_HEIGHT = 0; +// globals +S32 LLBUTTON_H_PAD = 4; +S32 BTN_HEIGHT_SMALL= 23; +S32 BTN_HEIGHT = 23; +S32 BTN_DROP_SHADOW = 2; LLButton::Params::Params() -: label_selected("label_selected"), // requires is_toggle true - label_shadow("label_shadow", true), - auto_resize("auto_resize", false), - use_ellipses("use_ellipses", false), - use_font_color("use_font_color", true), - image_unselected("image_unselected"), - image_selected("image_selected"), - image_hover_selected("image_hover_selected"), - image_hover_unselected("image_hover_unselected"), - image_disabled_selected("image_disabled_selected"), - image_disabled("image_disabled"), - image_pressed("image_pressed"), - image_pressed_selected("image_pressed_selected"), - image_overlay("image_overlay"), - image_overlay_alignment("image_overlay_alignment", std::string("center")), - 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"), - label_color_disabled_selected("label_color_disabled_selected"), - image_color("image_color"), - image_color_disabled("image_color_disabled"), - image_overlay_color("image_overlay_color", LLColor4::white % 0.75f), - image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), - image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), - flash_color("flash_color"), - pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), - pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")), - pad_bottom("pad_bottom"), - click_callback("click_callback"), - mouse_down_callback("mouse_down_callback"), - mouse_up_callback("mouse_up_callback"), - mouse_held_callback("mouse_held_callback"), - is_toggle("is_toggle", false), - scale_image("scale_image", true), - hover_glow_amount("hover_glow_amount"), - commit_on_return("commit_on_return", true), +: label_selected("label_selected"), // requires is_toggle true + label_shadow("label_shadow", true), + auto_resize("auto_resize", false), + use_ellipses("use_ellipses", false), + use_font_color("use_font_color", true), + image_unselected("image_unselected"), + image_selected("image_selected"), + image_hover_selected("image_hover_selected"), + image_hover_unselected("image_hover_unselected"), + image_disabled_selected("image_disabled_selected"), + image_disabled("image_disabled"), + image_pressed("image_pressed"), + image_pressed_selected("image_pressed_selected"), + image_overlay("image_overlay"), + image_overlay_alignment("image_overlay_alignment", std::string("center")), + 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"), + label_color_disabled_selected("label_color_disabled_selected"), + image_color("image_color"), + image_color_disabled("image_color_disabled"), + image_overlay_color("image_overlay_color", LLColor4::white % 0.75f), + image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), + image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), + flash_color("flash_color"), + pad_right("pad_right", LLBUTTON_H_PAD), + pad_left("pad_left", LLBUTTON_H_PAD), + pad_bottom("pad_bottom"), + click_callback("click_callback"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + mouse_held_callback("mouse_held_callback"), + is_toggle("is_toggle", false), + scale_image("scale_image", true), + hover_glow_amount("hover_glow_amount"), + commit_on_return("commit_on_return", true), commit_on_capture_lost("commit_on_capture_lost", false), - display_pressed_state("display_pressed_state", true), - use_draw_context_alpha("use_draw_context_alpha", true), - badge("badge"), - handle_right_mouse("handle_right_mouse"), - held_down_delay("held_down_delay"), - button_flash_enable("button_flash_enable", false), - button_flash_count("button_flash_count"), - button_flash_rate("button_flash_rate") + display_pressed_state("display_pressed_state", true), + use_draw_context_alpha("use_draw_context_alpha", true), + badge("badge"), + handle_right_mouse("handle_right_mouse"), + held_down_delay("held_down_delay"), + button_flash_enable("button_flash_enable", false), + button_flash_count("button_flash_count"), + button_flash_rate("button_flash_rate") { - addSynonym(is_toggle, "toggle"); - changeDefault(initial_value, LLSD(false)); + addSynonym(is_toggle, "toggle"); + changeDefault(initial_value, LLSD(false)); } LLButton::LLButton(const LLButton::Params& p) -: LLUICtrl(p), - LLBadgeOwner(getHandle()), - mMouseDownFrame(0), - mMouseHeldDownCount(0), - mBorderEnabled( FALSE ), - mFlashing( FALSE ), - mCurGlowStrength(0.f), - mNeedsHighlight(FALSE), - mUnselectedLabel(p.label()), - mSelectedLabel(p.label_selected()), - mGLFont(p.font), - mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called - mHeldDownFrameDelay(p.held_down_delay.frames), - mImageUnselected(p.image_unselected), - mImageSelected(p.image_selected), - mImageDisabled(p.image_disabled), - mImageDisabledSelected(p.image_disabled_selected), - mImageFlash(p.image_flash), - mImagePressed(p.image_pressed), - mImagePressedSelected(p.image_pressed_selected), - mImageHoverSelected(p.image_hover_selected), - mImageHoverUnselected(p.image_hover_unselected), - mUnselectedLabelColor(p.label_color()), - mSelectedLabelColor(p.label_color_selected()), - mDisabledLabelColor(p.label_color_disabled()), - mDisabledSelectedLabelColor(p.label_color_disabled_selected()), - mImageColor(p.image_color()), - mFlashBgColor(p.flash_color()), - mDisabledImageColor(p.image_color_disabled()), - mImageOverlay(p.image_overlay()), - mImageOverlayColor(p.image_overlay_color()), - mImageOverlayDisabledColor(p.image_overlay_disabled_color()), - mImageOverlaySelectedColor(p.image_overlay_selected_color()), - mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), - 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), - mAutoResize(p.auto_resize), - mUseEllipses( p.use_ellipses ), - mUseFontColor( p.use_font_color), - mHAlign(p.font_halign), - mLeftHPad(p.pad_left), - mRightHPad(p.pad_right), - mBottomVPad(p.pad_bottom), - mHoverGlowStrength(p.hover_glow_amount), - mCommitOnReturn(p.commit_on_return), +: LLUICtrl(p), + LLBadgeOwner(getHandle()), + mMouseDownFrame(0), + mMouseHeldDownCount(0), + mBorderEnabled( FALSE ), + mFlashing( FALSE ), + mCurGlowStrength(0.f), + mNeedsHighlight(FALSE), + mUnselectedLabel(p.label()), + mSelectedLabel(p.label_selected()), + mGLFont(p.font), + mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called + mHeldDownFrameDelay(p.held_down_delay.frames), + mImageUnselected(p.image_unselected), + mImageSelected(p.image_selected), + mImageDisabled(p.image_disabled), + mImageDisabledSelected(p.image_disabled_selected), + mImageFlash(p.image_flash), + mImagePressed(p.image_pressed), + mImagePressedSelected(p.image_pressed_selected), + mImageHoverSelected(p.image_hover_selected), + mImageHoverUnselected(p.image_hover_unselected), + mUnselectedLabelColor(p.label_color()), + mSelectedLabelColor(p.label_color_selected()), + mDisabledLabelColor(p.label_color_disabled()), + mDisabledSelectedLabelColor(p.label_color_disabled_selected()), + mImageColor(p.image_color()), + mFlashBgColor(p.flash_color()), + mDisabledImageColor(p.image_color_disabled()), + mImageOverlay(p.image_overlay()), + mImageOverlayColor(p.image_overlay_color()), + mImageOverlayDisabledColor(p.image_overlay_disabled_color()), + mImageOverlaySelectedColor(p.image_overlay_selected_color()), + mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), + 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), + mAutoResize(p.auto_resize), + mUseEllipses( p.use_ellipses ), + mUseFontColor( p.use_font_color), + mHAlign(p.font_halign), + mLeftHPad(p.pad_left), + mRightHPad(p.pad_right), + mBottomVPad(p.pad_bottom), + mHoverGlowStrength(p.hover_glow_amount), + mCommitOnReturn(p.commit_on_return), mCommitOnCaptureLost(p.commit_on_capture_lost), - mFadeWhenDisabled(FALSE), - mForcePressedState(false), - mDisplayPressedState(p.display_pressed_state), - mLastDrawCharsCount(0), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mHeldDownSignal(NULL), - mUseDrawContextAlpha(p.use_draw_context_alpha), - mHandleRightMouse(p.handle_right_mouse), - mFlashingTimer(NULL) -{ - if (p.button_flash_enable) - { - // If optional parameter "p.button_flash_count" is not provided, LLFlashTimer will be - // used instead it a "default" value from gSavedSettings.getS32("FlashCount")). - // Likewise, missing "p.button_flash_rate" is replaced by gSavedSettings.getF32("FlashPeriod"). - // Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing"). - S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0; - F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0; - mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate); - } - else - { - mButtonFlashCount = p.button_flash_count; - mButtonFlashRate = p.button_flash_rate; - } - - static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0); - static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>()); - - if (!p.label_selected.isProvided()) - { - mSelectedLabel = mUnselectedLabel; - } - - // Hack to make sure there is space for at least one character - if (getRect().mRight >= 0 && getRect().getWidth() > 0 && - getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) - { - // Use old defaults - mLeftHPad = llbutton_orig_h_pad; - mRightHPad = llbutton_orig_h_pad; - } - - mMouseDownTimer.stop(); - - // if custom unselected button image provided... - if (p.image_unselected != default_params.image_unselected) - { - //...fade it out for disabled image by default... - if (p.image_disabled() == default_params.image_disabled() ) - { - mImageDisabled = p.image_unselected; - mFadeWhenDisabled = TRUE; - } - - if (p.image_pressed_selected == default_params.image_pressed_selected) - { - mImagePressedSelected = mImageUnselected; - } - } - - // if custom selected button image provided... - if (p.image_selected != default_params.image_selected) - { - //...fade it out for disabled image by default... - if (p.image_disabled_selected() == default_params.image_disabled_selected()) - { - mImageDisabledSelected = p.image_selected; - mFadeWhenDisabled = TRUE; - } - - if (p.image_pressed == default_params.image_pressed) - { - mImagePressed = mImageSelected; - } - } - - if (!p.image_pressed.isProvided()) - { - mImagePressed = mImageSelected; - } - - if (!p.image_pressed_selected.isProvided()) - { - mImagePressedSelected = mImageUnselected; - } - - if (mImageUnselected.isNull()) - { - LL_WARNS() << "Button: " << getName() << " with no image!" << LL_ENDL; - } - - if (p.click_callback.isProvided()) - { - setCommitCallback(initCommitCallback(p.click_callback)); // alias -> commit_callback - } - if (p.mouse_down_callback.isProvided()) - { - setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); - } - if (p.mouse_up_callback.isProvided()) - { - setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); - } - if (p.mouse_held_callback.isProvided()) - { - setHeldDownCallback(initCommitCallback(p.mouse_held_callback)); - } - - if (p.badge.isProvided()) - { - LLBadgeOwner::initBadgeParams(p.badge()); - } + mFadeWhenDisabled(FALSE), + mForcePressedState(false), + mDisplayPressedState(p.display_pressed_state), + mLastDrawCharsCount(0), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mHeldDownSignal(NULL), + mUseDrawContextAlpha(p.use_draw_context_alpha), + mHandleRightMouse(p.handle_right_mouse), + mFlashingTimer(NULL) +{ + if (p.button_flash_enable) + { + // If optional parameter "p.button_flash_count" is not provided, LLFlashTimer will be + // used instead it a "default" value from gSavedSettings.getS32("FlashCount")). + // Likewise, missing "p.button_flash_rate" is replaced by gSavedSettings.getF32("FlashPeriod"). + // Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing"). + S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0; + F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0; + mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate); + } + else + { + mButtonFlashCount = p.button_flash_count; + mButtonFlashRate = p.button_flash_rate; + } + + static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0); + static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>()); + + if (!p.label_selected.isProvided()) + { + mSelectedLabel = mUnselectedLabel; + } + + // Hack to make sure there is space for at least one character + if (getRect().mRight >= 0 && getRect().getWidth() > 0 && + getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) + { + // Use old defaults + mLeftHPad = llbutton_orig_h_pad; + mRightHPad = llbutton_orig_h_pad; + } + + mMouseDownTimer.stop(); + + // if custom unselected button image provided... + if (p.image_unselected != default_params.image_unselected) + { + //...fade it out for disabled image by default... + if (p.image_disabled() == default_params.image_disabled() ) + { + mImageDisabled = p.image_unselected; + mFadeWhenDisabled = TRUE; + } + + if (p.image_pressed_selected == default_params.image_pressed_selected) + { + mImagePressedSelected = mImageUnselected; + } + } + + // if custom selected button image provided... + if (p.image_selected != default_params.image_selected) + { + //...fade it out for disabled image by default... + if (p.image_disabled_selected() == default_params.image_disabled_selected()) + { + mImageDisabledSelected = p.image_selected; + mFadeWhenDisabled = TRUE; + } + + if (p.image_pressed == default_params.image_pressed) + { + mImagePressed = mImageSelected; + } + } + + if (!p.image_pressed.isProvided()) + { + mImagePressed = mImageSelected; + } + + if (!p.image_pressed_selected.isProvided()) + { + mImagePressedSelected = mImageUnselected; + } + + if (mImageUnselected.isNull()) + { + LL_WARNS() << "Button: " << getName() << " with no image!" << LL_ENDL; + } + + if (p.click_callback.isProvided()) + { + setCommitCallback(initCommitCallback(p.click_callback)); // alias -> commit_callback + } + if (p.mouse_down_callback.isProvided()) + { + setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); + } + if (p.mouse_up_callback.isProvided()) + { + setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); + } + if (p.mouse_held_callback.isProvided()) + { + setHeldDownCallback(initCommitCallback(p.mouse_held_callback)); + } + + if (p.badge.isProvided()) + { + LLBadgeOwner::initBadgeParams(p.badge()); + } } LLButton::~LLButton() { - delete mMouseDownSignal; - delete mMouseUpSignal; - delete mHeldDownSignal; + delete mMouseDownSignal; + delete mMouseUpSignal; + delete mHeldDownSignal; - if (mFlashingTimer) - { - mFlashingTimer->unset(); - } + if (mFlashingTimer) + { + mFlashingTimer->unset(); + } } // HACK: Committing a button is the same as instantly clicking it. // virtual void LLButton::onCommit() { - // WARNING: Sometimes clicking a button destroys the floater or - // panel containing it. Therefore we need to call LLUICtrl::onCommit() - // LAST, otherwise this becomes deleted memory. + // WARNING: Sometimes clicking a button destroys the floater or + // panel containing it. Therefore we need to call LLUICtrl::onCommit() + // LAST, otherwise this becomes deleted memory. - if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); - - if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } + if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } - if (mIsToggle) - { - toggleState(); - } + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } - // do this last, as it can result in destroying this button - LLUICtrl::onCommit(); + if (mIsToggle) + { + toggleState(); + } + + // do this last, as it can result in destroying this button + LLUICtrl::onCommit(); } boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) { - return setClickedCallback(initCommitCallback(cb)); + return setClickedCallback(initCommitCallback(cb)); } boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb) { - return setMouseDownCallback(initCommitCallback(cb)); + return setMouseDownCallback(initCommitCallback(cb)); } boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb) { - return setMouseUpCallback(initCommitCallback(cb)); + return setMouseUpCallback(initCommitCallback(cb)); } boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) { - return setHeldDownCallback(initCommitCallback(cb)); + return setHeldDownCallback(initCommitCallback(cb)); } boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) { - if (!mCommitSignal) mCommitSignal = new commit_signal_t(); - return mCommitSignal->connect(cb); + if (!mCommitSignal) mCommitSignal = new commit_signal_t(); + return mCommitSignal->connect(cb); } boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) { - if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); - return mMouseDownSignal->connect(cb); + if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); + return mMouseDownSignal->connect(cb); } boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb ) { - if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); - return mMouseUpSignal->connect(cb); + if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); + return mMouseUpSignal->connect(cb); } boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb ) { - if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t(); - return mHeldDownSignal->connect(cb); + if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t(); + return mHeldDownSignal->connect(cb); } // *TODO: Deprecate (for backwards compatibility only) boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) { - return setClickedCallback(boost::bind(cb, data)); + return setClickedCallback(boost::bind(cb, data)); } boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data ) { - return setMouseDownCallback(boost::bind(cb, data)); + return setMouseDownCallback(boost::bind(cb, data)); } boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data ) { - return setMouseUpCallback(boost::bind(cb, data)); + return setMouseUpCallback(boost::bind(cb, data)); } boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data ) { - return setHeldDownCallback(boost::bind(cb, data)); + return setHeldDownCallback(boost::bind(cb, data)); } BOOL LLButton::postBuild() { - autoResize(); + autoResize(); - addBadgeToParentHolder(); + addBadgeToParentHolder(); - return LLUICtrl::postBuild(); + return LLUICtrl::postBuild(); } BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) { - BOOL handled = FALSE; - if(' ' == uni_char - && !gKeyboard->getKeyRepeated(' ')) - { - if (mIsToggle) - { - toggleState(); - } + BOOL handled = FALSE; + if(' ' == uni_char + && !gKeyboard->getKeyRepeated(' ')) + { + if (mIsToggle) + { + toggleState(); + } + + LLUICtrl::onCommit(); - LLUICtrl::onCommit(); - - handled = TRUE; - } - return handled; + handled = TRUE; + } + return handled; } BOOL LLButton::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) - { - if (mIsToggle) - { - toggleState(); - } + BOOL handled = FALSE; + if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) + { + if (mIsToggle) + { + toggleState(); + } - handled = TRUE; + handled = TRUE; - LLUICtrl::onCommit(); - } - return handled; + LLUICtrl::onCommit(); + } + return handled; } BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) { - if (!childrenHandleMouseDown(x, y, mask)) - { - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); + if (!childrenHandleMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); - if (hasTabStop() && !getIsChrome()) - { - setFocus(TRUE); - } + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } + + if (!mFunctionName.empty()) + { + LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL; + LLUIUsage::instance().logCommand(mFunctionName); + LLUIUsage::instance().logControl(getPathname()); + } - if (!mFunctionName.empty()) - { - LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL; - LLUIUsage::instance().logCommand(mFunctionName); - LLUIUsage::instance().logControl(getPathname()); - } + /* + * ATTENTION! This call fires another mouse down callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseDownSignal(x, y, mask); + */ + LLUICtrl::handleMouseDown(x, y, mask); - /* - * ATTENTION! This call fires another mouse down callback. - * If you wish to remove this call emit that signal directly - * by calling LLUICtrl::mMouseDownSignal(x, y, mask); - */ - LLUICtrl::handleMouseDown(x, y, mask); + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); - if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); + mMouseDownTimer.start(); + mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseHeldDownCount = 0; - mMouseDownTimer.start(); - mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); - mMouseHeldDownCount = 0; - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } - } - return TRUE; + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } + return TRUE; } BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) { - // We only handle the click if the click both started and ended within us - if( hasMouseCapture() ) - { + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { // reset timers before focus change, to not cause // additional commits if mCommitOnCaptureLost. resetMouseDownTimer(); - // Always release the mouse - gFocusMgr.setMouseCapture( NULL ); - - /* - * ATTENTION! This call fires another mouse up callback. - * If you wish to remove this call emit that signal directly - * by calling LLUICtrl::mMouseUpSignal(x, y, mask); - */ - LLUICtrl::handleMouseUp(x, y, mask); - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); - - // Regardless of where mouseup occurs, handle callback - if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); - - // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. - // If mouseup in the widget, it's been clicked - if (pointInView(x, y)) - { - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } - - if (mIsToggle) - { - toggleState(); - } - - LLUICtrl::onCommit(); - } - } - else - { - childrenHandleMouseUp(x, y, mask); - } - - return TRUE; -} - -BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask)) - { - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - - if (hasTabStop() && !getIsChrome()) - { - setFocus(TRUE); - } - -// if (pointInView(x, y)) -// { -// } - // send the mouse down signal - LLUICtrl::handleRightMouseDown(x,y,mask); - // *TODO: Return result of LLUICtrl call above? Should defer to base class - // but this might change the mouse handling of existing buttons in a bad way - // if they are not mouse opaque. - } - - return TRUE; -} - -BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) -{ - if (mHandleRightMouse) - { - // We only handle the click if the click both started and ended within us - if( hasMouseCapture() ) - { - // Always release the mouse - gFocusMgr.setMouseCapture( NULL ); - - // if (pointInView(x, y)) - // { - // mRightMouseUpSignal(this, x,y,mask); - // } - } - else - { - childrenHandleRightMouseUp(x, y, mask); - } - - // send the mouse up signal - LLUICtrl::handleRightMouseUp(x,y,mask); - // *TODO: Return result of LLUICtrl call above? Should defer to base class - // but this might change the mouse handling of existing buttons in a bad way. - // if they are not mouse opaque. - } - return TRUE; + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + + /* + * ATTENTION! This call fires another mouse up callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseUpSignal(x, y, mask); + */ + LLUICtrl::handleMouseUp(x, y, mask); + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + + // Regardless of where mouseup occurs, handle callback + if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + + // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. + // If mouseup in the widget, it's been clicked + if (pointInView(x, y)) + { + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + if (mIsToggle) + { + toggleState(); + } + + LLUICtrl::onCommit(); + } + } + else + { + childrenHandleMouseUp(x, y, mask); + } + + return TRUE; +} + +BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } + +// if (pointInView(x, y)) +// { +// } + // send the mouse down signal + LLUICtrl::handleRightMouseDown(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way + // if they are not mouse opaque. + } + + return TRUE; +} + +BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse) + { + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + + // if (pointInView(x, y)) + // { + // mRightMouseUpSignal(this, x,y,mask); + // } + } + else + { + childrenHandleRightMouseUp(x, y, mask); + } + + // send the mouse up signal + LLUICtrl::handleRightMouseUp(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way. + // if they are not mouse opaque. + } + return TRUE; } void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) { - LLUICtrl::onMouseLeave(x, y, mask); + LLUICtrl::onMouseLeave(x, y, mask); - mNeedsHighlight = FALSE; + mNeedsHighlight = FALSE; } void LLButton::setHighlight(bool b) { - mNeedsHighlight = b; + mNeedsHighlight = b; } BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) { - if (isInEnabledChain() - && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) - mNeedsHighlight = TRUE; - - if (!childrenHandleHover(x, y, mask)) - { - if (mMouseDownTimer.getStarted()) - { - F32 elapsed = getHeldDownTime(); - if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) - { - LLSD param; - param["count"] = mMouseHeldDownCount++; - if (mHeldDownSignal) (*mHeldDownSignal)(this, param); - } - } - - // We only handle the click if the click both started and ended within us - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; - } - return TRUE; + if (isInEnabledChain() + && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) + mNeedsHighlight = TRUE; + + if (!childrenHandleHover(x, y, mask)) + { + if (mMouseDownTimer.getStarted()) + { + F32 elapsed = getHeldDownTime(); + if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + { + LLSD param; + param["count"] = mMouseHeldDownCount++; + if (mHeldDownSignal) (*mHeldDownSignal)(this, param); + } + } + + // We only handle the click if the click both started and ended within us + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; + } + return TRUE; } void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) { - overlay_width = mImageOverlay->getWidth(); - overlay_height = mImageOverlay->getHeight(); + overlay_width = mImageOverlay->getWidth(); + overlay_height = mImageOverlay->getHeight(); - F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); - overlay_width = ll_round((F32)overlay_width * scale_factor); - overlay_height = ll_round((F32)overlay_height * scale_factor); + F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); + overlay_width = ll_round((F32)overlay_width * scale_factor); + overlay_height = ll_round((F32)overlay_height * scale_factor); } // virtual void LLButton::draw() { - static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true); - F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); - - bool pressed_by_keyboard = FALSE; - if (hasFocus()) - { - pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN)); - } - - bool mouse_pressed_and_over = false; - if (hasMouseCapture()) - { - S32 local_mouse_x ; - S32 local_mouse_y; - LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); - mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); - } - - bool enabled = isInEnabledChain(); - - bool pressed = pressed_by_keyboard - || mouse_pressed_and_over - || mForcePressedState; - bool selected = getToggleState(); - - bool use_glow_effect = FALSE; - LLColor4 highlighting_color = LLColor4::white; - LLColor4 glow_color = LLColor4::white; - LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; + static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true); + F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); + + bool pressed_by_keyboard = FALSE; + if (hasFocus()) + { + pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN)); + } + + bool mouse_pressed_and_over = false; + if (hasMouseCapture()) + { + S32 local_mouse_x ; + S32 local_mouse_y; + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); + } + + bool enabled = isInEnabledChain(); + + bool pressed = pressed_by_keyboard + || mouse_pressed_and_over + || mForcePressedState; + bool selected = getToggleState(); + + bool use_glow_effect = FALSE; + LLColor4 highlighting_color = LLColor4::white; + LLColor4 glow_color = LLColor4::white; + LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; LLUIImage* imagep = NULL; LLUIImage* image_glow = NULL; // Cancel sticking of color, if the button is pressed, - // or when a flashing of the previously selected button is ended - if (mFlashingTimer - && ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed)) - { - mFlashing = false; - } - - bool flash = mFlashing && sEnableButtonFlashing; - - if (pressed && mDisplayPressedState) - { - imagep = selected ? mImagePressedSelected : mImagePressed; - } - else if ( mNeedsHighlight ) - { - if (selected) - { - if (mImageHoverSelected) - { - imagep = mImageHoverSelected; - } - else - { - imagep = mImageSelected; - use_glow_effect = TRUE; - } - } - else - { - if (mImageHoverUnselected) - { - imagep = mImageHoverUnselected; - } - else - { - imagep = mImageUnselected; - use_glow_effect = TRUE; - } - } - } - else - { - imagep = selected ? mImageSelected : mImageUnselected; - } - - // Override if more data is available - // HACK: Use gray checked state to mean either: - // enabled and tentative - // or - // disabled but checked - if (!mImageDisabledSelected.isNull() - && - ( (enabled && getTentative()) - || (!enabled && selected ) ) ) - { - imagep = mImageDisabledSelected; - } - else if (!mImageDisabled.isNull() - && !enabled - && !selected) - { - imagep = mImageDisabled; - } - - image_glow = imagep; - - if (mFlashing) - { - if (flash && mImageFlash) - { - // if button should flash and we have icon for flashing, use it as image for button - image_glow = mImageFlash; - } - - // provide fade-in and fade-out via flash_color - if (mFlashingTimer) - { - LLColor4 flash_color = mFlashBgColor.get(); - use_glow_effect = TRUE; - glow_type = LLRender::BT_ALPHA; // blend the glow - - if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress()) - { - glow_color = flash_color; - } - else if (mNeedsHighlight) - { + // or when a flashing of the previously selected button is ended + if (mFlashingTimer + && ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed)) + { + mFlashing = false; + } + + bool flash = mFlashing && sEnableButtonFlashing; + + if (pressed && mDisplayPressedState) + { + imagep = selected ? mImagePressedSelected : mImagePressed; + } + else if ( mNeedsHighlight ) + { + if (selected) + { + if (mImageHoverSelected) + { + imagep = mImageHoverSelected; + } + else + { + imagep = mImageSelected; + use_glow_effect = TRUE; + } + } + else + { + if (mImageHoverUnselected) + { + imagep = mImageHoverUnselected; + } + else + { + imagep = mImageUnselected; + use_glow_effect = TRUE; + } + } + } + else + { + imagep = selected ? mImageSelected : mImageUnselected; + } + + // Override if more data is available + // HACK: Use gray checked state to mean either: + // enabled and tentative + // or + // disabled but checked + if (!mImageDisabledSelected.isNull() + && + ( (enabled && getTentative()) + || (!enabled && selected ) ) ) + { + imagep = mImageDisabledSelected; + } + else if (!mImageDisabled.isNull() + && !enabled + && !selected) + { + imagep = mImageDisabled; + } + + image_glow = imagep; + + if (mFlashing) + { + if (flash && mImageFlash) + { + // if button should flash and we have icon for flashing, use it as image for button + image_glow = mImageFlash; + } + + // provide fade-in and fade-out via flash_color + if (mFlashingTimer) + { + LLColor4 flash_color = mFlashBgColor.get(); + use_glow_effect = TRUE; + glow_type = LLRender::BT_ALPHA; // blend the glow + + if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress()) + { + glow_color = flash_color; + } + else if (mNeedsHighlight) + { glow_color = highlighting_color; - } + } else { // will fade from highlight color glow_color = flash_color; } - } - } - - if (mNeedsHighlight && !imagep) - { - use_glow_effect = TRUE; - } - - // Figure out appropriate color for the text - LLColor4 label_color; - - // label changes when button state changes, not when pressed - if ( enabled ) - { - if ( getToggleState() ) - { - label_color = mSelectedLabelColor.get(); - } - else - { - label_color = mUnselectedLabelColor.get(); - } - } - else - { - if ( getToggleState() ) - { - label_color = mDisabledSelectedLabelColor.get(); - } - else - { - label_color = mDisabledLabelColor.get(); - } - } - - // Highlight if needed - if( ll::ui::SearchableControl::getHighlighted() ) - label_color = ll::ui::SearchableControl::getHighlightColor(); - - // Unselected label assignments - LLWString label = getCurrentLabel(); - - // overlay with keyboard focus border - if (hasFocus()) - { - F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); - drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt))); - } - - if (use_glow_effect) - { - mCurGlowStrength = lerp(mCurGlowStrength, - mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.f : 0.f) : mHoverGlowStrength, - LLSmoothInterpolation::getInterpolant(0.05f)); - } - else - { - mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); - } - - // Draw button image, if available. - // Otherwise draw basic rectangular button. - if (imagep != NULL) - { - // apply automatic 50% alpha fade to disabled image - LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); - if ( mScaleImage) - { - imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha ); - if (mCurGlowStrength > 0.01f) - { - gGL.setSceneBlendType(glow_type); - image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - else - { - S32 y = getLocalRect().getHeight() - imagep->getHeight(); - imagep->draw(0, y, (enabled ? mImageColor.get() : disabled_color) % alpha); - if (mCurGlowStrength > 0.01f) - { - gGL.setSceneBlendType(glow_type); - image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - } - else - { - // no image - LL_DEBUGS() << "No image for button " << getName() << LL_ENDL; - // draw it in pink so we can find it - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE); - } - - // let overlay image and text play well together - S32 text_left = mLeftHPad; - S32 text_right = getRect().getWidth() - mRightHPad; - S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad; - - // draw overlay image - if (mImageOverlay.notNull()) - { - // get max width and height (discard level 0) - S32 overlay_width; - S32 overlay_height; - - getOverlayImageSize(overlay_width, overlay_height); - - S32 center_x = getLocalRect().getCenterX(); - S32 center_y = getLocalRect().getCenterY(); - - //FUGLY HACK FOR "DEPRESSED" BUTTONS - if (pressed && mDisplayPressedState) - { - center_y--; - center_x++; - } - - center_y += (mImageOverlayBottomPad - mImageOverlayTopPad); - // fade out overlay images on disabled buttons - LLColor4 overlay_color = mImageOverlayColor.get(); - if (!enabled) - { - overlay_color = mImageOverlayDisabledColor.get(); - } - else if (getToggleState()) - { - overlay_color = mImageOverlaySelectedColor.get(); - } - overlay_color.mV[VALPHA] *= alpha; - - switch(mImageOverlayAlignment) - { - case LLFontGL::LEFT: - text_left += overlay_width + mImgOverlayLabelSpace; - text_width -= overlay_width + mImgOverlayLabelSpace; - mImageOverlay->draw( - mLeftHPad, - center_y - (overlay_height / 2), - overlay_width, - overlay_height, - overlay_color); - break; - case LLFontGL::HCENTER: - mImageOverlay->draw( - center_x - (overlay_width / 2), - center_y - (overlay_height / 2), - overlay_width, - overlay_height, - overlay_color); - break; - case LLFontGL::RIGHT: - text_right -= overlay_width + mImgOverlayLabelSpace; - text_width -= overlay_width + mImgOverlayLabelSpace; - mImageOverlay->draw( - getRect().getWidth() - mRightHPad - overlay_width, - center_y - (overlay_height / 2), - overlay_width, - overlay_height, - overlay_color); - break; - default: - // draw nothing - break; - } - } - - // Draw label - if( !label.empty() ) - { - LLWStringUtil::trim(label); - - S32 x; - switch( mHAlign ) - { - case LLFontGL::RIGHT: - x = text_right; - break; - case LLFontGL::HCENTER: - x = text_left + (text_width / 2); - break; - case LLFontGL::LEFT: - default: - x = text_left; - break; - } - - if (pressed && mDisplayPressedState) - { - x++; - } - - // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as - // max_chars. - // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. - // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. - // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. - mLastDrawCharsCount = mGLFont->render(label, 0, - (F32)x, - (F32)(getRect().getHeight() / 2 + mBottomVPad), - label_color % alpha, - mHAlign, LLFontGL::VCENTER, - LLFontGL::NORMAL, - mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, - S32_MAX, text_width, - NULL, mUseEllipses, mUseFontColor); - } - - LLUICtrl::draw(); + } + } + + if (mNeedsHighlight && !imagep) + { + use_glow_effect = TRUE; + } + + // Figure out appropriate color for the text + LLColor4 label_color; + + // label changes when button state changes, not when pressed + if ( enabled ) + { + if ( getToggleState() ) + { + label_color = mSelectedLabelColor.get(); + } + else + { + label_color = mUnselectedLabelColor.get(); + } + } + else + { + if ( getToggleState() ) + { + label_color = mDisabledSelectedLabelColor.get(); + } + else + { + label_color = mDisabledLabelColor.get(); + } + } + + // Highlight if needed + if( ll::ui::SearchableControl::getHighlighted() ) + label_color = ll::ui::SearchableControl::getHighlightColor(); + + // Unselected label assignments + LLWString label = getCurrentLabel(); + + // overlay with keyboard focus border + if (hasFocus()) + { + F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); + drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt))); + } + + if (use_glow_effect) + { + mCurGlowStrength = lerp(mCurGlowStrength, + mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.f : 0.f) : mHoverGlowStrength, + LLSmoothInterpolation::getInterpolant(0.05f)); + } + else + { + mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); + } + + // Draw button image, if available. + // Otherwise draw basic rectangular button. + if (imagep != NULL) + { + // apply automatic 50% alpha fade to disabled image + LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); + if ( mScaleImage) + { + imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha ); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(glow_type); + image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + else + { + S32 y = getLocalRect().getHeight() - imagep->getHeight(); + imagep->draw(0, y, (enabled ? mImageColor.get() : disabled_color) % alpha); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(glow_type); + image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + } + else + { + // no image + LL_DEBUGS() << "No image for button " << getName() << LL_ENDL; + // draw it in pink so we can find it + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE); + } + + // let overlay image and text play well together + S32 text_left = mLeftHPad; + S32 text_right = getRect().getWidth() - mRightHPad; + S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad; + + // draw overlay image + if (mImageOverlay.notNull()) + { + // get max width and height (discard level 0) + S32 overlay_width; + S32 overlay_height; + + getOverlayImageSize(overlay_width, overlay_height); + + S32 center_x = getLocalRect().getCenterX(); + S32 center_y = getLocalRect().getCenterY(); + + //FUGLY HACK FOR "DEPRESSED" BUTTONS + if (pressed && mDisplayPressedState) + { + center_y--; + center_x++; + } + + center_y += (mImageOverlayBottomPad - mImageOverlayTopPad); + // fade out overlay images on disabled buttons + LLColor4 overlay_color = mImageOverlayColor.get(); + if (!enabled) + { + overlay_color = mImageOverlayDisabledColor.get(); + } + else if (getToggleState()) + { + overlay_color = mImageOverlaySelectedColor.get(); + } + overlay_color.mV[VALPHA] *= alpha; + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + text_left += overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; + mImageOverlay->draw( + mLeftHPad, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + case LLFontGL::HCENTER: + mImageOverlay->draw( + center_x - (overlay_width / 2), + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + case LLFontGL::RIGHT: + text_right -= overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; + mImageOverlay->draw( + getRect().getWidth() - mRightHPad - overlay_width, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + default: + // draw nothing + break; + } + } + + // Draw label + if( !label.empty() ) + { + LLWStringUtil::trim(label); + + S32 x; + switch( mHAlign ) + { + case LLFontGL::RIGHT: + x = text_right; + break; + case LLFontGL::HCENTER: + x = text_left + (text_width / 2); + break; + case LLFontGL::LEFT: + default: + x = text_left; + break; + } + + if (pressed && mDisplayPressedState) + { + x++; + } + + // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as + // max_chars. + // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. + // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. + // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. + mLastDrawCharsCount = mGLFont->render(label, 0, + (F32)x, + (F32)(getRect().getHeight() / 2 + mBottomVPad), + label_color % alpha, + mHAlign, LLFontGL::VCENTER, + LLFontGL::NORMAL, + mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, + S32_MAX, text_width, + NULL, mUseEllipses, mUseFontColor); + } + + LLUICtrl::draw(); } void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size) { - if (imagep == NULL) return; - if (mScaleImage) - { - imagep->drawBorder(getLocalRect(), color, size); - } - else - { - S32 y = getLocalRect().getHeight() - imagep->getHeight(); - imagep->drawBorder(0, y, color, size); - } + if (imagep == NULL) return; + if (mScaleImage) + { + imagep->drawBorder(getLocalRect(), color, size); + } + else + { + S32 y = getLocalRect().getHeight() - imagep->getHeight(); + imagep->drawBorder(0, y, color, size); + } } BOOL LLButton::getToggleState() const @@ -990,214 +991,214 @@ BOOL LLButton::getToggleState() const void LLButton::setToggleState(BOOL b) { - if( b != getToggleState() ) - { - setControlValue(b); // will fire LLControlVariable callbacks (if any) - setValue(b); // may or may not be redundant - setFlashing(false); // stop flash state whenever the selected/unselected state if reset - // Unselected label assignments - autoResize(); - } + if( b != getToggleState() ) + { + setControlValue(b); // will fire LLControlVariable callbacks (if any) + setValue(b); // may or may not be redundant + setFlashing(false); // stop flash state whenever the selected/unselected state if reset + // Unselected label assignments + autoResize(); + } } void LLButton::setFlashing(bool b, bool force_flashing/* = false */) -{ - mForceFlashing = force_flashing; - if (mFlashingTimer) - { - mFlashing = b; - (b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing()); - } - else if (b != mFlashing) - { - mFlashing = b; - mFrameTimer.reset(); - } -} - -BOOL LLButton::toggleState() +{ + mForceFlashing = force_flashing; + if (mFlashingTimer) + { + mFlashing = b; + (b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing()); + } + else if (b != mFlashing) + { + mFlashing = b; + mFrameTimer.reset(); + } +} + +BOOL LLButton::toggleState() { bool flipped = ! getToggleState(); - setToggleState(flipped); + setToggleState(flipped); - return flipped; + return flipped; } void LLButton::setLabel( const std::string& label ) { - mUnselectedLabel = mSelectedLabel = label; + mUnselectedLabel = mSelectedLabel = label; } void LLButton::setLabel( const LLUIString& label ) { - mUnselectedLabel = mSelectedLabel = label; + mUnselectedLabel = mSelectedLabel = label; } void LLButton::setLabel( const LLStringExplicit& label ) { - setLabelUnselected(label); - setLabelSelected(label); + setLabelUnselected(label); + setLabelSelected(label); } //virtual BOOL LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - mUnselectedLabel.setArg(key, text); - mSelectedLabel.setArg(key, text); - return TRUE; + mUnselectedLabel.setArg(key, text); + mSelectedLabel.setArg(key, text); + return TRUE; } void LLButton::setLabelUnselected( const LLStringExplicit& label ) { - mUnselectedLabel = label; + mUnselectedLabel = label; } void LLButton::setLabelSelected( const LLStringExplicit& label ) { - mSelectedLabel = label; + mSelectedLabel = label; } bool LLButton::labelIsTruncated() const { - return getCurrentLabel().getString().size() > mLastDrawCharsCount; + return getCurrentLabel().getString().size() > mLastDrawCharsCount; } const LLUIString& LLButton::getCurrentLabel() const { - return getToggleState() ? mSelectedLabel : mUnselectedLabel; + return getToggleState() ? mSelectedLabel : mUnselectedLabel; } void LLButton::setImageUnselected(LLPointer<LLUIImage> image) { - mImageUnselected = image; - if (mImageUnselected.isNull()) - { - LL_WARNS() << "Setting default button image for: " << getName() << " to NULL" << LL_ENDL; - } + mImageUnselected = image; + if (mImageUnselected.isNull()) + { + LL_WARNS() << "Setting default button image for: " << getName() << " to NULL" << LL_ENDL; + } } void LLButton::autoResize() { - resize(getCurrentLabel()); + resize(getCurrentLabel()); } void LLButton::resize(LLUIString label) { - // get label length - S32 label_width = mGLFont->getWidth(label.getString()); - // get current btn length - S32 btn_width =getRect().getWidth(); - // check if it need resize - if (mAutoResize) - { - S32 min_width = label_width + mLeftHPad + mRightHPad; - if (mImageOverlay) - { - S32 overlay_width = mImageOverlay->getWidth(); - F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight(); - overlay_width = ll_round((F32)overlay_width * scale_factor); - - switch(mImageOverlayAlignment) - { - case LLFontGL::LEFT: - case LLFontGL::RIGHT: - min_width += overlay_width + mImgOverlayLabelSpace; - break; - case LLFontGL::HCENTER: - min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad); - break; - default: - // draw nothing - break; - } - } - if (btn_width < min_width) - { - reshape(min_width, getRect().getHeight()); - } - } + // get label length + S32 label_width = mGLFont->getWidth(label.getString()); + // get current btn length + S32 btn_width =getRect().getWidth(); + // check if it need resize + if (mAutoResize) + { + S32 min_width = label_width + mLeftHPad + mRightHPad; + if (mImageOverlay) + { + S32 overlay_width = mImageOverlay->getWidth(); + F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight(); + overlay_width = ll_round((F32)overlay_width * scale_factor); + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + case LLFontGL::RIGHT: + min_width += overlay_width + mImgOverlayLabelSpace; + break; + case LLFontGL::HCENTER: + min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad); + break; + default: + // draw nothing + break; + } + } + if (btn_width < min_width) + { + reshape(min_width, getRect().getHeight()); + } + } } void LLButton::setImages( const std::string &image_name, const std::string &selected_name ) { - setImageUnselected(LLUI::getUIImage(image_name)); - setImageSelected(LLUI::getUIImage(selected_name)); + setImageUnselected(LLUI::getUIImage(image_name)); + setImageSelected(LLUI::getUIImage(selected_name)); } void LLButton::setImageSelected(LLPointer<LLUIImage> image) { - mImageSelected = image; + mImageSelected = image; } -void LLButton::setImageColor(const LLColor4& c) -{ - mImageColor = c; +void LLButton::setImageColor(const LLColor4& c) +{ + mImageColor = c; } void LLButton::setColor(const LLColor4& color) { - setImageColor(color); + setImageColor(color); } void LLButton::setImageDisabled(LLPointer<LLUIImage> image) { - mImageDisabled = image; - mDisabledImageColor = mImageColor; - mFadeWhenDisabled = TRUE; + mImageDisabled = image; + mDisabledImageColor = mImageColor; + mFadeWhenDisabled = TRUE; } void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image) { - mImageDisabledSelected = image; - mDisabledImageColor = mImageColor; - mFadeWhenDisabled = TRUE; + mImageDisabledSelected = image; + mDisabledImageColor = mImageColor; + mFadeWhenDisabled = TRUE; } void LLButton::setImagePressed(LLPointer<LLUIImage> image) { - mImagePressed = image; + mImagePressed = image; } void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image) { - mImageHoverSelected = image; + mImageHoverSelected = image; } void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image) { - mImageHoverUnselected = image; + mImageHoverUnselected = image; } void LLButton::setImageFlash(LLPointer<LLUIImage> image) { - mImageFlash = image; + mImageFlash = image; } void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color) { - if (image_name.empty()) - { - mImageOverlay = NULL; - } - else - { - mImageOverlay = LLUI::getUIImage(image_name); - mImageOverlayAlignment = alignment; - mImageOverlayColor = color; - } + if (image_name.empty()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImage(image_name); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } } void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color) { - if (image_id.isNull()) - { - mImageOverlay = NULL; - } - else - { - mImageOverlay = LLUI::getUIImageByID(image_id); - mImageOverlayAlignment = alignment; - mImageOverlayColor = color; - } + if (image_id.isNull()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImageByID(image_id); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } } void LLButton::onMouseCaptureLost() @@ -1214,7 +1215,7 @@ void LLButton::onMouseCaptureLost() LLUICtrl::onCommit(); } - resetMouseDownTimer(); + resetMouseDownTimer(); } //------------------------------------------------------------------------- @@ -1222,99 +1223,99 @@ void LLButton::onMouseCaptureLost() //------------------------------------------------------------------------- S32 round_up(S32 grid, S32 value) { - S32 mod = value % grid; + S32 mod = value % grid; - if (mod > 0) - { - // not even multiple - return value + (grid - mod); - } - else - { - return value; - } + if (mod > 0) + { + // not even multiple + return value + (grid - mod); + } + else + { + return value; + } } -void LLButton::addImageAttributeToXML(LLXMLNodePtr node, - const std::string& image_name, - const LLUUID& image_id, - const std::string& xml_tag_name) const +void LLButton::addImageAttributeToXML(LLXMLNodePtr node, + const std::string& image_name, + const LLUUID& image_id, + const std::string& xml_tag_name) const { - if( !image_name.empty() ) - { - node->createChild(xml_tag_name.c_str(), TRUE)->setStringValue(image_name); - } - else if( image_id != LLUUID::null ) - { - node->createChild((xml_tag_name + "_id").c_str(), TRUE)->setUUIDValue(image_id); - } + if( !image_name.empty() ) + { + node->createChild(xml_tag_name.c_str(), TRUE)->setStringValue(image_name); + } + else if( image_id != LLUUID::null ) + { + node->createChild((xml_tag_name + "_id").c_str(), TRUE)->setUUIDValue(image_id); + } } // static void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) { - bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString()); - LLButton* button = dynamic_cast<LLButton*>(ctrl); - if (button) - button->setToggleState(floater_vis); + bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString()); + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (button) + button->setToggleState(floater_vis); } // static // Gets called once void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) { - LLButton* button = dynamic_cast<LLButton*>(ctrl); - if (!button) - return; - // Get the visibility control name for the floater - std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); - // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) - button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); - // Set the clicked callback to toggle the floater - button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD())); + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD())); } // static void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) { - LLButton* button = dynamic_cast<LLButton*>(ctrl); - if (!button) - return; - // Get the visibility control name for the floater - std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); - // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) - button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); - // Set the clicked callback to toggle the floater - button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname)); + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname)); } // static void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname) { - // search back through the button's parents for a panel - // with a help_topic string defined - std::string help_topic; - if (LLUI::getInstance()->mHelpImpl && - ctrl->findHelpTopic(help_topic)) - { - LLUI::getInstance()->mHelpImpl->showTopic(help_topic); - return; // success - } + // search back through the button's parents for a panel + // with a help_topic string defined + std::string help_topic; + if (LLUI::getInstance()->mHelpImpl && + ctrl->findHelpTopic(help_topic)) + { + LLUI::getInstance()->mHelpImpl->showTopic(help_topic); + return; // success + } - // display an error if we can't find a help_topic string. - // fix this by adding a help_topic attribute to the xui file - LLNotificationsUtil::add("UnableToFindHelpTopic"); + // display an error if we can't find a help_topic string. + // fix this by adding a help_topic attribute to the xui file + LLNotificationsUtil::add("UnableToFindHelpTopic"); } void LLButton::resetMouseDownTimer() { - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + mMouseDownTimer.stop(); + mMouseDownTimer.reset(); } BOOL LLButton::handleDoubleClick(S32 x, S32 y, MASK mask) { - // just treat a double click as a second click - return handleMouseDown(x, y, mask); + // just treat a double click as a second click + return handleMouseDown(x, y, mask); } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 257159f64f..8ac42596e4 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -1,25 +1,25 @@ -/** +/** * @file llbutton.h * @brief Header for buttons * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,10 +43,10 @@ // // PLEASE please use these "constants" when building your own buttons. -// They are loaded from settings.xml at run time. -extern S32 LLBUTTON_H_PAD; -extern S32 BTN_HEIGHT_SMALL; -extern S32 BTN_HEIGHT; +extern S32 LLBUTTON_H_PAD; +extern S32 BTN_HEIGHT_SMALL; +extern S32 BTN_HEIGHT; +extern S32 BTN_DROP_SHADOW; // // Helpful functions @@ -65,342 +65,342 @@ class LLButton , public ll::ui::SearchableControl { public: - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - // text label - Optional<std::string> label_selected; - Optional<bool> label_shadow; - Optional<bool> auto_resize; - Optional<bool> use_ellipses; - Optional<bool> use_font_color; - - // images - Optional<LLUIImage*> image_unselected, - image_selected, - image_hover_selected, - image_hover_unselected, - image_disabled_selected, - image_disabled, - image_flash, - image_pressed, - image_pressed_selected, - image_overlay; - - Optional<std::string> image_overlay_alignment; - - // colors - Optional<LLUIColor> label_color, - label_color_selected, - label_color_disabled, - label_color_disabled_selected, - image_color, - image_color_disabled, - image_overlay_color, - image_overlay_selected_color, - image_overlay_disabled_color, - flash_color; - - // layout - Optional<S32> pad_right; - Optional<S32> pad_left; - Optional<S32> pad_bottom; // under text label - - //image overlay paddings - 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, - mouse_up_callback, - mouse_held_callback; - - // misc - Optional<bool> is_toggle, - scale_image, - commit_on_return, - commit_on_capture_lost, - display_pressed_state; - - Optional<F32> hover_glow_amount; - Optional<TimeIntervalParam> held_down_delay; - - Optional<bool> use_draw_context_alpha; - - Optional<LLBadge::Params> badge; - - Optional<bool> handle_right_mouse; - - Optional<bool> button_flash_enable; - Optional<S32> button_flash_count; - Optional<F32> button_flash_rate; - - Params(); - }; - + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + // text label + Optional<std::string> label_selected; + Optional<bool> label_shadow; + Optional<bool> auto_resize; + Optional<bool> use_ellipses; + Optional<bool> use_font_color; + + // images + Optional<LLUIImage*> image_unselected, + image_selected, + image_hover_selected, + image_hover_unselected, + image_disabled_selected, + image_disabled, + image_flash, + image_pressed, + image_pressed_selected, + image_overlay; + + Optional<std::string> image_overlay_alignment; + + // colors + Optional<LLUIColor> label_color, + label_color_selected, + label_color_disabled, + label_color_disabled_selected, + image_color, + image_color_disabled, + image_overlay_color, + image_overlay_selected_color, + image_overlay_disabled_color, + flash_color; + + // layout + Optional<S32> pad_right; + Optional<S32> pad_left; + Optional<S32> pad_bottom; // under text label + + //image overlay paddings + 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, + mouse_up_callback, + mouse_held_callback; + + // misc + Optional<bool> is_toggle, + scale_image, + commit_on_return, + commit_on_capture_lost, + display_pressed_state; + + Optional<F32> hover_glow_amount; + Optional<TimeIntervalParam> held_down_delay; + + Optional<bool> use_draw_context_alpha; + + Optional<LLBadge::Params> badge; + + Optional<bool> handle_right_mouse; + + Optional<bool> button_flash_enable; + Optional<S32> button_flash_count; + Optional<F32> button_flash_rate; + + Params(); + }; + protected: - friend class LLUICtrlFactory; - LLButton(const Params&); + friend class LLUICtrlFactory; + LLButton(const Params&); public: - ~LLButton(); - // For backward compatability only - typedef boost::function<void(void*)> button_callback_t; - - void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, - const LLUUID& imageID,const std::string& xmlTagName) const; - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - virtual void draw(); - /*virtual*/ BOOL postBuild(); - - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - virtual void onMouseCaptureLost(); - - virtual void onCommit(); - - void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } - void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } - void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } - void setUseFontColor( BOOL use_font_color) { mUseFontColor = use_font_color; } - - - boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); - boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); - boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); - boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb); - - boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button - boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON - // Passes a 'count' parameter in the commit param payload, i.e. param["count"]) - boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button - - - // *TODO: Deprecate (for backwards compatability only) - boost::signals2::connection setClickedCallback( button_callback_t cb, void* data ); - boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data ); - boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data ); - boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data ); - - void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; } - - F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); } - - BOOL toggleState(); - BOOL getToggleState() const; - void setToggleState(BOOL b); - - void setHighlight(bool b); - void setFlashing( bool b, bool force_flashing = false ); - BOOL getFlashing() const { return mFlashing; } + ~LLButton(); + // For backward compatability only + typedef boost::function<void(void*)> button_callback_t; + + void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, + const LLUUID& imageID,const std::string& xmlTagName) const; + virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual void draw(); + /*virtual*/ BOOL postBuild(); + + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual void onMouseCaptureLost(); + + virtual void onCommit(); + + void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } + void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } + void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } + void setUseFontColor( BOOL use_font_color) { mUseFontColor = use_font_color; } + + + boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); + boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); + boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); + boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb); + + boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button + boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON + // Passes a 'count' parameter in the commit param payload, i.e. param["count"]) + boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button + + + // *TODO: Deprecate (for backwards compatability only) + boost::signals2::connection setClickedCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data ); + boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data ); + + void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; } + + F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); } + + BOOL toggleState(); + BOOL getToggleState() const; + void setToggleState(BOOL b); + + void setHighlight(bool b); + void setFlashing( bool b, bool force_flashing = false ); + BOOL getFlashing() const { return mFlashing; } LLFlashTimer* getFlashTimer() {return mFlashingTimer;} - void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; }; - - void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } - LLFontGL::HAlign getHAlign() const { return mHAlign; } - void setLeftHPad( S32 pad ) { mLeftHPad = pad; } - void setRightHPad( S32 pad ) { mRightHPad = pad; } - - void setImageOverlayTopPad( S32 pad ) { mImageOverlayTopPad = pad; } - S32 getImageOverlayTopPad() const { return mImageOverlayTopPad; } - void setImageOverlayBottomPad( S32 pad ) { mImageOverlayBottomPad = pad; } - S32 getImageOverlayBottomPad() const { return mImageOverlayBottomPad; } - - const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); } - const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); } - - void setImageColor(const std::string& color_control); - void setImageColor(const LLColor4& c); - /*virtual*/ void setColor(const LLColor4& c); - - void setImages(const std::string &image_name, const std::string &selected_name); - - void setDisabledImageColor(const LLColor4& c) { mDisabledImageColor = c; } - - void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } - - void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); - void setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); - LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; } - LLFontGL::HAlign getImageOverlayHAlign() const { return mImageOverlayAlignment; } - - void autoResize(); // resize with label of current btn state - void resize(LLUIString label); // resize with label input - void setLabel(const std::string& label); - void setLabel(const LLUIString& label); - void setLabel( const LLStringExplicit& label); - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - void setLabelUnselected(const LLStringExplicit& label); - void setLabelSelected(const LLStringExplicit& label); - void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; } - - void setFont(const LLFontGL *font) - { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); } - const LLFontGL* getFont() const { return mGLFont; } - - - S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; } - bool labelIsTruncated() const; - const LLUIString& getCurrentLabel() const; - - void setScaleImage(BOOL scale) { mScaleImage = scale; } - BOOL getScaleImage() const { return mScaleImage; } - - void setDropShadowedText(BOOL b) { mDropShadowedText = b; } - - void setBorderEnabled(BOOL b) { mBorderEnabled = b; } - - void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } - - void setImageUnselected(LLPointer<LLUIImage> image); - void setImageSelected(LLPointer<LLUIImage> image); - void setImageHoverSelected(LLPointer<LLUIImage> image); - void setImageHoverUnselected(LLPointer<LLUIImage> image); - void setImageDisabled(LLPointer<LLUIImage> image); - void setImageDisabledSelected(LLPointer<LLUIImage> image); - void setImageFlash(LLPointer<LLUIImage> image); - void setImagePressed(LLPointer<LLUIImage> image); - - void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } - BOOL getCommitOnReturn() const { return mCommitOnReturn; } - - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks - static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); - static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); - static void setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); - static void showHelp(LLUICtrl* ctrl, const LLSD& sdname); - - void setForcePressedState(bool b) { mForcePressedState = b; } - - void setAutoResize(bool auto_resize) { mAutoResize = auto_resize; } + void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; }; + + void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } + LLFontGL::HAlign getHAlign() const { return mHAlign; } + void setLeftHPad( S32 pad ) { mLeftHPad = pad; } + void setRightHPad( S32 pad ) { mRightHPad = pad; } + + void setImageOverlayTopPad( S32 pad ) { mImageOverlayTopPad = pad; } + S32 getImageOverlayTopPad() const { return mImageOverlayTopPad; } + void setImageOverlayBottomPad( S32 pad ) { mImageOverlayBottomPad = pad; } + S32 getImageOverlayBottomPad() const { return mImageOverlayBottomPad; } + + const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); } + const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); } + + void setImageColor(const std::string& color_control); + void setImageColor(const LLColor4& c); + /*virtual*/ void setColor(const LLColor4& c); + + void setImages(const std::string &image_name, const std::string &selected_name); + + void setDisabledImageColor(const LLColor4& c) { mDisabledImageColor = c; } + + void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } + + void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); + void setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); + LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; } + LLFontGL::HAlign getImageOverlayHAlign() const { return mImageOverlayAlignment; } + + void autoResize(); // resize with label of current btn state + void resize(LLUIString label); // resize with label input + void setLabel(const std::string& label); + void setLabel(const LLUIString& label); + void setLabel( const LLStringExplicit& label); + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + void setLabelUnselected(const LLStringExplicit& label); + void setLabelSelected(const LLStringExplicit& label); + void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; } + + void setFont(const LLFontGL *font) + { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); } + const LLFontGL* getFont() const { return mGLFont; } + const std::string& getText() const { return getCurrentLabel().getString(); } + + S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; } + bool labelIsTruncated() const; + const LLUIString& getCurrentLabel() const; + + void setScaleImage(BOOL scale) { mScaleImage = scale; } + BOOL getScaleImage() const { return mScaleImage; } + + void setDropShadowedText(BOOL b) { mDropShadowedText = b; } + + void setBorderEnabled(BOOL b) { mBorderEnabled = b; } + + void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } + + void setImageUnselected(LLPointer<LLUIImage> image); + void setImageSelected(LLPointer<LLUIImage> image); + void setImageHoverSelected(LLPointer<LLUIImage> image); + void setImageHoverUnselected(LLPointer<LLUIImage> image); + void setImageDisabled(LLPointer<LLUIImage> image); + void setImageDisabledSelected(LLPointer<LLUIImage> image); + void setImageFlash(LLPointer<LLUIImage> image); + void setImagePressed(LLPointer<LLUIImage> image); + + void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } + BOOL getCommitOnReturn() const { return mCommitOnReturn; } + + static void onHeldDown(void *userdata); // to be called by gIdleCallbacks + static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); + static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + static void setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + static void showHelp(LLUICtrl* ctrl, const LLSD& sdname); + + void setForcePressedState(bool b) { mForcePressedState = b; } + + void setAutoResize(bool auto_resize) { mAutoResize = auto_resize; } protected: - LLPointer<LLUIImage> getImageUnselected() const { return mImageUnselected; } - LLPointer<LLUIImage> getImageSelected() const { return mImageSelected; } - void getOverlayImageSize(S32& overlay_width, S32& overlay_height); - - LLFrameTimer mMouseDownTimer; - bool mNeedsHighlight; - S32 mButtonFlashCount; - F32 mButtonFlashRate; - - void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size); - void resetMouseDownTimer(); - - commit_signal_t* mMouseDownSignal; - commit_signal_t* mMouseUpSignal; - commit_signal_t* mHeldDownSignal; - - const LLFontGL* mGLFont; - - S32 mMouseDownFrame; - S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback - F32 mHeldDownDelay; // seconds, after which held-down callbacks get called - S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called - S32 mLastDrawCharsCount; - - LLPointer<LLUIImage> mImageOverlay; - LLFontGL::HAlign mImageOverlayAlignment; - LLUIColor mImageOverlayColor; - LLUIColor mImageOverlaySelectedColor; - LLUIColor mImageOverlayDisabledColor; - - LLPointer<LLUIImage> mImageUnselected; - LLUIString mUnselectedLabel; - LLUIColor mUnselectedLabelColor; - - LLPointer<LLUIImage> mImageSelected; - LLUIString mSelectedLabel; - LLUIColor mSelectedLabelColor; - - LLPointer<LLUIImage> mImageHoverSelected; - - LLPointer<LLUIImage> mImageHoverUnselected; - - LLPointer<LLUIImage> mImageDisabled; - LLUIColor mDisabledLabelColor; - - LLPointer<LLUIImage> mImageDisabledSelected; - LLUIString mDisabledSelectedLabel; - LLUIColor mDisabledSelectedLabelColor; - - LLPointer<LLUIImage> mImagePressed; - LLPointer<LLUIImage> mImagePressedSelected; - - /* There are two ways an image can flash- by making changes in color according to flash_color attribute - or by changing icon from current to the one specified in image_flash. Second way is used only if - flash icon name is set in attributes(by default it isn't). First way is used otherwise. */ - LLPointer<LLUIImage> mImageFlash; - - LLUIColor mFlashBgColor; - - LLUIColor mImageColor; - LLUIColor mDisabledImageColor; - - bool mIsToggle; - bool mScaleImage; - - bool mDropShadowedText; - bool mAutoResize; - bool mUseEllipses; - bool mUseFontColor; - bool mBorderEnabled; - bool mFlashing; - - LLFontGL::HAlign mHAlign; - S32 mLeftHPad; - S32 mRightHPad; - S32 mBottomVPad; // under text label - - S32 mImageOverlayTopPad; - S32 mImageOverlayBottomPad; - - bool mUseDrawContextAlpha; - - /* - * Space between image_overlay and label - */ - S32 mImgOverlayLabelSpace; - - F32 mHoverGlowStrength; - F32 mCurGlowStrength; - - bool mCommitOnReturn; - bool mCommitOnCaptureLost; - bool mFadeWhenDisabled; - bool mForcePressedState; - bool mDisplayPressedState; - - LLFrameTimer mFrameTimer; - LLFlashTimer * mFlashingTimer; - bool mForceFlashing; // Stick flashing color even if button is pressed - bool mHandleRightMouse; + LLPointer<LLUIImage> getImageUnselected() const { return mImageUnselected; } + LLPointer<LLUIImage> getImageSelected() const { return mImageSelected; } + void getOverlayImageSize(S32& overlay_width, S32& overlay_height); + + LLFrameTimer mMouseDownTimer; + bool mNeedsHighlight; + S32 mButtonFlashCount; + F32 mButtonFlashRate; + + void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size); + void resetMouseDownTimer(); + + commit_signal_t* mMouseDownSignal; + commit_signal_t* mMouseUpSignal; + commit_signal_t* mHeldDownSignal; + + const LLFontGL* mGLFont; + + S32 mMouseDownFrame; + S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback + F32 mHeldDownDelay; // seconds, after which held-down callbacks get called + S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called + S32 mLastDrawCharsCount; + + LLPointer<LLUIImage> mImageOverlay; + LLFontGL::HAlign mImageOverlayAlignment; + LLUIColor mImageOverlayColor; + LLUIColor mImageOverlaySelectedColor; + LLUIColor mImageOverlayDisabledColor; + + LLPointer<LLUIImage> mImageUnselected; + LLUIString mUnselectedLabel; + LLUIColor mUnselectedLabelColor; + + LLPointer<LLUIImage> mImageSelected; + LLUIString mSelectedLabel; + LLUIColor mSelectedLabelColor; + + LLPointer<LLUIImage> mImageHoverSelected; + + LLPointer<LLUIImage> mImageHoverUnselected; + + LLPointer<LLUIImage> mImageDisabled; + LLUIColor mDisabledLabelColor; + + LLPointer<LLUIImage> mImageDisabledSelected; + LLUIString mDisabledSelectedLabel; + LLUIColor mDisabledSelectedLabelColor; + + LLPointer<LLUIImage> mImagePressed; + LLPointer<LLUIImage> mImagePressedSelected; + + /* There are two ways an image can flash- by making changes in color according to flash_color attribute + or by changing icon from current to the one specified in image_flash. Second way is used only if + flash icon name is set in attributes(by default it isn't). First way is used otherwise. */ + LLPointer<LLUIImage> mImageFlash; + + LLUIColor mFlashBgColor; + + LLUIColor mImageColor; + LLUIColor mDisabledImageColor; + + bool mIsToggle; + bool mScaleImage; + + bool mDropShadowedText; + bool mAutoResize; + bool mUseEllipses; + bool mUseFontColor; + bool mBorderEnabled; + bool mFlashing; + + LLFontGL::HAlign mHAlign; + S32 mLeftHPad; + S32 mRightHPad; + S32 mBottomVPad; // under text label + + S32 mImageOverlayTopPad; + S32 mImageOverlayBottomPad; + + bool mUseDrawContextAlpha; + + /* + * Space between image_overlay and label + */ + S32 mImgOverlayLabelSpace; + + F32 mHoverGlowStrength; + F32 mCurGlowStrength; + + bool mCommitOnReturn; + bool mCommitOnCaptureLost; + bool mFadeWhenDisabled; + bool mForcePressedState; + bool mDisplayPressedState; + + LLFrameTimer mFrameTimer; + LLFlashTimer * mFlashingTimer; + bool mForceFlashing; // Stick flashing color even if button is pressed + bool mHandleRightMouse; protected: - virtual std::string _getSearchText() const - { - return getLabelUnselected() + getToolTip(); - } + virtual std::string _getSearchText() const + { + return getLabelUnselected() + getToolTip(); + } }; // Build time optimization, generate once in .cpp file #ifndef LLBUTTON_CPP extern template class LLButton* LLView::getChild<class LLButton>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_LLBUTTON_H diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h index 0a10877c09..07775dc30f 100644 --- a/indra/llui/llcallbackmap.h +++ b/indra/llui/llcallbackmap.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallbackmap.h * @brief LLCallbackMap base class * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,25 +34,25 @@ class LLCallbackMap { public: - // callback definition. - typedef boost::function<void* (void* data)> callback_t; - - typedef std::map<std::string, LLCallbackMap> map_t; - typedef map_t::iterator map_iter_t; - typedef map_t::const_iterator map_const_iter_t; - - template <class T> - static void* buildPanel(void* data) - { - T* panel = new T(); - return (void*)panel; - } - - LLCallbackMap() : mCallback(NULL), mData(NULL) { } - LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { } - - callback_t mCallback; - void* mData; + // callback definition. + typedef boost::function<void* (void* data)> callback_t; + + typedef std::map<std::string, LLCallbackMap> map_t; + typedef map_t::iterator map_iter_t; + typedef map_t::const_iterator map_const_iter_t; + + template <class T> + static void* buildPanel(void* data) + { + T* panel = new T(); + return (void*)panel; + } + + LLCallbackMap() : mCallback(NULL), mData(NULL) { } + LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { } + + callback_t mCallback; + void* mData; }; #endif // LLCALLBACKMAP_H diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index b4fd5f60aa..56105add7e 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -1,4 +1,4 @@ -/** +/** * @file llchat.h * @author James Cook * @brief Chat constants and data structures. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,79 +34,79 @@ // enumerations used by the chat system typedef enum e_chat_source_type { - CHAT_SOURCE_SYSTEM = 0, - CHAT_SOURCE_AGENT = 1, - CHAT_SOURCE_OBJECT = 2, - CHAT_SOURCE_TELEPORT = 3, - CHAT_SOURCE_UNKNOWN = 4, - CHAT_SOURCE_REGION = 5, + CHAT_SOURCE_SYSTEM = 0, + CHAT_SOURCE_AGENT = 1, + CHAT_SOURCE_OBJECT = 2, + CHAT_SOURCE_TELEPORT = 3, + CHAT_SOURCE_UNKNOWN = 4, + CHAT_SOURCE_REGION = 5, } EChatSourceType; typedef enum e_chat_type { - CHAT_TYPE_WHISPER = 0, - CHAT_TYPE_NORMAL = 1, - CHAT_TYPE_SHOUT = 2, - CHAT_TYPE_START = 4, - CHAT_TYPE_STOP = 5, - CHAT_TYPE_DEBUG_MSG = 6, - CHAT_TYPE_REGION = 7, - CHAT_TYPE_OWNER = 8, - CHAT_TYPE_DIRECT = 9 // From llRegionSayTo() + CHAT_TYPE_WHISPER = 0, + CHAT_TYPE_NORMAL = 1, + CHAT_TYPE_SHOUT = 2, + CHAT_TYPE_START = 4, + CHAT_TYPE_STOP = 5, + CHAT_TYPE_DEBUG_MSG = 6, + CHAT_TYPE_REGION = 7, + CHAT_TYPE_OWNER = 8, + CHAT_TYPE_DIRECT = 9 // From llRegionSayTo() } EChatType; typedef enum e_chat_audible_level { - CHAT_AUDIBLE_NOT = -1, - CHAT_AUDIBLE_BARELY = 0, - CHAT_AUDIBLE_FULLY = 1 + CHAT_AUDIBLE_NOT = -1, + CHAT_AUDIBLE_BARELY = 0, + CHAT_AUDIBLE_FULLY = 1 } EChatAudible; typedef enum e_chat_style { - CHAT_STYLE_NORMAL, - CHAT_STYLE_IRC, - CHAT_STYLE_HISTORY, - CHAT_STYLE_TELEPORT_SEP + CHAT_STYLE_NORMAL, + CHAT_STYLE_IRC, + CHAT_STYLE_HISTORY, + CHAT_STYLE_TELEPORT_SEP }EChatStyle; // A piece of chat class LLChat { public: - LLChat(const std::string& text = std::string()) - : mText(text), - mFromName(), - mFromID(), - mNotifId(), - mOwnerID(), - mSourceType(CHAT_SOURCE_AGENT), - mChatType(CHAT_TYPE_NORMAL), - mAudible(CHAT_AUDIBLE_FULLY), - mMuted(FALSE), - mTime(0.0), - mTimeStr(), - mPosAgent(), - mURL(), - mChatStyle(CHAT_STYLE_NORMAL), - mSessionID() - { } - - std::string mText; // UTF-8 line of text - std::string mFromName; // agent or object name - LLUUID mFromID; // agent id or object id - LLUUID mNotifId; - LLUUID mOwnerID; - EChatSourceType mSourceType; - EChatType mChatType; - EChatAudible mAudible; - BOOL mMuted; // pass muted chat to maintain list of chatters - F64 mTime; // viewer only, seconds from viewer start - std::string mTimeStr; - LLVector3 mPosAgent; - std::string mURL; - EChatStyle mChatStyle; - LLUUID mSessionID; + LLChat(const std::string& text = std::string()) + : mText(text), + mFromName(), + mFromID(), + mNotifId(), + mOwnerID(), + mSourceType(CHAT_SOURCE_AGENT), + mChatType(CHAT_TYPE_NORMAL), + mAudible(CHAT_AUDIBLE_FULLY), + mMuted(FALSE), + mTime(0.0), + mTimeStr(), + mPosAgent(), + mURL(), + mChatStyle(CHAT_STYLE_NORMAL), + mSessionID() + { } + + std::string mText; // UTF-8 line of text + std::string mFromName; // agent or object name + LLUUID mFromID; // agent id or object id + LLUUID mNotifId; + LLUUID mOwnerID; + EChatSourceType mSourceType; + EChatType mChatType; + EChatAudible mAudible; + BOOL mMuted; // pass muted chat to maintain list of chatters + F64 mTime; // viewer only, seconds from viewer start + std::string mTimeStr; + LLVector3 mPosAgent; + std::string mURL; + EChatStyle mChatStyle; + LLUUID mSessionID; }; #endif diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index c506576126..8a8b9e7461 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -32,117 +32,117 @@ static LLDefaultChildRegistry::Register<LLChatEntry> r("chat_editor"); LLChatEntry::Params::Params() -: has_history("has_history", true), - is_expandable("is_expandable", false), - expand_lines_count("expand_lines_count", 1) +: has_history("has_history", true), + is_expandable("is_expandable", false), + expand_lines_count("expand_lines_count", 1) {} LLChatEntry::LLChatEntry(const Params& p) -: LLTextEditor(p), - mTextExpandedSignal(NULL), - mHasHistory(p.has_history), - mIsExpandable(p.is_expandable), - mExpandLinesCount(p.expand_lines_count), - mPrevLinesCount(0), - mSingleLineMode(false), - mPrevExpandedLineCount(S32_MAX) +: LLTextEditor(p), + mTextExpandedSignal(NULL), + mHasHistory(p.has_history), + mIsExpandable(p.is_expandable), + mExpandLinesCount(p.expand_lines_count), + mPrevLinesCount(0), + mSingleLineMode(false), + mPrevExpandedLineCount(S32_MAX) { - // Initialize current history line iterator - mCurrentHistoryLine = mLineHistory.begin(); + // Initialize current history line iterator + mCurrentHistoryLine = mLineHistory.begin(); - mAutoIndent = false; - keepSelectionOnReturn(true); + mAutoIndent = false; + keepSelectionOnReturn(true); } LLChatEntry::~LLChatEntry() { - delete mTextExpandedSignal; + delete mTextExpandedSignal; } void LLChatEntry::draw() { - if(mIsExpandable) - { - reflow(); - expandText(); - } - LLTextEditor::draw(); + if(mIsExpandable) + { + reflow(); + expandText(); + } + LLTextEditor::draw(); } void LLChatEntry::onCommit() { - updateHistory(); - LLTextEditor::onCommit(); + updateHistory(); + LLTextEditor::onCommit(); } boost::signals2::connection LLChatEntry::setTextExpandedCallback(const commit_signal_t::slot_type& cb) { - if (!mTextExpandedSignal) - { - mTextExpandedSignal = new commit_signal_t(); - } - return mTextExpandedSignal->connect(cb); + if (!mTextExpandedSignal) + { + mTextExpandedSignal = new commit_signal_t(); + } + return mTextExpandedSignal->connect(cb); } void LLChatEntry::expandText() { - S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount; - - int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second); - bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ; - mPrevExpandedLineCount = line_count; - - // true if pasted text has more lines than expand height limit and expand limit is not reached yet - bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count); - - if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && getLineCount() != mPrevLinesCount) - { - int lines_height = 0; - if (text_pasted) - { - // text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty, - // so lines_height is the sum of the last 'expanded_line_count' lines height - lines_height = (mLineInfoList.end() - line_count)->mRect.mTop - mLineInfoList.back().mRect.mBottom; - } - else - { - lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom; - } - - int height = mVPad * 2 + lines_height; - - LLRect doc_rect = getRect(); - doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height); - setShape(doc_rect); - - mPrevLinesCount = getLineCount(); - - if (mTextExpandedSignal) - { - (*mTextExpandedSignal)(this, LLSD() ); - } - - needsReflow(); - } + S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount; + + int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second); + bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ; + mPrevExpandedLineCount = line_count; + + // true if pasted text has more lines than expand height limit and expand limit is not reached yet + bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count); + + if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && getLineCount() != mPrevLinesCount) + { + int lines_height = 0; + if (text_pasted) + { + // text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty, + // so lines_height is the sum of the last 'expanded_line_count' lines height + lines_height = (mLineInfoList.end() - line_count)->mRect.mTop - mLineInfoList.back().mRect.mBottom; + } + else + { + lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom; + } + + int height = mVPad * 2 + lines_height; + + LLRect doc_rect = getRect(); + doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height); + setShape(doc_rect); + + mPrevLinesCount = getLineCount(); + + if (mTextExpandedSignal) + { + (*mTextExpandedSignal)(this, LLSD() ); + } + + needsReflow(); + } } // line history support void LLChatEntry::updateHistory() { - // On history enabled, remember committed line and - // reset current history line number. - // Be sure only to remember lines that are not empty and that are - // different from the last on the list. - if (mHasHistory && getLength()) - { - // Add text to history, ignoring duplicates - if (mLineHistory.empty() || getText() != mLineHistory.back()) - { - mLineHistory.push_back(getText()); - } - - mCurrentHistoryLine = mLineHistory.end(); - } + // On history enabled, remember committed line and + // reset current history line number. + // Be sure only to remember lines that are not empty and that are + // different from the last on the list. + if (mHasHistory && getLength()) + { + // Add text to history, ignoring duplicates + if (mLineHistory.empty() || getText() != mLineHistory.back()) + { + mLineHistory.push_back(getText()); + } + + mCurrentHistoryLine = mLineHistory.end(); + } } void LLChatEntry::beforeValueChange() @@ -166,86 +166,86 @@ bool LLChatEntry::useLabel() const void LLChatEntry::onFocusReceived() { - LLUICtrl::onFocusReceived(); - updateAllowingLanguageInput(); + LLUICtrl::onFocusReceived(); + updateAllowingLanguageInput(); } void LLChatEntry::onFocusLost() { - LLTextEditor::focusLostHelper(); - LLUICtrl::onFocusLost(); + LLTextEditor::focusLostHelper(); + LLUICtrl::onFocusLost(); } BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - LLTextEditor::handleSpecialKey(key, mask); - - switch(key) - { - case KEY_RETURN: - if (MASK_NONE == mask) - { - needsReflow(); - } - break; - - case KEY_UP: - if (mHasHistory && MASK_CONTROL == mask) - { - if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin()) - { - setText(*(--mCurrentHistoryLine)); - endOfDoc(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - case KEY_DOWN: - if (mHasHistory && MASK_CONTROL == mask) - { - if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) ) - { - setText(*(++mCurrentHistoryLine)); - endOfDoc(); - } - else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) ) - { - mCurrentHistoryLine++; - std::string empty(""); - setText(empty); - needsReflow(); - endOfDoc(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - default: - break; - } - - return handled; + BOOL handled = FALSE; + + LLTextEditor::handleSpecialKey(key, mask); + + switch(key) + { + case KEY_RETURN: + if (MASK_NONE == mask) + { + needsReflow(); + } + break; + + case KEY_UP: + if (mHasHistory && MASK_CONTROL == mask) + { + if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin()) + { + setText(*(--mCurrentHistoryLine)); + endOfDoc(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + case KEY_DOWN: + if (mHasHistory && MASK_CONTROL == mask) + { + if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) ) + { + setText(*(++mCurrentHistoryLine)); + endOfDoc(); + } + else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) ) + { + mCurrentHistoryLine++; + std::string empty(""); + setText(empty); + needsReflow(); + endOfDoc(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + default: + break; + } + + return handled; } void LLChatEntry::enableSingleLineMode(bool single_line_mode) { - if (mScroller) - { - mScroller->setSize(single_line_mode ? 0 : -1); - } - - mSingleLineMode = single_line_mode; - mPrevLinesCount = -1; - setWordWrap(!single_line_mode); + if (mScroller) + { + mScroller->setSize(single_line_mode ? 0 : -1); + } + + mSingleLineMode = single_line_mode; + mPrevLinesCount = -1; + setWordWrap(!single_line_mode); } diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h index 3f13691a30..f7473b320d 100644 --- a/indra/llui/llchatentry.h +++ b/indra/llui/llchatentry.h @@ -4,8 +4,8 @@ * @brief Text editor widget which is used for user input * * Features: - * Optional line history so previous entries can be recalled by CTRL UP/DOWN - * Optional auto-resize behavior on input chat field + * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * Optional auto-resize behavior on input chat field * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -38,69 +38,69 @@ class LLChatEntry : public LLTextEditor { public: - struct Params : public LLInitParam::Block<Params, LLTextEditor::Params> - { - Optional<bool> has_history, - is_expandable; + struct Params : public LLInitParam::Block<Params, LLTextEditor::Params> + { + Optional<bool> has_history, + is_expandable; - Optional<int> expand_lines_count; + Optional<int> expand_lines_count; - Params(); - }; + Params(); + }; - virtual ~LLChatEntry(); + virtual ~LLChatEntry(); protected: - friend class LLUICtrlFactory; - LLChatEntry(const Params& p); + friend class LLUICtrlFactory; + LLChatEntry(const Params& p); /*virtual*/ void beforeValueChange(); /*virtual*/ void onValueChange(S32 start, S32 end); /*virtual*/ bool useLabel() const; public: - virtual void draw(); - virtual void onCommit(); - /*virtual*/ void onFocusReceived(); - /*virtual*/ void onFocusLost(); + virtual void draw(); + virtual void onCommit(); + /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusLost(); - void enableSingleLineMode(bool single_line_mode); - boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb); + void enableSingleLineMode(bool single_line_mode); + boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb); private: - /** - * Implements auto-resize behavior. - * When user's typing reaches the right edge of the chat field - * the chat field expands vertically by one line. The bottom of - * the chat field remains bottom-justified. The chat field does - * not expand beyond mExpandLinesCount. - */ - void expandText(); - - /** - * Implements line history so previous entries can be recalled by CTRL UP/DOWN - */ - void updateHistory(); - - BOOL handleSpecialKey(const KEY key, const MASK mask); - - - // Fired when text height expanded to mExpandLinesCount - commit_signal_t* mTextExpandedSignal; - - // line history support: - typedef std::vector<std::string> line_history_t; - line_history_t::iterator mCurrentHistoryLine; // currently browsed history line - line_history_t mLineHistory; // line history storage - bool mHasHistory; // flag for enabled/disabled line history - bool mIsExpandable; - bool mSingleLineMode; - - S32 mExpandLinesCount; - S32 mPrevLinesCount; - S32 mPrevExpandedLineCount; + /** + * Implements auto-resize behavior. + * When user's typing reaches the right edge of the chat field + * the chat field expands vertically by one line. The bottom of + * the chat field remains bottom-justified. The chat field does + * not expand beyond mExpandLinesCount. + */ + void expandText(); + + /** + * Implements line history so previous entries can be recalled by CTRL UP/DOWN + */ + void updateHistory(); + + BOOL handleSpecialKey(const KEY key, const MASK mask); + + + // Fired when text height expanded to mExpandLinesCount + commit_signal_t* mTextExpandedSignal; + + // line history support: + typedef std::vector<std::string> line_history_t; + line_history_t::iterator mCurrentHistoryLine; // currently browsed history line + line_history_t mLineHistory; // line history storage + bool mHasHistory; // flag for enabled/disabled line history + bool mIsExpandable; + bool mSingleLineMode; + + S32 mExpandLinesCount; + S32 mPrevLinesCount; + S32 mPrevExpandedLineCount; }; #endif /* LLCHATENTRY_H_ */ diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index 362fe0c19e..8ba37a8075 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcheckboxctrl.cpp * @brief LLCheckBoxCtrl base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,7 +45,7 @@ static LLDefaultChildRegistry::Register<LLCheckBoxCtrl> r("check_box"); // Compiler optimization, generate extern template template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; void LLCheckBoxCtrl::WordWrap::declareValues() { @@ -55,44 +55,44 @@ void LLCheckBoxCtrl::WordWrap::declareValues() } LLCheckBoxCtrl::Params::Params() -: initial_value("initial_value", false), - label_text("label_text"), - check_button("check_button"), - word_wrap("word_wrap", EWordWrap::WRAP_NONE), - radio_style("radio_style") +: initial_value("initial_value", false), + label_text("label_text"), + check_button("check_button"), + word_wrap("word_wrap", EWordWrap::WRAP_NONE), + radio_style("radio_style") {} LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) -: LLUICtrl(p), - mTextEnabledColor(p.label_text.text_color()), - mTextDisabledColor(p.label_text.text_readonly_color()), - mFont(p.font()), - mWordWrap(p.word_wrap) +: LLUICtrl(p), + mTextEnabledColor(p.label_text.text_color()), + mTextDisabledColor(p.label_text.text_readonly_color()), + mFont(p.font()), + mWordWrap(p.word_wrap) { - mViewModel->setValue(LLSD(p.initial_value)); - mViewModel->resetDirty(); - static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); - static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); - static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); - - // must be big enough to hold all children - setUseBoundingRect(TRUE); - - // *HACK Get rid of this with SL-55508... - // this allows blank check boxes and radio boxes for now - std::string local_label = p.label; - if(local_label.empty()) - { - local_label = " "; - } - - LLTextBox::Params tbparams = p.label_text; - tbparams.initial_value(local_label); - if (p.font.isProvided()) - { - tbparams.font(p.font); - } + mViewModel->setValue(LLSD(p.initial_value)); + mViewModel->resetDirty(); + static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); + static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); + static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); + + // must be big enough to hold all children + setUseBoundingRect(TRUE); + + // *HACK Get rid of this with SL-55508... + // this allows blank check boxes and radio boxes for now + std::string local_label = p.label; + if(local_label.empty()) + { + local_label = " "; + } + + LLTextBox::Params tbparams = p.label_text; + tbparams.initial_value(local_label); + if (p.font.isProvided()) + { + tbparams.font(p.font); + } mLabel = LLUICtrlFactory::create<LLTextBox>(tbparams); if (mWordWrap != WRAP_NONE) @@ -104,11 +104,11 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) label_rect.mRight = label_rect.mLeft + new_width; mLabel->setRect(label_rect); } - mLabel->reshapeToFitText(); + mLabel->reshapeToFitText(); - LLRect label_rect = mLabel->getRect(); - if (mLabel->getLineCount() > 1) - { + LLRect label_rect = mLabel->getRect(); + if (mLabel->getLineCount() > 1) + { if (mWordWrap == WRAP_DOWN) { // reshapeToFitText uses LLView::reshape() which always reshapes @@ -122,67 +122,67 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) // WRAP_UP is essentially done by reshapeToFitText() (extends from bottom to top) // howhever it doesn't respect rect of checkbox // todo: this should be fixed, but there are at least couple checkboxes that use this feature as is. - } - - addChild(mLabel); - - // Button - // Note: button cover the label by extending all the way to the right and down. - LLRect btn_rect = p.check_button.rect(); - btn_rect.setOriginAndSize( - btn_rect.mLeft, - llmin(btn_rect.mBottom, label_rect.mBottom), - llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft), - llmax(label_rect.getHeight(), btn_rect.mTop)); - std::string active_true_id, active_false_id; - std::string inactive_true_id, inactive_false_id; - - LLButton::Params params = p.check_button; - params.rect(btn_rect); - //params.control_name(p.control_name); - params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onCommit, this)); - params.commit_on_return(false); - // Checkboxes only allow boolean initial values, but buttons can - // take any LLSD. - params.initial_value(LLSD(p.initial_value)); - params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - - mButton = LLUICtrlFactory::create<LLButton>(params); - addChild(mButton); + } + + addChild(mLabel); + + // Button + // Note: button cover the label by extending all the way to the right and down. + LLRect btn_rect = p.check_button.rect(); + btn_rect.setOriginAndSize( + btn_rect.mLeft, + llmin(btn_rect.mBottom, label_rect.mBottom), + llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft), + llmax(label_rect.getHeight(), btn_rect.mTop)); + std::string active_true_id, active_false_id; + std::string inactive_true_id, inactive_false_id; + + LLButton::Params params = p.check_button; + params.rect(btn_rect); + //params.control_name(p.control_name); + params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onCommit, this)); + params.commit_on_return(false); + // Checkboxes only allow boolean initial values, but buttons can + // take any LLSD. + params.initial_value(LLSD(p.initial_value)); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + + mButton = LLUICtrlFactory::create<LLButton>(params); + addChild(mButton); } LLCheckBoxCtrl::~LLCheckBoxCtrl() { - // Children all cleaned up by default view destructor. + // Children all cleaned up by default view destructor. } void LLCheckBoxCtrl::onCommit() { - if( getEnabled() ) - { - setTentative(FALSE); - setControlValue(getValue()); - LLUICtrl::onCommit(); - } + if( getEnabled() ) + { + setTentative(FALSE); + setControlValue(getValue()); + LLUICtrl::onCommit(); + } } void LLCheckBoxCtrl::setEnabled(BOOL b) { - LLView::setEnabled(b); - - if (b) - { - mLabel->setColor( mTextEnabledColor.get() ); - } - else - { - mLabel->setColor( mTextDisabledColor.get() ); - } + LLView::setEnabled(b); + + if (b) + { + mLabel->setColor( mTextEnabledColor.get() ); + } + else + { + mLabel->setColor( mTextDisabledColor.get() ); + } } void LLCheckBoxCtrl::clear() { - setValue( FALSE ); + setValue( FALSE ); } void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) @@ -202,34 +202,34 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) // reshapeToFitText reshapes label to minimal size according to last bounding box // it will work fine in case of decrease of space, but if we get more space or text // becomes longer, label will fail to grow so reinit label's dimentions. - + LLRect label_rect = mLabel->getRect(); S32 new_width = rect.getWidth() - label_rect.mLeft; mLabel->reshape(new_width, label_rect.getHeight(), TRUE); - S32 label_top = label_rect.mTop; - mLabel->reshapeToFitText(TRUE); + S32 label_top = label_rect.mTop; + mLabel->reshapeToFitText(TRUE); label_rect = mLabel->getRect(); - if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN) - { - // reshapeToFitText uses LLView::reshape() which always reshapes - // from bottom to top, but we want to extend the bottom so - // reposition control - S32 delta = label_top - label_rect.mTop; - label_rect.translate(0, delta); - mLabel->setRect(label_rect); - } - - // Button - // Note: button cover the label by extending all the way to the right and down. - LLRect btn_rect = mButton->getRect(); - btn_rect.setOriginAndSize( - btn_rect.mLeft, - llmin(btn_rect.mBottom, label_rect.mBottom), - llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft), - llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight())); - mButton->setShape(btn_rect); + if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN) + { + // reshapeToFitText uses LLView::reshape() which always reshapes + // from bottom to top, but we want to extend the bottom so + // reposition control + S32 delta = label_top - label_rect.mTop; + label_rect.translate(0, delta); + mLabel->setRect(label_rect); + } + + // Button + // Note: button cover the label by extending all the way to the right and down. + LLRect btn_rect = mButton->getRect(); + btn_rect.setOriginAndSize( + btn_rect.mLeft, + llmin(btn_rect.mBottom, label_rect.mBottom), + llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft), + llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight())); + mButton->setShape(btn_rect); updateBoundingRect(); } @@ -237,68 +237,68 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) //virtual void LLCheckBoxCtrl::setValue(const LLSD& value ) { - mButton->setValue( value ); + mButton->setValue( value ); } //virtual LLSD LLCheckBoxCtrl::getValue() const { - return mButton->getValue(); + return mButton->getValue(); } //virtual void LLCheckBoxCtrl::setTentative(BOOL b) { - mButton->setTentative(b); + mButton->setTentative(b); } //virtual BOOL LLCheckBoxCtrl::getTentative() const { - return mButton->getTentative(); + return mButton->getTentative(); } void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label ) { - mLabel->setText( label ); - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + mLabel->setText( label ); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); } std::string LLCheckBoxCtrl::getLabel() const { - return mLabel->getText(); + return mLabel->getText(); } BOOL LLCheckBoxCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - BOOL res = mLabel->setTextArg(key, text); - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); - return res; + BOOL res = mLabel->setTextArg(key, text); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + return res; } // virtual void LLCheckBoxCtrl::setControlName(const std::string& control_name, LLView* context) { - mButton->setControlName(control_name, context); + mButton->setControlName(control_name, context); } -// virtual Returns TRUE if the user has modified this control. -BOOL LLCheckBoxCtrl::isDirty() const +// virtual Returns TRUE if the user has modified this control. +BOOL LLCheckBoxCtrl::isDirty() const { - if ( mButton ) - { - return mButton->isDirty(); - } - return FALSE; // Shouldn't get here + if ( mButton ) + { + return mButton->isDirty(); + } + return FALSE; // Shouldn't get here } -// virtual Clear dirty state -void LLCheckBoxCtrl::resetDirty() +// virtual Clear dirty state +void LLCheckBoxCtrl::resetDirty() { - if ( mButton ) - { - mButton->resetDirty(); - } + if ( mButton ) + { + mButton->resetDirty(); + } } diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index eb5bd5b6da..f2b61db308 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file llcheckboxctrl.h * @brief LLCheckBoxCtrl base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,8 +36,8 @@ // Constants // -const BOOL RADIO_STYLE = TRUE; -const BOOL CHECK_STYLE = FALSE; +const BOOL RADIO_STYLE = TRUE; +const BOOL CHECK_STYLE = FALSE; // // Classes @@ -63,95 +63,95 @@ public: static void declareValues(); }; - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> initial_value; // override LLUICtrl initial_value + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> initial_value; // override LLUICtrl initial_value - Optional<LLTextBox::Params> label_text; - Optional<LLButton::Params> check_button; + Optional<LLTextBox::Params> label_text; + Optional<LLButton::Params> check_button; - Optional<EWordWrap, WordWrap> word_wrap; + Optional<EWordWrap, WordWrap> word_wrap; - Ignored radio_style; + Ignored radio_style; - Params(); - }; + Params(); + }; - virtual ~LLCheckBoxCtrl(); + virtual ~LLCheckBoxCtrl(); protected: - LLCheckBoxCtrl(const Params&); - friend class LLUICtrlFactory; + LLCheckBoxCtrl(const Params&); + friend class LLUICtrlFactory; public: - // LLView interface + // LLView interface + + virtual void setEnabled( BOOL b ); - virtual void setEnabled( BOOL b ); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + // LLUICtrl interface + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const; + BOOL get() { return (BOOL)getValue().asBoolean(); } + void set(BOOL value) { setValue(value); } - // LLUICtrl interface - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - BOOL get() { return (BOOL)getValue().asBoolean(); } - void set(BOOL value) { setValue(value); } + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; - virtual void setTentative(BOOL b); - virtual BOOL getTentative() const; + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual void clear(); + virtual void onCommit(); - virtual void clear(); - virtual void onCommit(); + // LLCheckBoxCtrl interface + virtual BOOL toggle() { return mButton->toggleState(); } // returns new state - // LLCheckBoxCtrl interface - virtual BOOL toggle() { return mButton->toggleState(); } // returns new state + void setBtnFocus() { mButton->setFocus(TRUE); } - void setBtnFocus() { mButton->setFocus(TRUE); } + void setEnabledColor( const LLColor4 &color ) { mTextEnabledColor = color; } + void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; } - void setEnabledColor( const LLColor4 &color ) { mTextEnabledColor = color; } - void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; } + void setLabel( const LLStringExplicit& label ); + std::string getLabel() const; - void setLabel( const LLStringExplicit& label ); - std::string getLabel() const; + void setFont( const LLFontGL* font ) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } - void setFont( const LLFontGL* font ) { mFont = font; } - const LLFontGL* getFont() { return mFont; } - - virtual void setControlName(const std::string& control_name, LLView* context); + virtual void setControlName(const std::string& control_name, LLView* context); - virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. - virtual void resetDirty(); // Clear dirty state + virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. + virtual void resetDirty(); // Clear dirty state protected: - virtual std::string _getSearchText() const - { - return getLabel() + getToolTip(); - } + virtual std::string _getSearchText() const + { + return getLabel() + getToolTip(); + } - virtual void onSetHighlight() const // When highlight, really do highlight the label - { - if( mLabel ) - mLabel->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); - } + virtual void onSetHighlight() const // When highlight, really do highlight the label + { + if( mLabel ) + mLabel->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); + } protected: - // note: value is stored in toggle state of button - LLButton* mButton; - LLTextBox* mLabel; - const LLFontGL* mFont; + // note: value is stored in toggle state of button + LLButton* mButton; + LLTextBox* mLabel; + const LLFontGL* mFont; - LLUIColor mTextEnabledColor; - LLUIColor mTextDisabledColor; + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; - EWordWrap mWordWrap; // off, shifts text up, shifts text down + EWordWrap mWordWrap; // off, shifts text up, shifts text down }; // Build time optimization, generate once in .cpp file #ifndef LLCHECKBOXCTRL_CPP extern template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_LLCHECKBOXCTRL_H diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 06fac190ed..5132d33bbf 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llclipboard.cpp * @brief LLClipboard base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,121 +35,121 @@ #include "llwindow.h" LLClipboard::LLClipboard() : - mGeneration(0) + mGeneration(0) { - reset(); + reset(); } LLClipboard::~LLClipboard() { - reset(); + reset(); } void LLClipboard::reset() { - // Increment the clipboard count - mGeneration++; - // Clear the clipboard - mObjects.clear(); - mCutMode = false; - mString = LLWString(); + // Increment the clipboard count + mGeneration++; + // Clear the clipboard + mObjects.clear(); + mCutMode = false; + mString = LLWString(); } // Copy the input uuid to the LL clipboard bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type) { - reset(); - return addToClipboard(src, type); + reset(); + return addToClipboard(src, type); } // Add the input uuid to the LL clipboard // Convert the uuid to string and concatenate that string to the system clipboard if legit bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type) { - bool res = false; - if (src.notNull()) - { - res = true; - if (LLAssetType::lookupIsAssetIDKnowable(type)) - { - LLWString source = utf8str_to_wstring(src.asString()); - res = addToClipboard(source, 0, source.size()); - } - if (res) - { - mObjects.push_back(src); - mGeneration++; - } - } - return res; + bool res = false; + if (src.notNull()) + { + res = true; + if (LLAssetType::lookupIsAssetIDKnowable(type)) + { + LLWString source = utf8str_to_wstring(src.asString()); + res = addToClipboard(source, 0, source.size()); + } + if (res) + { + mObjects.push_back(src); + mGeneration++; + } + } + return res; } bool LLClipboard::pasteFromClipboard(std::vector<LLUUID>& inv_objects) const { - bool res = false; - S32 count = mObjects.size(); - inv_objects.reserve(inv_objects.size() + count); - if (count > 0) - { - res = true; - inv_objects.clear(); - for (S32 i = 0; i < count; i++) - { - inv_objects.push_back(mObjects[i]); - } - } - return res; + bool res = false; + S32 count = mObjects.size(); + inv_objects.reserve(inv_objects.size() + count); + if (count > 0) + { + res = true; + inv_objects.clear(); + for (S32 i = 0; i < count; i++) + { + inv_objects.push_back(mObjects[i]); + } + } + return res; } // Returns true if the LL Clipboard has pasteable items in it bool LLClipboard::hasContents() const { - return (mObjects.size() > 0); + return (mObjects.size() > 0); } // Returns true if the input uuid is in the list of clipboard objects bool LLClipboard::isOnClipboard(const LLUUID& object) const { - std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); - return (iter != mObjects.end()); + std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); + return (iter != mObjects.end()); } // Copy the input string to the LL and the system clipboard bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { - return addToClipboard(src, pos, len, use_primary); + return addToClipboard(src, pos, len, use_primary); } // Concatenate the input string to the LL and the system clipboard bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary) { - try - { - mString = src.substr(pos, len); - } - catch (const std::exception& e) - { - LL_WARNS() << "Can't add the substring to clipboard: " << e.what() << LL_ENDL; - return false; - } - return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); + try + { + mString = src.substr(pos, len); + } + catch (const std::exception& e) + { + LL_WARNS() << "Can't add the substring to clipboard: " << e.what() << LL_ENDL; + return false; + } + return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString)); } // Copy the System clipboard to the output string. // Manage the LL Clipboard / System clipboard consistency bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary) { - bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); - if (res) - { - mString = dst; - } - return res; + bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst)); + if (res) + { + mString = dst; + } + return res; } // Return true if there's something on the System clipboard bool LLClipboard::isTextAvailable(bool use_primary) const { - return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable()); + return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable()); } diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index a668ac1ac6..12d8233e0a 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -1,25 +1,25 @@ -/** +/** * @file llclipboard.h * @brief LLClipboard base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,56 +38,56 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLClipboard // -// This class is used to cut/copy/paste text strings and inventory items around +// This class is used to cut/copy/paste text strings and inventory items around // the world. Use LLClipboard::instance().method() to use its methods. // Note that the text and UUIDs are loosely coupled only. There are few cases // where the viewer does offer a serialized version of the UUID on the clipboard. -// In those case, the text is overridden when copying/cutting the item. +// In those case, the text is overridden when copying/cutting the item. // In all other cases, the text and the UUIDs are very much independent. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLClipboard : public LLSingleton<LLClipboard> { - LLSINGLETON(LLClipboard); - ~LLClipboard(); - + LLSINGLETON(LLClipboard); + ~LLClipboard(); + public: - // Clears the clipboard - void reset(); - // Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) - int getGeneration() const { return mGeneration; } + // Clears the clipboard + void reset(); + // Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state) + int getGeneration() const { return mGeneration; } + + // Text strings management: + // ------------------------ + // We support two flavors of text clipboards. The default is the explicitly + // copy-and-pasted clipboard. The second is the so-called 'primary' clipboard + // which is implicitly copied upon selection on platforms which expect this + // (i.e. X11/Linux, Mac). + bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); + bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); + bool pasteFromClipboard(LLWString& dst, bool use_primary = false); + bool isTextAvailable(bool use_primary = false) const; + + // Object list management: + // ----------------------- + // Clears and adds one single object to the clipboard + bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); + // Adds one object to the current list of objects on the clipboard + bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); + // Gets a copy of the objects on the clipboard + bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const; - // Text strings management: - // ------------------------ - // We support two flavors of text clipboards. The default is the explicitly - // copy-and-pasted clipboard. The second is the so-called 'primary' clipboard - // which is implicitly copied upon selection on platforms which expect this - // (i.e. X11/Linux, Mac). - bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); - bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false); - bool pasteFromClipboard(LLWString& dst, bool use_primary = false); - bool isTextAvailable(bool use_primary = false) const; - - // Object list management: - // ----------------------- - // Clears and adds one single object to the clipboard - bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); - // Adds one object to the current list of objects on the clipboard - bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE); - // Gets a copy of the objects on the clipboard - bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const; - - bool hasContents() const; // True if the clipboard has pasteable objects - bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard + bool hasContents() const; // True if the clipboard has pasteable objects + bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard - bool isCutMode() const { return mCutMode; } - void setCutMode(bool mode) { mCutMode = mode; mGeneration++; } + bool isCutMode() const { return mCutMode; } + void setCutMode(bool mode) { mCutMode = mode; mGeneration++; } private: - std::vector<LLUUID> mObjects; // Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) - LLWString mString; // The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable. - bool mCutMode; // This is a convenience flag for the viewer. - int mGeneration; // Incremented when the clipboard changes so that interested parties can check for changes on the clipboard. + std::vector<LLUUID> mObjects; // Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat) + LLWString mString; // The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable. + bool mCutMode; // This is a convenience flag for the viewer. + int mGeneration; // Incremented when the clipboard changes so that interested parties can check for changes on the clipboard. }; #endif // LL_LLCLIPBOARD_H diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 9ca05a16f3..71dd93d07d 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcombobox.cpp * @brief LLComboBox base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -58,274 +58,276 @@ static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_bo void LLComboBox::PreferredPositionValues::declareValues() { - declare("above", ABOVE); - declare("below", BELOW); + declare("above", ABOVE); + declare("below", BELOW); } LLComboBox::ItemParams::ItemParams() -: label("label") +: label("label") { } LLComboBox::Params::Params() -: allow_text_entry("allow_text_entry", false), - allow_new_values("allow_new_values", false), - show_text_as_tentative("show_text_as_tentative", true), - max_chars("max_chars", 20), - list_position("list_position", BELOW), - items("item"), - combo_button("combo_button"), - combo_list("combo_list"), - combo_editor("combo_editor"), - drop_down_button("drop_down_button") +: allow_text_entry("allow_text_entry", false), + allow_new_values("allow_new_values", false), + show_text_as_tentative("show_text_as_tentative", true), + max_chars("max_chars", 20), + list_position("list_position", BELOW), + items("item"), + combo_button("combo_button"), + combo_list("combo_list"), + combo_editor("combo_editor"), + drop_down_button("drop_down_button") { - addSynonym(items, "combo_item"); + addSynonym(items, "combo_item"); } LLComboBox::LLComboBox(const LLComboBox::Params& p) -: LLUICtrl(p), - mTextEntry(NULL), - mTextEntryTentative(p.show_text_as_tentative), - mHasAutocompletedText(false), - mAllowTextEntry(p.allow_text_entry), - mAllowNewValues(p.allow_new_values), - mMaxChars(p.max_chars), - mPrearrangeCallback(p.prearrange_callback()), - mTextEntryCallback(p.text_entry_callback()), - mTextChangedCallback(p.text_changed_callback()), - mListPosition(p.list_position), - mLastSelectedIndex(-1), - mLabel(p.label) -{ - // Text label button - - LLButton::Params button_params = (mAllowTextEntry ? p.combo_button : p.drop_down_button); - button_params.mouse_down_callback.function( - boost::bind(&LLComboBox::onButtonMouseDown, this)); - button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); - button_params.rect(p.rect); - - if(mAllowTextEntry) - { - button_params.pad_right(2); - } - - mArrowImage = button_params.image_unselected; +: LLUICtrl(p), + mTextEntry(NULL), + mTextEntryTentative(p.show_text_as_tentative), + mHasAutocompletedText(false), + mAllowTextEntry(p.allow_text_entry), + mAllowNewValues(p.allow_new_values), + mMaxChars(p.max_chars), + mPrearrangeCallback(p.prearrange_callback()), + mTextEntryCallback(p.text_entry_callback()), + mTextChangedCallback(p.text_changed_callback()), + mListPosition(p.list_position), + mLastSelectedIndex(-1), + mLabel(p.label) +{ + // Text label button + + LLButton::Params button_params = (mAllowTextEntry ? p.combo_button : p.drop_down_button); + button_params.mouse_down_callback.function( + boost::bind(&LLComboBox::onButtonMouseDown, this)); + button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); + button_params.rect(p.rect); + + if(mAllowTextEntry) + { + button_params.pad_right(2); + } + + mArrowImage = button_params.image_unselected; if (mArrowImage.notNull()) { mImageLoadedConnection = mArrowImage->addLoadedCallback(boost::bind(&LLComboBox::imageLoaded, this)); } - mButton = LLUICtrlFactory::create<LLButton>(button_params); + mButton = LLUICtrlFactory::create<LLButton>(button_params); - - if(mAllowTextEntry) - { - //redo to compensate for button hack that leaves space for a character - //unless it is a "minimal combobox"(drop down) - mButton->setRightHPad(2); - } - addChild(mButton); - LLScrollListCtrl::Params params = p.combo_list; - params.name("ComboBox"); - params.commit_callback.function(boost::bind(&LLComboBox::onItemSelected, this, _2)); - params.visible(false); - params.commit_on_keyboard_movement(false); + if(mAllowTextEntry) + { + //redo to compensate for button hack that leaves space for a character + //unless it is a "minimal combobox"(drop down) + mButton->setRightHPad(2); + } + addChild(mButton); - mList = LLUICtrlFactory::create<LLScrollListCtrl>(params); - addChild(mList); + LLScrollListCtrl::Params params = p.combo_list; + params.name("ComboBox"); + params.commit_callback.function(boost::bind(&LLComboBox::onItemSelected, this, _2)); + params.visible(false); + params.commit_on_keyboard_movement(false); - // Mouse-down on button will transfer mouse focus to the list - // Grab the mouse-up event and make sure the button state is correct - mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this)); + mList = LLUICtrlFactory::create<LLScrollListCtrl>(params); + addChild(mList); - for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); - it != p.items.end(); - ++it) - { - LLScrollListItem::Params item_params = *it; - if (it->label.isProvided()) - { - item_params.columns.add().value(it->label()); - } + // Mouse-down on button will transfer mouse focus to the list + // Grab the mouse-up event and make sure the button state is correct + mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this)); - mList->addRow(item_params); - } + for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); + it != p.items.end(); + ++it) + { + LLScrollListItem::Params item_params = *it; + if (it->label.isProvided()) + { + item_params.columns.add().value(it->label()); + } + + mList->addRow(item_params); + } - createLineEditor(p); + createLineEditor(p); - mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this)); + mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this)); } void LLComboBox::initFromParams(const LLComboBox::Params& p) { - LLUICtrl::initFromParams(p); + LLUICtrl::initFromParams(p); - if (!acceptsTextInput() && mLabel.empty()) - { - selectFirstItem(); - } + if (!acceptsTextInput() && mLabel.empty()) + { + selectFirstItem(); + } } // virtual BOOL LLComboBox::postBuild() { - if (mControlVariable) - { - setValue(mControlVariable->getValue()); // selects the appropriate item - } - return TRUE; + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + return TRUE; } LLComboBox::~LLComboBox() { - // children automatically deleted, including mMenu, mButton + // children automatically deleted, including mMenu, mButton - // explicitly disconect this signal, since base class destructor might fire top lost - mTopLostSignalConnection.disconnect(); + // explicitly disconect this signal, since base class destructor might fire top lost + mTopLostSignalConnection.disconnect(); mImageLoadedConnection.disconnect(); + + LLUI::getInstance()->removePopup(this); } void LLComboBox::clear() -{ - if (mTextEntry) - { - mTextEntry->setText(LLStringUtil::null); - } - mButton->setLabelSelected(LLStringUtil::null); - mButton->setLabelUnselected(LLStringUtil::null); - mList->deselectAllItems(); - mLastSelectedIndex = -1; +{ + if (mTextEntry) + { + mTextEntry->setText(LLStringUtil::null); + } + mButton->setLabelSelected(LLStringUtil::null); + mButton->setLabelUnselected(LLStringUtil::null); + mList->deselectAllItems(); + mLastSelectedIndex = -1; } void LLComboBox::onCommit() { - if (mAllowTextEntry && getCurrentIndex() != -1) - { - // we have selected an existing item, blitz the manual text entry with - // the properly capitalized item - mTextEntry->setValue(getSimple()); - mTextEntry->setTentative(FALSE); - } - setControlValue(getValue()); - LLUICtrl::onCommit(); + if (mAllowTextEntry && getCurrentIndex() != -1) + { + // we have selected an existing item, blitz the manual text entry with + // the properly capitalized item + mTextEntry->setValue(getSimple()); + mTextEntry->setTentative(FALSE); + } + setControlValue(getValue()); + LLUICtrl::onCommit(); } // virtual BOOL LLComboBox::isDirty() const { - BOOL grubby = FALSE; - if ( mList ) - { - grubby = mList->isDirty(); - } - return grubby; + BOOL grubby = FALSE; + if ( mList ) + { + grubby = mList->isDirty(); + } + return grubby; } // virtual Clear dirty state -void LLComboBox::resetDirty() +void LLComboBox::resetDirty() { - if ( mList ) - { - mList->resetDirty(); - } + if ( mList ) + { + mList->resetDirty(); + } } bool LLComboBox::itemExists(const std::string& name) { - return mList->getItemByLabel(name); + return mList->getItemByLabel(name); } // add item "name" to menu LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOOL enabled) { - LLScrollListItem* item = mList->addSimpleElement(name, pos); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) - { - if (mControlVariable) - { - setValue(mControlVariable->getValue()); // selects the appropriate item - } - else - { - selectFirstItem(); - } - } - return item; + LLScrollListItem* item = mList->addSimpleElement(name, pos); + item->setEnabled(enabled); + if (!mAllowTextEntry && mLabel.empty()) + { + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } + } + return item; } // add item "name" with a unique id to menu LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAddPosition pos, BOOL enabled ) { - LLScrollListItem* item = mList->addSimpleElement(name, pos, id); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) - { - if (mControlVariable) - { - setValue(mControlVariable->getValue()); // selects the appropriate item - } - else - { - selectFirstItem(); - } - } - return item; + LLScrollListItem* item = mList->addSimpleElement(name, pos, id); + item->setEnabled(enabled); + if (!mAllowTextEntry && mLabel.empty()) + { + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } + } + return item; } // add item "name" with attached userdata LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddPosition pos, BOOL enabled ) { - LLScrollListItem* item = mList->addSimpleElement(name, pos); - item->setEnabled(enabled); - item->setUserdata( userdata ); - if (!mAllowTextEntry && mLabel.empty()) - { - if (mControlVariable) - { - setValue(mControlVariable->getValue()); // selects the appropriate item - } - else - { - selectFirstItem(); - } - } - return item; + LLScrollListItem* item = mList->addSimpleElement(name, pos); + item->setEnabled(enabled); + item->setUserdata( userdata ); + if (!mAllowTextEntry && mLabel.empty()) + { + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } + } + return item; } // add item "name" with attached generic data LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosition pos, BOOL enabled ) { - LLScrollListItem* item = mList->addSimpleElement(name, pos, value); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) - { - if (mControlVariable) - { - setValue(mControlVariable->getValue()); // selects the appropriate item - } - else - { - selectFirstItem(); - } - } - return item; + LLScrollListItem* item = mList->addSimpleElement(name, pos, value); + item->setEnabled(enabled); + if (!mAllowTextEntry && mLabel.empty()) + { + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } + } + return item; } LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos) { - return mList->addSeparator(pos); + return mList->addSeparator(pos); } void LLComboBox::sortByName(BOOL ascending) { - mList->sortOnce(0, ascending); + mList->sortOnce(0, ascending); } @@ -333,190 +335,188 @@ void LLComboBox::sortByName(BOOL ascending) // Returns TRUE if the item was found. BOOL LLComboBox::setSimple(const LLStringExplicit& name) { - BOOL found = mList->selectItemByLabel(name, FALSE); + BOOL found = mList->selectItemByLabel(name, FALSE); - if (found) - { - setLabel(name); - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } + if (found) + { + setLabel(name); + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } - return found; + return found; } // virtual void LLComboBox::setValue(const LLSD& value) { - BOOL found = mList->selectByValue(value); - if (found) - { - LLScrollListItem* item = mList->getFirstSelected(); - if (item) - { - updateLabel(); - } - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } - else - { - mLastSelectedIndex = -1; - } + BOOL found = mList->selectByValue(value); + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + updateLabel(); + } + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else + { + mLastSelectedIndex = -1; + } } const std::string LLComboBox::getSimple() const { - const std::string res = getSelectedItemLabel(); - if (res.empty() && mAllowTextEntry) - { - return mTextEntry->getText(); - } - else - { - return res; - } + const std::string res = getSelectedItemLabel(); + if (res.empty() && mAllowTextEntry) + { + return mTextEntry->getText(); + } + else + { + return res; + } } const std::string LLComboBox::getSelectedItemLabel(S32 column) const { - return mList->getSelectedItemLabel(column); + return mList->getSelectedItemLabel(column); } // virtual LLSD LLComboBox::getValue() const { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return item->getValue(); - } - else if (mAllowTextEntry) - { - return mTextEntry->getValue(); - } - else - { - return LLSD(); - } + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return item->getValue(); + } + else if (mAllowTextEntry) + { + return mTextEntry->getValue(); + } + else + { + return LLSD(); + } } void LLComboBox::setLabel(const LLStringExplicit& name) { - if ( mTextEntry ) - { - mTextEntry->setText(name); - if (mList->selectItemByLabel(name, FALSE)) - { - mTextEntry->setTentative(FALSE); - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } - else - { - mTextEntry->setTentative(mTextEntryTentative); - } - } - - if (!mAllowTextEntry) - { - mButton->setLabel(name); - } + if ( mTextEntry ) + { + mTextEntry->setText(name); + if (mList->selectItemByLabel(name, FALSE)) + { + mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else + { + mTextEntry->setTentative(mTextEntryTentative); + } + } + + if (!mAllowTextEntry) + { + mButton->setLabel(name); + } } void LLComboBox::updateLabel() { - // Update the combo editor with the selected - // item label. - if (mTextEntry) - { - mTextEntry->setText(getSelectedItemLabel()); - mTextEntry->setTentative(FALSE); - } + // Update the combo editor with the selected + // item label. + if (mTextEntry) + { + mTextEntry->setText(getSelectedItemLabel()); + mTextEntry->setTentative(FALSE); + } - // If combo box doesn't allow text entry update - // the combo button label. - if (!mAllowTextEntry) - { - mButton->setLabel(getSelectedItemLabel()); - } + // If combo box doesn't allow text entry update + // the combo button label. + if (!mAllowTextEntry) + { + mButton->setLabel(getSelectedItemLabel()); + } } BOOL LLComboBox::remove(const std::string& name) { - BOOL found = mList->selectItemByLabel(name); + BOOL found = mList->selectItemByLabel(name); - if (found) - { - LLScrollListItem* item = mList->getFirstSelected(); - if (item) - { - mList->deleteSingleItem(mList->getItemIndex(item)); - } - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + mList->deleteSingleItem(mList->getItemIndex(item)); + } + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } - return found; + return found; } BOOL LLComboBox::remove(S32 index) { - if (index < mList->getItemCount()) - { - mList->deleteSingleItem(index); - setLabel(getSelectedItemLabel()); - return TRUE; - } - return FALSE; + if (index < mList->getItemCount()) + { + mList->deleteSingleItem(index); + setLabel(getSelectedItemLabel()); + return TRUE; + } + return FALSE; } // Keyboard focus lost. void LLComboBox::onFocusLost() { - hideList(); - // if valid selection - if (mAllowTextEntry && getCurrentIndex() != -1) - { - mTextEntry->selectAll(); - } - mButton->setForcePressedState(false); - LLUICtrl::onFocusLost(); + hideList(); + // if valid selection + if (mAllowTextEntry && getCurrentIndex() != -1) + { + mTextEntry->selectAll(); + } + mButton->setForcePressedState(false); + LLUICtrl::onFocusLost(); } void LLComboBox::setButtonVisible(BOOL visible) { - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); - - mButton->setVisible(visible); - if (mTextEntry) - { - LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - if (visible) - { - S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; - } - //mTextEntry->setRect(text_entry_rect); - mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); - } + mButton->setVisible(visible); + if (mTextEntry) + { + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + if (visible) + { + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; + } + //mTextEntry->setRect(text_entry_rect); + mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); + } } BOOL LLComboBox::setCurrentByIndex( S32 index ) { - BOOL found = mList->selectNthItem( index ); - if (found) - { - setLabel(getSelectedItemLabel()); - mLastSelectedIndex = index; - } - return found; + BOOL found = mList->selectNthItem( index ); + if (found) + { + setLabel(getSelectedItemLabel()); + mLastSelectedIndex = index; + } + return found; } S32 LLComboBox::getCurrentIndex() const { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return mList->getItemIndex( item ); - } - return -1; + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return mList->getItemIndex( item ); + } + return -1; } void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled) @@ -530,232 +530,231 @@ void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled) void LLComboBox::createLineEditor(const LLComboBox::Params& p) { - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); - LLRect rect = getLocalRect(); - if (mAllowTextEntry) - { - S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - S32 shadow_size = drop_shadow_button; - mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, - rect.mTop, rect.mRight, rect.mBottom)); - mButton->setTabStop(FALSE); - mButton->setHAlign(LLFontGL::HCENTER); - - LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; - // clear label on button - std::string cur_label = mButton->getLabelSelected(); - LLLineEditor::Params params = p.combo_editor; - params.rect(text_entry_rect); - params.default_text(LLStringUtil::null); - params.max_length.bytes(mMaxChars); - params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); - params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.commit_on_focus_lost(false); - params.follows.flags(FOLLOWS_ALL); - params.label(mLabel); - mTextEntry = LLUICtrlFactory::create<LLLineEditor> (params); - mTextEntry->setText(cur_label); - mTextEntry->setIgnoreTab(TRUE); - addChild(mTextEntry); - - // clear label on button - setLabel(LLStringUtil::null); - - mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); - } - else - { - mButton->setRect(rect); - mButton->setLabel(mLabel.getString()); - - if (mTextEntry) - { - mTextEntry->setVisible(FALSE); - } - } + LLRect rect = getLocalRect(); + if (mAllowTextEntry) + { + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + S32 shadow_size = BTN_DROP_SHADOW; + mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, + rect.mTop, rect.mRight, rect.mBottom)); + mButton->setTabStop(FALSE); + mButton->setHAlign(LLFontGL::HCENTER); + + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; + // clear label on button + std::string cur_label = mButton->getLabelSelected(); + LLLineEditor::Params params = p.combo_editor; + params.rect(text_entry_rect); + params.default_text(LLStringUtil::null); + params.max_length.bytes(mMaxChars); + params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); + params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); + params.commit_on_focus_lost(false); + params.follows.flags(FOLLOWS_ALL); + params.label(mLabel); + mTextEntry = LLUICtrlFactory::create<LLLineEditor> (params); + mTextEntry->setText(cur_label); + mTextEntry->setIgnoreTab(TRUE); + addChild(mTextEntry); + + // clear label on button + setLabel(LLStringUtil::null); + + mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); + } + else + { + mButton->setRect(rect); + mButton->setLabel(mLabel.getString()); + + if (mTextEntry) + { + mTextEntry->setVisible(FALSE); + } + } } void LLComboBox::setLeftTextPadding(S32 pad) { - S32 left_pad, right_pad; - mTextEntry->getTextPadding(&left_pad, &right_pad); - mTextEntry->setTextPadding(pad, right_pad); + S32 left_pad, right_pad; + mTextEntry->getTextPadding(&left_pad, &right_pad); + mTextEntry->setTextPadding(pad, right_pad); } void* LLComboBox::getCurrentUserdata() { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return item->getUserdata(); - } - return NULL; + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return item->getUserdata(); + } + return NULL; } void LLComboBox::showList() { - // Make sure we don't go off top of screen. - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - //HACK: shouldn't have to know about scale here - mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::getScaleFactor().mV[VY]) - 50 ); - - // Make sure that we can see the whole list - LLRect root_view_local; - LLView* root_view = getRootView(); - root_view->localRectToOtherView(root_view->getLocalRect(), &root_view_local, this); - - LLRect rect = mList->getRect(); - - S32 min_width = getRect().getWidth(); - S32 max_width = llmax(min_width, MAX_COMBO_WIDTH); - // make sure we have up to date content width metrics - S32 list_width = llclamp(mList->calcMaxContentWidth(), min_width, max_width); - - if (mListPosition == BELOW) - { - if (rect.getHeight() <= -root_view_local.mBottom) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, rect.getHeight() ); - } - else - { - // stack on top or bottom, depending on which has more room - if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); - } - else - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - } - } - else // ABOVE - { - if (rect.getHeight() <= root_view_local.mTop - getRect().getHeight()) - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - else - { - // stack on top or bottom, depending on which has more room - if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); - } - else - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - } - - } - mList->setOrigin(rect.mLeft, rect.mBottom); - mList->reshape(rect.getWidth(), rect.getHeight()); - mList->translateIntoRect(root_view_local); - - // Make sure we didn't go off bottom of screen - S32 x, y; - mList->localPointToScreen(0, 0, &x, &y); - - if (y < 0) - { - mList->translate(0, -y); - } - - // NB: this call will trigger the focuslost callback which will hide the list, so do it first - // before finally showing the list - - mList->setFocus(TRUE); - - // Show the list and push the button down - mButton->setToggleState(TRUE); - mList->setVisible(TRUE); - - LLUI::getInstance()->addPopup(this); - - setUseBoundingRect(TRUE); -// updateBoundingRect(); + // Make sure we don't go off top of screen. + LLCoordWindow window_size; + getWindow()->getSize(&window_size); + //HACK: shouldn't have to know about scale here + mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::getScaleFactor().mV[VY]) - 50 ); + + // Make sure that we can see the whole list + LLRect root_view_local; + LLView* root_view = getRootView(); + root_view->localRectToOtherView(root_view->getLocalRect(), &root_view_local, this); + + LLRect rect = mList->getRect(); + + S32 min_width = getRect().getWidth(); + S32 max_width = llmax(min_width, MAX_COMBO_WIDTH); + // make sure we have up to date content width metrics + S32 list_width = llclamp(mList->calcMaxContentWidth(), min_width, max_width); + + if (mListPosition == BELOW) + { + if (rect.getHeight() <= -root_view_local.mBottom) + { + // Move rect so it hangs off the bottom of this view + rect.setLeftTopAndSize(0, 0, list_width, rect.getHeight() ); + } + else + { + // stack on top or bottom, depending on which has more room + if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) + { + // Move rect so it hangs off the bottom of this view + rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); + } + else + { + // move rect so it stacks on top of this view (clipped to size of screen) + rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); + } + } + } + else // ABOVE + { + if (rect.getHeight() <= root_view_local.mTop - getRect().getHeight()) + { + // move rect so it stacks on top of this view (clipped to size of screen) + rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); + } + else + { + // stack on top or bottom, depending on which has more room + if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) + { + // Move rect so it hangs off the bottom of this view + rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); + } + else + { + // move rect so it stacks on top of this view (clipped to size of screen) + rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); + } + } + + } + mList->setOrigin(rect.mLeft, rect.mBottom); + mList->reshape(rect.getWidth(), rect.getHeight()); + mList->translateIntoRect(root_view_local); + + // Make sure we didn't go off bottom of screen + S32 x, y; + mList->localPointToScreen(0, 0, &x, &y); + + if (y < 0) + { + mList->translate(0, -y); + } + + // NB: this call will trigger the focuslost callback which will hide the list, so do it first + // before finally showing the list + + mList->setFocus(TRUE); + + // Show the list and push the button down + mButton->setToggleState(TRUE); + mList->setVisible(TRUE); + + LLUI::getInstance()->addPopup(this); + + setUseBoundingRect(TRUE); +// updateBoundingRect(); } void LLComboBox::hideList() { - if (mList->getVisible()) - { - // assert selection in list - if(mAllowNewValues) - { - // mLastSelectedIndex = -1 means that we entered a new value, don't select - // any of existing items in this case. - if(mLastSelectedIndex >= 0) - mList->selectNthItem(mLastSelectedIndex); - } - else if(mLastSelectedIndex >= 0) - mList->selectNthItem(mLastSelectedIndex); - - mButton->setToggleState(FALSE); - mList->setVisible(FALSE); - mList->mouseOverHighlightNthItem(-1); - - setUseBoundingRect(FALSE); - LLUI::getInstance()->removePopup(this); -// updateBoundingRect(); - } + if (mList->getVisible()) + { + // assert selection in list + if(mAllowNewValues) + { + // mLastSelectedIndex = -1 means that we entered a new value, don't select + // any of existing items in this case. + if(mLastSelectedIndex >= 0) + mList->selectNthItem(mLastSelectedIndex); + } + else if(mLastSelectedIndex >= 0) + mList->selectNthItem(mLastSelectedIndex); + + mButton->setToggleState(FALSE); + mList->setVisible(FALSE); + mList->mouseOverHighlightNthItem(-1); + + setUseBoundingRect(FALSE); + LLUI::getInstance()->removePopup(this); +// updateBoundingRect(); + } } void LLComboBox::onButtonMouseDown() { - if (!mList->getVisible()) - { - // this might change selection, so do it first - prearrangeList(); + if (!mList->getVisible()) + { + // this might change selection, so do it first + prearrangeList(); - // highlight the last selected item from the original selection before potentially selecting a new item - // as visual cue to original value of combo box - LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); - if (last_selected_item) - { - mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); - } + // highlight the last selected item from the original selection before potentially selecting a new item + // as visual cue to original value of combo box + LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); + if (last_selected_item) + { + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); + } - if (mList->getItemCount() != 0) - { - showList(); - } + if (mList->getItemCount() != 0) + { + showList(); + } - setFocus( TRUE ); + setFocus( TRUE ); - // pass mouse capture on to list if button is depressed - if (mButton->hasMouseCapture()) - { - gFocusMgr.setMouseCapture(mList); + // pass mouse capture on to list if button is depressed + if (mButton->hasMouseCapture()) + { + gFocusMgr.setMouseCapture(mList); - // But keep the "pressed" look, which buttons normally lose when they - // lose focus - mButton->setForcePressedState(true); - } - } - else - { - hideList(); - } + // But keep the "pressed" look, which buttons normally lose when they + // lose focus + mButton->setForcePressedState(true); + } + } + else + { + hideList(); + } } void LLComboBox::onListMouseUp() { - // In some cases this is the termination of a mouse click that started on - // the button, so clear its pressed state - mButton->setForcePressedState(false); + // In some cases this is the termination of a mouse click that started on + // the button, so clear its pressed state + mButton->setForcePressedState(false); } //------------------------------------------------------------------ @@ -764,282 +763,282 @@ void LLComboBox::onListMouseUp() void LLComboBox::onItemSelected(const LLSD& data) { - mLastSelectedIndex = getCurrentIndex(); - if (mLastSelectedIndex != -1) - { - updateLabel(); + mLastSelectedIndex = getCurrentIndex(); + if (mLastSelectedIndex != -1) + { + updateLabel(); - if (mAllowTextEntry) - { - gFocusMgr.setKeyboardFocus(mTextEntry); - mTextEntry->selectAll(); - } - } - // hiding the list reasserts the old value stored in the text editor/dropdown button - hideList(); + if (mAllowTextEntry) + { + gFocusMgr.setKeyboardFocus(mTextEntry); + mTextEntry->selectAll(); + } + } + // hiding the list reasserts the old value stored in the text editor/dropdown button + hideList(); - // commit does the reverse, asserting the value in the list - onCommit(); + // commit does the reverse, asserting the value in the list + onCommit(); } BOOL LLComboBox::handleToolTip(S32 x, S32 y, MASK mask) { std::string tool_tip; - if(LLUICtrl::handleToolTip(x, y, mask)) - { - return TRUE; - } - - tool_tip = getToolTip(); - if (tool_tip.empty()) - { - tool_tip = getSelectedItemLabel(); - } - - if( !tool_tip.empty() ) - { - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tool_tip) - .sticky_rect(calcScreenRect())); - } - return TRUE; + if(LLUICtrl::handleToolTip(x, y, mask)) + { + return TRUE; + } + + tool_tip = getToolTip(); + if (tool_tip.empty()) + { + tool_tip = getSelectedItemLabel(); + } + + if( !tool_tip.empty() ) + { + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tool_tip) + .sticky_rect(calcScreenRect())); + } + return TRUE; } BOOL LLComboBox::handleKeyHere(KEY key, MASK mask) { - BOOL result = FALSE; - if (hasFocus()) - { - if (mList->getVisible() - && key == KEY_ESCAPE && mask == MASK_NONE) - { - hideList(); - return TRUE; - } - //give list a chance to pop up and handle key - LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); - if (last_selected_item) - { - // highlight the original selection before potentially selecting a new item - mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); - } - result = mList->handleKeyHere(key, mask); - - // will only see return key if it is originating from line editor - // since the dropdown button eats the key - if (key == KEY_RETURN) - { - if (mask == MASK_NONE) - { - mOnReturnSignal(this, getValue()); - } - - // don't show list and don't eat key input when committing - // free-form text entry with RETURN since user already knows + BOOL result = FALSE; + if (hasFocus()) + { + if (mList->getVisible() + && key == KEY_ESCAPE && mask == MASK_NONE) + { + hideList(); + return TRUE; + } + //give list a chance to pop up and handle key + LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); + if (last_selected_item) + { + // highlight the original selection before potentially selecting a new item + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); + } + result = mList->handleKeyHere(key, mask); + + // will only see return key if it is originating from line editor + // since the dropdown button eats the key + if (key == KEY_RETURN) + { + if (mask == MASK_NONE) + { + mOnReturnSignal(this, getValue()); + } + + // don't show list and don't eat key input when committing + // free-form text entry with RETURN since user already knows // what they are trying to select - return FALSE; - } - // if selection has changed, pop open list - else if (mList->getLastSelectedItem() != last_selected_item - || ((key == KEY_DOWN || key == KEY_UP) - && mList->getCanSelect() - && !mList->isEmpty())) - { - showList(); - } - } - return result; + return FALSE; + } + // if selection has changed, pop open list + else if (mList->getLastSelectedItem() != last_selected_item + || ((key == KEY_DOWN || key == KEY_UP) + && mList->getCanSelect() + && !mList->isEmpty())) + { + showList(); + } + } + return result; } BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) { - BOOL result = FALSE; - if (gFocusMgr.childHasKeyboardFocus(this)) - { - // space bar just shows the list - if (' ' != uni_char ) - { - LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); - if (last_selected_item) - { - // highlight the original selection before potentially selecting a new item - mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); - } - result = mList->handleUnicodeCharHere(uni_char); - if (mList->getLastSelectedItem() != last_selected_item) - { - showList(); - } - } - } - return result; + BOOL result = FALSE; + if (gFocusMgr.childHasKeyboardFocus(this)) + { + // space bar just shows the list + if (' ' != uni_char ) + { + LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); + if (last_selected_item) + { + // highlight the original selection before potentially selecting a new item + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); + } + result = mList->handleUnicodeCharHere(uni_char); + if (mList->getLastSelectedItem() != last_selected_item) + { + showList(); + } + } + } + return result; } void LLComboBox::setTextEntry(const LLStringExplicit& text) { - if (mTextEntry) - { - mTextEntry->setText(text); - mHasAutocompletedText = FALSE; - updateSelection(); - } + if (mTextEntry) + { + mTextEntry->setText(text); + mHasAutocompletedText = FALSE; + updateSelection(); + } } void LLComboBox::setKeystrokeOnEsc(BOOL enable) { - if (mTextEntry) - { - mTextEntry->setKeystrokeOnEsc(enable); - } + if (mTextEntry) + { + mTextEntry->setKeystrokeOnEsc(enable); + } } void LLComboBox::onTextEntry(LLLineEditor* line_editor) { - if (mTextEntryCallback != NULL) - { - (mTextEntryCallback)(line_editor, LLSD()); - } - - KEY key = gKeyboard->currentKey(); - if (key == KEY_BACKSPACE || - key == KEY_DELETE) - { - if (mList->selectItemByLabel(line_editor->getText(), FALSE)) - { - line_editor->setTentative(FALSE); - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } - else - { - line_editor->setTentative(mTextEntryTentative); - mList->deselectAllItems(); - mLastSelectedIndex = -1; - } - if (mTextChangedCallback != NULL) - { - (mTextChangedCallback)(line_editor, LLSD()); - } - return; - } - - if (key == KEY_LEFT || - key == KEY_RIGHT) - { - return; - } - - if (key == KEY_DOWN) - { - setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1)); - if (!mList->getVisible()) - { - prearrangeList(); - - if (mList->getItemCount() != 0) - { - showList(); - } - } - line_editor->selectAll(); - line_editor->setTentative(FALSE); - } - else if (key == KEY_UP) - { - setCurrentByIndex(llmax(0, getCurrentIndex() - 1)); - if (!mList->getVisible()) - { - prearrangeList(); - - if (mList->getItemCount() != 0) - { - showList(); - } - } - line_editor->selectAll(); - line_editor->setTentative(FALSE); - } - else - { - // RN: presumably text entry - updateSelection(); - } - if (mTextChangedCallback != NULL) - { - (mTextChangedCallback)(line_editor, LLSD()); - } + if (mTextEntryCallback != NULL) + { + (mTextEntryCallback)(line_editor, LLSD()); + } + + KEY key = gKeyboard->currentKey(); + if (key == KEY_BACKSPACE || + key == KEY_DELETE) + { + if (mList->selectItemByLabel(line_editor->getText(), FALSE)) + { + line_editor->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else + { + line_editor->setTentative(mTextEntryTentative); + mList->deselectAllItems(); + mLastSelectedIndex = -1; + } + if (mTextChangedCallback != NULL) + { + (mTextChangedCallback)(line_editor, LLSD()); + } + return; + } + + if (key == KEY_LEFT || + key == KEY_RIGHT) + { + return; + } + + if (key == KEY_DOWN) + { + setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1)); + if (!mList->getVisible()) + { + prearrangeList(); + + if (mList->getItemCount() != 0) + { + showList(); + } + } + line_editor->selectAll(); + line_editor->setTentative(FALSE); + } + else if (key == KEY_UP) + { + setCurrentByIndex(llmax(0, getCurrentIndex() - 1)); + if (!mList->getVisible()) + { + prearrangeList(); + + if (mList->getItemCount() != 0) + { + showList(); + } + } + line_editor->selectAll(); + line_editor->setTentative(FALSE); + } + else + { + // RN: presumably text entry + updateSelection(); + } + if (mTextChangedCallback != NULL) + { + (mTextChangedCallback)(line_editor, LLSD()); + } } void LLComboBox::updateSelection() { - LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); - // user-entered portion of string, based on assumption that any selected + LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); + // user-entered portion of string, based on assumption that any selected // text was a result of auto-completion - LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText(); - std::string full_string = mTextEntry->getText(); - - // go ahead and arrange drop down list on first typed character, even - // though we aren't showing it... some code relies on prearrange - // callback to populate content - if( mTextEntry->getWText().size() == 1 ) - { - prearrangeList(mTextEntry->getText()); - } - - if (mList->selectItemByLabel(full_string, FALSE)) - { - mTextEntry->setTentative(FALSE); - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } - else if (mList->selectItemByPrefix(left_wstring, FALSE)) - { - LLWString selected_item = utf8str_to_wstring(getSelectedItemLabel()); - LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size()); - mTextEntry->setText(wstring_to_utf8str(wtext)); - mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size()); - mTextEntry->endSelection(); - mTextEntry->setTentative(FALSE); - mHasAutocompletedText = TRUE; - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } - else // no matching items found - { - mList->deselectAllItems(); - mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion - mTextEntry->setTentative(mTextEntryTentative); - mHasAutocompletedText = FALSE; - mLastSelectedIndex = -1; - } + LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText(); + std::string full_string = mTextEntry->getText(); + + // go ahead and arrange drop down list on first typed character, even + // though we aren't showing it... some code relies on prearrange + // callback to populate content + if( mTextEntry->getWText().size() == 1 ) + { + prearrangeList(mTextEntry->getText()); + } + + if (mList->selectItemByLabel(full_string, FALSE)) + { + mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else if (mList->selectItemByPrefix(left_wstring, FALSE)) + { + LLWString selected_item = utf8str_to_wstring(getSelectedItemLabel()); + LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size()); + mTextEntry->setText(wstring_to_utf8str(wtext)); + mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size()); + mTextEntry->endSelection(); + mTextEntry->setTentative(FALSE); + mHasAutocompletedText = TRUE; + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else // no matching items found + { + mList->deselectAllItems(); + mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion + mTextEntry->setTentative(mTextEntryTentative); + mHasAutocompletedText = FALSE; + mLastSelectedIndex = -1; + } } void LLComboBox::onTextCommit(const LLSD& data) { - std::string text = mTextEntry->getText(); - setSimple(text); - onCommit(); - mTextEntry->selectAll(); + std::string text = mTextEntry->getText(); + setSimple(text); + onCommit(); + mTextEntry->selectAll(); } void LLComboBox::setFocus(BOOL b) { - LLUICtrl::setFocus(b); + LLUICtrl::setFocus(b); - if (b) - { - mList->clearSearchString(); - if (mList->getVisible()) - { - mList->setFocus(TRUE); - } - } + if (b) + { + mList->clearSearchString(); + if (mList->getVisible()) + { + mList->setFocus(TRUE); + } + } } void LLComboBox::prearrangeList(std::string filter) { - if (mPrearrangeCallback) - { - mPrearrangeCallback(this, LLSD(filter)); - } + if (mPrearrangeCallback) + { + mPrearrangeCallback(this, LLSD(filter)); + } } @@ -1081,13 +1080,11 @@ void LLComboBox::onSetHighlight() const void LLComboBox::imageLoaded() { - static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0); - if (mAllowTextEntry) { LLRect rect = getLocalRect(); S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; - S32 shadow_size = drop_shadow_button; + S32 shadow_size = BTN_DROP_SHADOW; mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); if (mButton->getVisible()) @@ -1096,7 +1093,7 @@ void LLComboBox::imageLoaded() if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button; + text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * BTN_DROP_SHADOW; mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); } } @@ -1108,43 +1105,43 @@ void LLComboBox::imageLoaded() S32 LLComboBox::getItemCount() const { - return mList->getItemCount(); + return mList->getItemCount(); } void LLComboBox::addColumn(const LLSD& column, EAddPosition pos) { - mList->clearColumns(); - mList->addColumn(column, pos); + mList->clearColumns(); + mList->addColumn(column, pos); } void LLComboBox::clearColumns() { - mList->clearColumns(); + mList->clearColumns(); } void LLComboBox::setColumnLabel(const std::string& column, const std::string& label) { - mList->setColumnLabel(column, label); + mList->setColumnLabel(column, label); } LLScrollListItem* LLComboBox::addElement(const LLSD& value, EAddPosition pos, void* userdata) { - return mList->addElement(value, pos, userdata); + return mList->addElement(value, pos, userdata); } LLScrollListItem* LLComboBox::addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) { - return mList->addSimpleElement(value, pos, id); + return mList->addSimpleElement(value, pos, id); } void LLComboBox::clearRows() { - mList->clearRows(); + mList->clearRows(); } void LLComboBox::sortByColumn(const std::string& name, BOOL ascending) { - mList->sortByColumn(name, ascending); + mList->sortByColumn(name, ascending); } //============================================================================ @@ -1152,83 +1149,83 @@ void LLComboBox::sortByColumn(const std::string& name, BOOL ascending) BOOL LLComboBox::setCurrentByID(const LLUUID& id) { - BOOL found = mList->selectByID( id ); + BOOL found = mList->selectByID( id ); - if (found) - { - setLabel(getSelectedItemLabel()); - mLastSelectedIndex = mList->getFirstSelectedIndex(); - } + if (found) + { + setLabel(getSelectedItemLabel()); + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } - return found; + return found; } LLUUID LLComboBox::getCurrentID() const { - return mList->getStringUUIDSelectedItem(); + return mList->getStringUUIDSelectedItem(); } BOOL LLComboBox::setSelectedByValue(const LLSD& value, BOOL selected) { - BOOL found = mList->setSelectedByValue(value, selected); - if (found) - { - setLabel(getSelectedItemLabel()); - } - return found; + BOOL found = mList->setSelectedByValue(value, selected); + if (found) + { + setLabel(getSelectedItemLabel()); + } + return found; } LLSD LLComboBox::getSelectedValue() { - return mList->getSelectedValue(); + return mList->getSelectedValue(); } BOOL LLComboBox::isSelected(const LLSD& value) const { - return mList->isSelected(value); + return mList->isSelected(value); } BOOL LLComboBox::operateOnSelection(EOperation op) { - if (op == OP_DELETE) - { - mList->deleteSelectedItems(); - return TRUE; - } - return FALSE; + if (op == OP_DELETE) + { + mList->deleteSelectedItems(); + return TRUE; + } + return FALSE; } BOOL LLComboBox::operateOnAll(EOperation op) { - if (op == OP_DELETE) - { - clearRows(); - return TRUE; - } - return FALSE; + if (op == OP_DELETE) + { + clearRows(); + return TRUE; + } + return FALSE; } BOOL LLComboBox::selectItemRange( S32 first, S32 last ) { - return mList->selectItemRange(first, last); + return mList->selectItemRange(first, last); } static LLDefaultChildRegistry::Register<LLIconsComboBox> register_icons_combo_box("icons_combo_box"); LLIconsComboBox::Params::Params() -: icon_column("icon_column", ICON_COLUMN), - label_column("label_column", LABEL_COLUMN) +: icon_column("icon_column", ICON_COLUMN), + label_column("label_column", LABEL_COLUMN) {} LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p) -: LLComboBox(p), - mIconColumnIndex(p.icon_column), - mLabelColumnIndex(p.label_column) +: LLComboBox(p), + mIconColumnIndex(p.icon_column), + mLabelColumnIndex(p.label_column) {} const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const { - mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign()); + mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign()); - return LLComboBox::getSelectedItemLabel(mLabelColumnIndex); + return LLComboBox::getSelectedItemLabel(mLabelColumnIndex); } diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index cac8850a25..93382a1022 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -1,25 +1,25 @@ -/** +/** * @file llcombobox.h * @brief LLComboBox base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,59 +48,59 @@ class LLComboBox , public LLCtrlListInterface , public ll::ui::SearchableControl { -public: - typedef enum e_preferred_position - { - ABOVE, - BELOW - } EPreferredPosition; - - struct PreferredPositionValues : public LLInitParam::TypeValuesHelper<EPreferredPosition, PreferredPositionValues> - { - static void declareValues(); - }; - - - struct ItemParams : public LLInitParam::Block<ItemParams, LLScrollListItem::Params> - { - Optional<std::string> label; - ItemParams(); - }; - - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> allow_text_entry, - show_text_as_tentative, - allow_new_values; - Optional<S32> max_chars; - Optional<commit_callback_t> prearrange_callback, - text_entry_callback, - text_changed_callback; - - Optional<EPreferredPosition, PreferredPositionValues> list_position; - - // components - Optional<LLButton::Params> combo_button; - Optional<LLScrollListCtrl::Params> combo_list; - Optional<LLLineEditor::Params> combo_editor; - - Optional<LLButton::Params> drop_down_button; - - Multiple<ItemParams> items; - - Params(); - }; - - - virtual ~LLComboBox(); - /*virtual*/ BOOL postBuild(); - +public: + typedef enum e_preferred_position + { + ABOVE, + BELOW + } EPreferredPosition; + + struct PreferredPositionValues : public LLInitParam::TypeValuesHelper<EPreferredPosition, PreferredPositionValues> + { + static void declareValues(); + }; + + + struct ItemParams : public LLInitParam::Block<ItemParams, LLScrollListItem::Params> + { + Optional<std::string> label; + ItemParams(); + }; + + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> allow_text_entry, + show_text_as_tentative, + allow_new_values; + Optional<S32> max_chars; + Optional<commit_callback_t> prearrange_callback, + text_entry_callback, + text_changed_callback; + + Optional<EPreferredPosition, PreferredPositionValues> list_position; + + // components + Optional<LLButton::Params> combo_button; + Optional<LLScrollListCtrl::Params> combo_list; + Optional<LLLineEditor::Params> combo_editor; + + Optional<LLButton::Params> drop_down_button; + + Multiple<ItemParams> items; + + Params(); + }; + + + virtual ~LLComboBox(); + /*virtual*/ BOOL postBuild(); + protected: - friend class LLUICtrlFactory; - LLComboBox(const Params&); - void initFromParams(const Params&); - void prearrangeList(std::string filter = ""); + friend class LLUICtrlFactory; + LLComboBox(const Params&); + void initFromParams(const Params&); + void prearrangeList(std::string filter = ""); virtual std::string _getSearchText() const; virtual void onSetHighlight() const; @@ -108,177 +108,177 @@ protected: void imageLoaded(); public: - // LLView interface - virtual void onFocusLost(); - - virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - - // LLUICtrl interface - virtual void clear(); // select nothing - virtual void onCommit(); - virtual BOOL acceptsTextInput() const { return mAllowTextEntry; } - virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. - virtual void resetDirty(); // Clear dirty state - - virtual void setFocus(BOOL b); - - // Selects item by underlying LLSD value, using LLSD::asString() matching. - // For simple items, this is just the name of the label. - virtual void setValue(const LLSD& value ); - - // Gets underlying LLSD value for currently selected items. For simple - // items, this is just the label. - virtual LLSD getValue() const; - - void setTextEntry(const LLStringExplicit& text); - void setKeystrokeOnEsc(BOOL enable); - - LLScrollListItem* add(const std::string& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu - LLScrollListItem* add(const std::string& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - LLScrollListItem* add(const std::string& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - LLScrollListItem* add(const std::string& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM); - BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed - void removeall() { clearRows(); } - bool itemExists(const std::string& name); - - void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name - - // Select current item by name using selectItemByLabel. Returns FALSE if not found. - BOOL setSimple(const LLStringExplicit& name); - // Get name of current item. Returns an empty string if not found. - const std::string getSimple() const; - // Get contents of column x of selected row - virtual const std::string getSelectedItemLabel(S32 column = 0) const; - - // Sets the label, which doesn't have to exist in the label. - // This is probably a UI abuse. - void setLabel(const LLStringExplicit& name); - - // Updates the combobox label to match the selected list item. - void updateLabel(); - - BOOL remove(const std::string& name); // remove item "name", return TRUE if found and removed - - BOOL setCurrentByIndex( S32 index ); - S32 getCurrentIndex() const; - - void setEnabledByValue(const LLSD& value, BOOL enabled); - - void createLineEditor(const Params&); - - //======================================================================== - LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; - LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; }; - - // LLCtrlListInterface functions - // See llscrolllistctrl.h - virtual S32 getItemCount() const; - // Overwrites the default column (See LLScrollListCtrl for format) - virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM); - virtual void clearColumns(); - virtual void setColumnLabel(const std::string& column, const std::string& label); - virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); - virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); - virtual void clearRows(); - virtual void sortByColumn(const std::string& name, BOOL ascending); - - // LLCtrlSelectionInterface functions - virtual BOOL getCanSelect() const { return TRUE; } - virtual BOOL selectFirstItem() { return setCurrentByIndex(0); } - virtual BOOL selectNthItem( S32 index ) { return setCurrentByIndex(index); } - virtual BOOL selectItemRange( S32 first, S32 last ); - virtual S32 getFirstSelectedIndex() const { return getCurrentIndex(); } - virtual BOOL setCurrentByID( const LLUUID& id ); - virtual LLUUID getCurrentID() const; // LLUUID::null if no items in menu - virtual BOOL setSelectedByValue(const LLSD& value, BOOL selected); - virtual LLSD getSelectedValue(); - virtual BOOL isSelected(const LLSD& value) const; - virtual BOOL operateOnSelection(EOperation op); - virtual BOOL operateOnAll(EOperation op); - - //======================================================================== - - void setLeftTextPadding(S32 pad); - - void* getCurrentUserdata(); - - void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; } - void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; } - void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } - - /** - * Connects callback to signal called when Return key is pressed. - */ - boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } - - void setButtonVisible(BOOL visible); - - void onButtonMouseDown(); - void onListMouseUp(); - void onItemSelected(const LLSD& data); - void onTextCommit(const LLSD& data); - - void updateSelection(); - virtual void showList(); - virtual void hideList(); - - virtual void onTextEntry(LLLineEditor* line_editor); - + // LLView interface + virtual void onFocusLost(); + + virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); + + // LLUICtrl interface + virtual void clear(); // select nothing + virtual void onCommit(); + virtual BOOL acceptsTextInput() const { return mAllowTextEntry; } + virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. + virtual void resetDirty(); // Clear dirty state + + virtual void setFocus(BOOL b); + + // Selects item by underlying LLSD value, using LLSD::asString() matching. + // For simple items, this is just the name of the label. + virtual void setValue(const LLSD& value ); + + // Gets underlying LLSD value for currently selected items. For simple + // items, this is just the label. + virtual LLSD getValue() const; + + void setTextEntry(const LLStringExplicit& text); + void setKeystrokeOnEsc(BOOL enable); + + LLScrollListItem* add(const std::string& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu + LLScrollListItem* add(const std::string& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); + LLScrollListItem* add(const std::string& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); + LLScrollListItem* add(const std::string& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); + LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM); + BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed + void removeall() { clearRows(); } + bool itemExists(const std::string& name); + + void sortByName(BOOL ascending = TRUE); // Sort the entries in the combobox by name + + // Select current item by name using selectItemByLabel. Returns FALSE if not found. + BOOL setSimple(const LLStringExplicit& name); + // Get name of current item. Returns an empty string if not found. + const std::string getSimple() const; + // Get contents of column x of selected row + virtual const std::string getSelectedItemLabel(S32 column = 0) const; + + // Sets the label, which doesn't have to exist in the label. + // This is probably a UI abuse. + void setLabel(const LLStringExplicit& name); + + // Updates the combobox label to match the selected list item. + void updateLabel(); + + BOOL remove(const std::string& name); // remove item "name", return TRUE if found and removed + + BOOL setCurrentByIndex( S32 index ); + S32 getCurrentIndex() const; + + void setEnabledByValue(const LLSD& value, BOOL enabled); + + void createLineEditor(const Params&); + + //======================================================================== + LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; + LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; }; + + // LLCtrlListInterface functions + // See llscrolllistctrl.h + virtual S32 getItemCount() const; + // Overwrites the default column (See LLScrollListCtrl for format) + virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM); + virtual void clearColumns(); + virtual void setColumnLabel(const std::string& column, const std::string& label); + virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); + virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); + virtual void clearRows(); + virtual void sortByColumn(const std::string& name, BOOL ascending); + + // LLCtrlSelectionInterface functions + virtual BOOL getCanSelect() const { return TRUE; } + virtual BOOL selectFirstItem() { return setCurrentByIndex(0); } + virtual BOOL selectNthItem( S32 index ) { return setCurrentByIndex(index); } + virtual BOOL selectItemRange( S32 first, S32 last ); + virtual S32 getFirstSelectedIndex() const { return getCurrentIndex(); } + virtual BOOL setCurrentByID( const LLUUID& id ); + virtual LLUUID getCurrentID() const; // LLUUID::null if no items in menu + virtual BOOL setSelectedByValue(const LLSD& value, BOOL selected); + virtual LLSD getSelectedValue(); + virtual BOOL isSelected(const LLSD& value) const; + virtual BOOL operateOnSelection(EOperation op); + virtual BOOL operateOnAll(EOperation op); + + //======================================================================== + + void setLeftTextPadding(S32 pad); + + void* getCurrentUserdata(); + + void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; } + void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; } + void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } + + /** + * Connects callback to signal called when Return key is pressed. + */ + boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } + + void setButtonVisible(BOOL visible); + + void onButtonMouseDown(); + void onListMouseUp(); + void onItemSelected(const LLSD& data); + void onTextCommit(const LLSD& data); + + void updateSelection(); + virtual void showList(); + virtual void hideList(); + + virtual void onTextEntry(LLLineEditor* line_editor); + protected: - LLButton* mButton; - LLLineEditor* mTextEntry; - LLScrollListCtrl* mList; - EPreferredPosition mListPosition; - LLPointer<LLUIImage> mArrowImage; - LLUIString mLabel; - BOOL mHasAutocompletedText; + LLButton* mButton; + LLLineEditor* mTextEntry; + LLScrollListCtrl* mList; + EPreferredPosition mListPosition; + LLPointer<LLUIImage> mArrowImage; + LLUIString mLabel; + BOOL mHasAutocompletedText; private: - BOOL mAllowTextEntry; - BOOL mAllowNewValues; - S32 mMaxChars; - BOOL mTextEntryTentative; - commit_callback_t mPrearrangeCallback; - commit_callback_t mTextEntryCallback; - commit_callback_t mTextChangedCallback; - commit_callback_t mSelectionCallback; - boost::signals2::connection mTopLostSignalConnection; + BOOL mAllowTextEntry; + BOOL mAllowNewValues; + S32 mMaxChars; + BOOL mTextEntryTentative; + commit_callback_t mPrearrangeCallback; + commit_callback_t mTextEntryCallback; + commit_callback_t mTextChangedCallback; + commit_callback_t mSelectionCallback; + boost::signals2::connection mTopLostSignalConnection; boost::signals2::connection mImageLoadedConnection; - commit_signal_t mOnReturnSignal; - S32 mLastSelectedIndex; + commit_signal_t mOnReturnSignal; + S32 mLastSelectedIndex; }; // A combo box with icons for the list of items. class LLIconsComboBox -: public LLComboBox +: public LLComboBox { public: - struct Params - : public LLInitParam::Block<Params, LLComboBox::Params> - { - Optional<S32> icon_column, - label_column; - Params(); - }; + struct Params + : public LLInitParam::Block<Params, LLComboBox::Params> + { + Optional<S32> icon_column, + label_column; + Params(); + }; - /*virtual*/ const std::string getSelectedItemLabel(S32 column = 0) const; + /*virtual*/ const std::string getSelectedItemLabel(S32 column = 0) const; private: - enum EColumnIndex - { - ICON_COLUMN = 0, - LABEL_COLUMN - }; - - friend class LLUICtrlFactory; - LLIconsComboBox(const Params&); - virtual ~LLIconsComboBox() {}; - - S32 mIconColumnIndex; - S32 mLabelColumnIndex; + enum EColumnIndex + { + ICON_COLUMN = 0, + LABEL_COLUMN + }; + + friend class LLUICtrlFactory; + LLIconsComboBox(const Params&); + virtual ~LLIconsComboBox() {}; + + S32 mIconColumnIndex; + S32 mLabelColumnIndex; }; #endif diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index 8ef7bd837f..270ec86e01 100644 --- a/indra/llui/llcommandmanager.cpp +++ b/indra/llui/llcommandmanager.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcommandmanager.cpp * @brief LLCommandManager class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,43 +46,43 @@ const LLCommandId LLCommandId::null = LLCommandId("null command"); // LLCommand::Params::Params() - : available_in_toybox("available_in_toybox", false) - , icon("icon") - , label_ref("label_ref") - , name("name") - , tooltip_ref("tooltip_ref") - , execute_function("execute_function") - , execute_parameters("execute_parameters") - , execute_stop_function("execute_stop_function") - , execute_stop_parameters("execute_stop_parameters") - , is_enabled_function("is_enabled_function") - , is_enabled_parameters("is_enabled_parameters") - , is_running_function("is_running_function") - , is_running_parameters("is_running_parameters") - , is_starting_function("is_starting_function") - , is_starting_parameters("is_starting_parameters") - , is_flashing_allowed("is_flashing_allowed", false) + : available_in_toybox("available_in_toybox", false) + , icon("icon") + , label_ref("label_ref") + , name("name") + , tooltip_ref("tooltip_ref") + , execute_function("execute_function") + , execute_parameters("execute_parameters") + , execute_stop_function("execute_stop_function") + , execute_stop_parameters("execute_stop_parameters") + , is_enabled_function("is_enabled_function") + , is_enabled_parameters("is_enabled_parameters") + , is_running_function("is_running_function") + , is_running_parameters("is_running_parameters") + , is_starting_function("is_starting_function") + , is_starting_parameters("is_starting_parameters") + , is_flashing_allowed("is_flashing_allowed", false) { } LLCommand::LLCommand(const LLCommand::Params& p) - : mIdentifier(p.name) - , mAvailableInToybox(p.available_in_toybox) - , mIcon(p.icon) - , mLabelRef(p.label_ref) - , mName(p.name) - , mTooltipRef(p.tooltip_ref) - , mExecuteFunction(p.execute_function) - , mExecuteParameters(p.execute_parameters) - , mExecuteStopFunction(p.execute_stop_function) - , mExecuteStopParameters(p.execute_stop_parameters) - , mIsEnabledFunction(p.is_enabled_function) - , mIsEnabledParameters(p.is_enabled_parameters) - , mIsRunningFunction(p.is_running_function) - , mIsRunningParameters(p.is_running_parameters) - , mIsStartingFunction(p.is_starting_function) - , mIsStartingParameters(p.is_starting_parameters) - , mIsFlashingAllowed(p.is_flashing_allowed) + : mIdentifier(p.name) + , mAvailableInToybox(p.available_in_toybox) + , mIcon(p.icon) + , mLabelRef(p.label_ref) + , mName(p.name) + , mTooltipRef(p.tooltip_ref) + , mExecuteFunction(p.execute_function) + , mExecuteParameters(p.execute_parameters) + , mExecuteStopFunction(p.execute_stop_function) + , mExecuteStopParameters(p.execute_stop_parameters) + , mIsEnabledFunction(p.is_enabled_function) + , mIsEnabledParameters(p.is_enabled_parameters) + , mIsRunningFunction(p.is_running_function) + , mIsRunningParameters(p.is_running_parameters) + , mIsStartingFunction(p.is_starting_function) + , mIsStartingParameters(p.is_starting_parameters) + , mIsFlashingAllowed(p.is_flashing_allowed) { } @@ -97,95 +97,95 @@ LLCommandManager::LLCommandManager() LLCommandManager::~LLCommandManager() { - for (CommandVector::iterator cmdIt = mCommands.begin(); cmdIt != mCommands.end(); ++cmdIt) - { - LLCommand * command = *cmdIt; + for (CommandVector::iterator cmdIt = mCommands.begin(); cmdIt != mCommands.end(); ++cmdIt) + { + LLCommand * command = *cmdIt; - delete command; - } + delete command; + } } U32 LLCommandManager::commandCount() const { - return mCommands.size(); + return mCommands.size(); } LLCommand * LLCommandManager::getCommand(U32 commandIndex) { - return mCommands[commandIndex]; + return mCommands[commandIndex]; } LLCommand * LLCommandManager::getCommand(const LLCommandId& commandId) { - LLCommand * command_match = NULL; + LLCommand * command_match = NULL; + + CommandIndexMap::const_iterator found = mCommandIndices.find(commandId.uuid()); - CommandIndexMap::const_iterator found = mCommandIndices.find(commandId.uuid()); - - if (found != mCommandIndices.end()) - { - command_match = mCommands[found->second]; - } + if (found != mCommandIndices.end()) + { + command_match = mCommands[found->second]; + } - return command_match; + return command_match; } LLCommand * LLCommandManager::getCommand(const std::string& name) { - LLCommand * command_match = NULL; - - CommandVector::const_iterator it = mCommands.begin(); - - while (it != mCommands.end()) - { + LLCommand * command_match = NULL; + + CommandVector::const_iterator it = mCommands.begin(); + + while (it != mCommands.end()) + { if ((*it)->name() == name) { command_match = *it; break; } it++; - } - - return command_match; + } + + return command_match; } void LLCommandManager::addCommand(LLCommand * command) { - LLCommandId command_id = command->id(); - mCommandIndices[command_id.uuid()] = mCommands.size(); - mCommands.push_back(command); + LLCommandId command_id = command->id(); + mCommandIndices[command_id.uuid()] = mCommands.size(); + mCommands.push_back(command); - LL_DEBUGS() << "Successfully added command: " << command->name() << LL_ENDL; + LL_DEBUGS() << "Successfully added command: " << command->name() << LL_ENDL; } //static bool LLCommandManager::load() { - LLCommandManager& mgr = LLCommandManager::instance(); + LLCommandManager& mgr = LLCommandManager::instance(); + + std::string commands_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "commands.xml"); - std::string commands_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "commands.xml"); + LLCommandManager::Params commandsParams; - LLCommandManager::Params commandsParams; + LLSimpleXUIParser parser; - LLSimpleXUIParser parser; - - if (!parser.readXUI(commands_file, commandsParams)) - { - LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL; - return false; - } + if (!parser.readXUI(commands_file, commandsParams)) + { + LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL; + return false; + } - if (!commandsParams.validateBlock()) - { - LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL; - return false; - } + if (!commandsParams.validateBlock()) + { + LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL; + return false; + } - for (const LLCommand::Params& commandParams : commandsParams.commands) - { - LLCommand * command = new LLCommand(commandParams); + for (const LLCommand::Params& commandParams : commandsParams.commands) + { + LLCommand * command = new LLCommand(commandParams); - mgr.addCommand(command); - } + mgr.addCommand(command); + } - return true; + return true; } diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h index 8cec5e2b24..3b2586a5a1 100644 --- a/indra/llui/llcommandmanager.h +++ b/indra/llui/llcommandmanager.h @@ -1,25 +1,25 @@ -/** +/** * @file llcommandmanager.h * @brief LLCommandManager class to hold commands * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,48 +38,48 @@ class LLCommandManager; class LLCommandId { public: - friend class LLCommand; - friend class LLCommandManager; - - struct Params : public LLInitParam::Block<Params> - { - Mandatory<std::string> name; - - Params() - : name("name") - {} - }; - - LLCommandId(const std::string& name) - { - mUUID = LLUUID::generateNewID(name); - } - - LLCommandId(const Params& p) - { - mUUID = LLUUID::generateNewID(p.name); - } - - LLCommandId(const LLUUID& uuid) - : mUUID(uuid) - {} - - const LLUUID& uuid() const { return mUUID; } - - bool operator!=(const LLCommandId& command) const - { - return (mUUID != command.mUUID); - } - - bool operator==(const LLCommandId& command) const - { - return (mUUID == command.mUUID); - } - - static const LLCommandId null; + friend class LLCommand; + friend class LLCommandManager; + + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; + + Params() + : name("name") + {} + }; + + LLCommandId(const std::string& name) + { + mUUID = LLUUID::generateNewID(name); + } + + LLCommandId(const Params& p) + { + mUUID = LLUUID::generateNewID(p.name); + } + + LLCommandId(const LLUUID& uuid) + : mUUID(uuid) + {} + + const LLUUID& uuid() const { return mUUID; } + + bool operator!=(const LLCommandId& command) const + { + return (mUUID != command.mUUID); + } + + bool operator==(const LLCommandId& command) const + { + return (mUUID == command.mUUID); + } + + static const LLCommandId null; private: - LLUUID mUUID; + LLUUID mUUID; }; typedef std::list<LLCommandId> command_id_list_t; @@ -88,121 +88,121 @@ typedef std::list<LLCommandId> command_id_list_t; class LLCommand { public: - struct Params : public LLInitParam::Block<Params> - { - Mandatory<bool> available_in_toybox; - Mandatory<std::string> icon; - Mandatory<std::string> label_ref; - Mandatory<std::string> name; - Mandatory<std::string> tooltip_ref; + struct Params : public LLInitParam::Block<Params> + { + Mandatory<bool> available_in_toybox; + Mandatory<std::string> icon; + Mandatory<std::string> label_ref; + Mandatory<std::string> name; + Mandatory<std::string> tooltip_ref; - Mandatory<std::string> execute_function; - Optional<LLSD> execute_parameters; + Mandatory<std::string> execute_function; + Optional<LLSD> execute_parameters; - Optional<std::string> execute_stop_function; - Optional<LLSD> execute_stop_parameters; - - Optional<std::string> is_enabled_function; - Optional<LLSD> is_enabled_parameters; + Optional<std::string> execute_stop_function; + Optional<LLSD> execute_stop_parameters; - Optional<std::string> is_running_function; - Optional<LLSD> is_running_parameters; + Optional<std::string> is_enabled_function; + Optional<LLSD> is_enabled_parameters; - Optional<std::string> is_starting_function; - Optional<LLSD> is_starting_parameters; + Optional<std::string> is_running_function; + Optional<LLSD> is_running_parameters; - Optional<bool> is_flashing_allowed; + Optional<std::string> is_starting_function; + Optional<LLSD> is_starting_parameters; - Params(); - }; + Optional<bool> is_flashing_allowed; - LLCommand(const LLCommand::Params& p); + Params(); + }; - const bool availableInToybox() const { return mAvailableInToybox; } - const std::string& icon() const { return mIcon; } - const LLCommandId& id() const { return mIdentifier; } - const std::string& labelRef() const { return mLabelRef; } - const std::string& name() const { return mName; } - const std::string& tooltipRef() const { return mTooltipRef; } + LLCommand(const LLCommand::Params& p); - const std::string& executeFunctionName() const { return mExecuteFunction; } - const LLSD& executeParameters() const { return mExecuteParameters; } + const bool availableInToybox() const { return mAvailableInToybox; } + const std::string& icon() const { return mIcon; } + const LLCommandId& id() const { return mIdentifier; } + const std::string& labelRef() const { return mLabelRef; } + const std::string& name() const { return mName; } + const std::string& tooltipRef() const { return mTooltipRef; } - const std::string& executeStopFunctionName() const { return mExecuteStopFunction; } - const LLSD& executeStopParameters() const { return mExecuteStopParameters; } - - const std::string& isEnabledFunctionName() const { return mIsEnabledFunction; } - const LLSD& isEnabledParameters() const { return mIsEnabledParameters; } + const std::string& executeFunctionName() const { return mExecuteFunction; } + const LLSD& executeParameters() const { return mExecuteParameters; } - const std::string& isRunningFunctionName() const { return mIsRunningFunction; } - const LLSD& isRunningParameters() const { return mIsRunningParameters; } + const std::string& executeStopFunctionName() const { return mExecuteStopFunction; } + const LLSD& executeStopParameters() const { return mExecuteStopParameters; } - const std::string& isStartingFunctionName() const { return mIsStartingFunction; } - const LLSD& isStartingParameters() const { return mIsStartingParameters; } + const std::string& isEnabledFunctionName() const { return mIsEnabledFunction; } + const LLSD& isEnabledParameters() const { return mIsEnabledParameters; } - bool isFlashingAllowed() const { return mIsFlashingAllowed; } + const std::string& isRunningFunctionName() const { return mIsRunningFunction; } + const LLSD& isRunningParameters() const { return mIsRunningParameters; } + + const std::string& isStartingFunctionName() const { return mIsStartingFunction; } + const LLSD& isStartingParameters() const { return mIsStartingParameters; } + + bool isFlashingAllowed() const { return mIsFlashingAllowed; } private: - LLCommandId mIdentifier; + LLCommandId mIdentifier; - bool mAvailableInToybox; - std::string mIcon; - std::string mLabelRef; - std::string mName; - std::string mTooltipRef; + bool mAvailableInToybox; + std::string mIcon; + std::string mLabelRef; + std::string mName; + std::string mTooltipRef; - std::string mExecuteFunction; - LLSD mExecuteParameters; + std::string mExecuteFunction; + LLSD mExecuteParameters; - std::string mExecuteStopFunction; - LLSD mExecuteStopParameters; - - std::string mIsEnabledFunction; - LLSD mIsEnabledParameters; + std::string mExecuteStopFunction; + LLSD mExecuteStopParameters; - std::string mIsRunningFunction; - LLSD mIsRunningParameters; + std::string mIsEnabledFunction; + LLSD mIsEnabledParameters; - std::string mIsStartingFunction; - LLSD mIsStartingParameters; + std::string mIsRunningFunction; + LLSD mIsRunningParameters; - bool mIsFlashingAllowed; + std::string mIsStartingFunction; + LLSD mIsStartingParameters; + + bool mIsFlashingAllowed; }; class LLCommandManager -: public LLSingleton<LLCommandManager> +: public LLSingleton<LLCommandManager> { - LLSINGLETON(LLCommandManager); - ~LLCommandManager(); + LLSINGLETON(LLCommandManager); + ~LLCommandManager(); public: - struct Params : public LLInitParam::Block<Params> - { - Multiple< LLCommand::Params, AtLeast<1> > commands; + struct Params : public LLInitParam::Block<Params> + { + Multiple< LLCommand::Params, AtLeast<1> > commands; - Params() - : commands("command") - { - } - }; + Params() + : commands("command") + { + } + }; - U32 commandCount() const; - LLCommand * getCommand(U32 commandIndex); - LLCommand * getCommand(const LLCommandId& commandId); - LLCommand * getCommand(const std::string& name); + U32 commandCount() const; + LLCommand * getCommand(U32 commandIndex); + LLCommand * getCommand(const LLCommandId& commandId); + LLCommand * getCommand(const std::string& name); - static bool load(); + static bool load(); protected: - void addCommand(LLCommand * command); + void addCommand(LLCommand * command); private: - typedef std::map<LLUUID, U32> CommandIndexMap; - typedef std::vector<LLCommand *> CommandVector; - - CommandVector mCommands; - CommandIndexMap mCommandIndices; + typedef std::map<LLUUID, U32> CommandIndexMap; + typedef std::vector<LLCommand *> CommandVector; + + CommandVector mCommands; + CommandIndexMap mCommandIndices; }; diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index 8fc2978bdd..795bf1070a 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llconsole.cpp * @brief a scrolling console output device * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -52,352 +52,352 @@ extern void AddNewDebugConsoleToLCD(const LLWString &newLine); LLConsole* gConsole = NULL; // Created and destroyed in LLViewerWindow. const F32 FADE_DURATION = 2.f; - + static LLDefaultChildRegistry::Register<LLConsole> r("console"); -LLConsole::LLConsole(const LLConsole::Params& p) -: LLUICtrl(p), - LLFixedBuffer(p.max_lines), - mLinePersistTime(p.persist_time), // seconds - mFont(p.font), - mConsoleWidth(0), - mConsoleHeight(0) +LLConsole::LLConsole(const LLConsole::Params& p) +: LLUICtrl(p), + LLFixedBuffer(p.max_lines), + mLinePersistTime(p.persist_time), // seconds + mFont(p.font), + mConsoleWidth(0), + mConsoleHeight(0) { - if (p.font_size_index.isProvided()) - { - setFontSize(p.font_size_index); - } - mFadeTime = mLinePersistTime - FADE_DURATION; - setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")); + if (p.font_size_index.isProvided()) + { + setFontSize(p.font_size_index); + } + mFadeTime = mLinePersistTime - FADE_DURATION; + setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")); } void LLConsole::setLinePersistTime(F32 seconds) { - mLinePersistTime = seconds; - mFadeTime = mLinePersistTime - FADE_DURATION; + mLinePersistTime = seconds; + mFadeTime = mLinePersistTime - FADE_DURATION; } void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent) { - S32 new_width = llmax(50, llmin(getRect().getWidth(), width)); - S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height)); - - if ( mConsoleWidth == new_width - && mConsoleHeight == new_height ) - { - return; - } - - mConsoleWidth = new_width; - mConsoleHeight= new_height; - - LLUICtrl::reshape(new_width, new_height, called_from_parent); - - for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) - { - (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); - } + S32 new_width = llmax(50, llmin(getRect().getWidth(), width)); + S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height)); + + if ( mConsoleWidth == new_width + && mConsoleHeight == new_height ) + { + return; + } + + mConsoleWidth = new_width; + mConsoleHeight= new_height; + + LLUICtrl::reshape(new_width, new_height, called_from_parent); + + for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) + { + (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); + } } void LLConsole::setFontSize(S32 size_index) { - if (-1 == size_index) - { - mFont = LLFontGL::getFontMonospace(); - } - else if (0 == size_index) - { - mFont = LLFontGL::getFontSansSerif(); - } - else if (1 == size_index) - { - mFont = LLFontGL::getFontSansSerifBig(); - } - else - { - mFont = LLFontGL::getFontSansSerifHuge(); - } - // Make sure the font exists - if (mFont == NULL) - { - mFont = LLFontGL::getFontDefault(); - } - - for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) - { - (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); - } + if (-1 == size_index) + { + mFont = LLFontGL::getFontMonospace(); + } + else if (0 == size_index) + { + mFont = LLFontGL::getFontSansSerif(); + } + else if (1 == size_index) + { + mFont = LLFontGL::getFontSansSerifBig(); + } + else + { + mFont = LLFontGL::getFontSansSerifHuge(); + } + // Make sure the font exists + if (mFont == NULL) + { + mFont = LLFontGL::getFontDefault(); + } + + for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) + { + (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); + } } void LLConsole::draw() { - // Units in pixels - static const F32 padding_horizontal = 10; - static const F32 padding_vertical = 3; - LLGLSUIDefault gls_ui; - - // skip lines added more than mLinePersistTime ago - F32 cur_time = mTimer.getElapsedTimeF32(); - - F32 skip_time = cur_time - mLinePersistTime; - F32 fade_time = cur_time - mFadeTime; - - if (mParagraphs.empty()) //No text to draw. - { - return; - } - - U32 num_lines=0; - - paragraph_t::reverse_iterator paragraph_it; - paragraph_it = mParagraphs.rbegin(); - U32 paragraph_num=mParagraphs.size(); - - while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend()) - { - num_lines += (*paragraph_it).mLines.size(); - if(num_lines > mMaxLines - || ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f)) - { //All lines above here are done. Lose them. - for (U32 i=0;i<paragraph_num;i++) - { - if (!mParagraphs.empty()) - mParagraphs.pop_front(); - } - break; - } - paragraph_num--; - paragraph_it++; - } - - if (mParagraphs.empty()) - { - return; - } - - // draw remaining lines - F32 y_pos = 0.f; - - LLUIImagePtr imagep = LLUI::getUIImage("transparent"); - - static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f); - F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f); - - LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); - color.mV[VALPHA] *= console_opacity; - - F32 line_height = mFont->getLineHeight(); - - for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++) - { - S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical); - S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal); - - y_pos += ((*paragraph_it).mLines.size()) * line_height; - imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color); - - F32 y_off=0; - - F32 alpha; - - if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time)) - { - alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime); - } - else - { - alpha = 1.0f; - } - - if( alpha > 0.f ) - { - for (lines_t::iterator line_it=(*paragraph_it).mLines.begin(); - line_it != (*paragraph_it).mLines.end(); - line_it ++) - { - for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin(); - seg_it != (*line_it).mLineColorSegments.end(); - seg_it++) - { - mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off, - LLColor4( - (*seg_it).mColor.mV[VRED], - (*seg_it).mColor.mV[VGREEN], - (*seg_it).mColor.mV[VBLUE], - (*seg_it).mColor.mV[VALPHA]*alpha), - LLFontGL::LEFT, - LLFontGL::BASELINE, - LLFontGL::NORMAL, - LLFontGL::DROP_SHADOW, - S32_MAX, - target_width - ); - } - y_off += line_height; - } - } - y_pos += padding_vertical; - } + // Units in pixels + static const F32 padding_horizontal = 10; + static const F32 padding_vertical = 3; + LLGLSUIDefault gls_ui; + + // skip lines added more than mLinePersistTime ago + F32 cur_time = mTimer.getElapsedTimeF32(); + + F32 skip_time = cur_time - mLinePersistTime; + F32 fade_time = cur_time - mFadeTime; + + if (mParagraphs.empty()) //No text to draw. + { + return; + } + + U32 num_lines=0; + + paragraph_t::reverse_iterator paragraph_it; + paragraph_it = mParagraphs.rbegin(); + U32 paragraph_num=mParagraphs.size(); + + while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend()) + { + num_lines += (*paragraph_it).mLines.size(); + if(num_lines > mMaxLines + || ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f)) + { //All lines above here are done. Lose them. + for (U32 i=0;i<paragraph_num;i++) + { + if (!mParagraphs.empty()) + mParagraphs.pop_front(); + } + break; + } + paragraph_num--; + paragraph_it++; + } + + if (mParagraphs.empty()) + { + return; + } + + // draw remaining lines + F32 y_pos = 0.f; + + LLUIImagePtr imagep = LLUI::getUIImage("transparent"); + + static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f); + F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f); + + LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); + color.mV[VALPHA] *= console_opacity; + + F32 line_height = mFont->getLineHeight(); + + for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++) + { + S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical); + S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal); + + y_pos += ((*paragraph_it).mLines.size()) * line_height; + imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color); + + F32 y_off=0; + + F32 alpha; + + if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time)) + { + alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime); + } + else + { + alpha = 1.0f; + } + + if( alpha > 0.f ) + { + for (lines_t::iterator line_it=(*paragraph_it).mLines.begin(); + line_it != (*paragraph_it).mLines.end(); + line_it ++) + { + for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin(); + seg_it != (*line_it).mLineColorSegments.end(); + seg_it++) + { + mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off, + LLColor4( + (*seg_it).mColor.mV[VRED], + (*seg_it).mColor.mV[VGREEN], + (*seg_it).mColor.mV[VBLUE], + (*seg_it).mColor.mV[VALPHA]*alpha), + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::NORMAL, + LLFontGL::DROP_SHADOW, + S32_MAX, + target_width + ); + } + y_off += line_height; + } + } + y_pos += padding_vertical; + } } //Generate highlight color segments for this paragraph. Pass in default color of paragraph. -void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) +void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) { - LLSD paragraph_color_segments; - paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText); - LLSD color_sd = color.getValue(); - paragraph_color_segments[0]["color"]=color_sd; - - for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray(); - color_segment_it != paragraph_color_segments.endArray(); - ++color_segment_it) - { - LLSD color_llsd = (*color_segment_it)["color"]; - std::string color_str = (*color_segment_it)["text"].asString(); - - ParagraphColorSegment color_segment; - - color_segment.mColor.setValue(color_llsd); - color_segment.mNumChars = color_str.length(); - - mParagraphColorSegments.push_back(color_segment); - } + LLSD paragraph_color_segments; + paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText); + LLSD color_sd = color.getValue(); + paragraph_color_segments[0]["color"]=color_sd; + + for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray(); + color_segment_it != paragraph_color_segments.endArray(); + ++color_segment_it) + { + LLSD color_llsd = (*color_segment_it)["color"]; + std::string color_str = (*color_segment_it)["text"].asString(); + + ParagraphColorSegment color_segment; + + color_segment.mColor.setValue(color_llsd); + color_segment.mNumChars = color_str.length(); + + mParagraphColorSegments.push_back(color_segment); + } } //Called when a paragraph is added to the console or window is resized. void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize) { - if ( !force_resize ) - { - if ( mMaxWidth >= 0.0f - && mMaxWidth < screen_width ) - { - return; //No resize required. - } - } - - screen_width = screen_width - 30; //Margin for small windows. - - if ( mParagraphText.empty() - || mParagraphColorSegments.empty() - || font == NULL) - { - return; //Not enough info to complete. - } - - mLines.clear(); //Chuck everything. - mMaxWidth = 0.0f; - - paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin(); - U32 current_color_length = (*current_color).mNumChars; - - S32 paragraph_offset = 0; //Offset into the paragraph text. - - // Wrap lines that are longer than the view is wide. - while( paragraph_offset < (S32)mParagraphText.length() && - mParagraphText[paragraph_offset] != 0) - { - S32 skip_chars; // skip '\n' - // Figure out if a word-wrapped line fits here. - LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset); - if (line_end != LLWString::npos) - { - skip_chars = 1; // skip '\n' - } - else - { - line_end = mParagraphText.size(); - skip_chars = 0; - } - - U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); - - if (drawable != 0) - { - F32 x_position = 0; //Screen X position of text. - - mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) ); - Line line; - - U32 left_to_draw = drawable; - U32 drawn = 0; - - while (left_to_draw >= current_color_length - && current_color != mParagraphColorSegments.end() ) - { - LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length ); - line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. - (*current_color).mColor, - x_position ) ); - - x_position += font->getWidth( color_text.c_str() ); //Set up next screen position. - - drawn += current_color_length; - left_to_draw -= current_color_length; - - current_color++; //Goto next paragraph color record. - - if (current_color != mParagraphColorSegments.end()) - { - current_color_length = (*current_color).mNumChars; - } - } - - if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() ) - { - LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw ); - - line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. - (*current_color).mColor, - x_position ) ); - - current_color_length -= left_to_draw; - } - mLines.push_back(line); //Append line to paragraph line list. - } - paragraph_offset += (drawable + skip_chars); - } + if ( !force_resize ) + { + if ( mMaxWidth >= 0.0f + && mMaxWidth < screen_width ) + { + return; //No resize required. + } + } + + screen_width = screen_width - 30; //Margin for small windows. + + if ( mParagraphText.empty() + || mParagraphColorSegments.empty() + || font == NULL) + { + return; //Not enough info to complete. + } + + mLines.clear(); //Chuck everything. + mMaxWidth = 0.0f; + + paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin(); + U32 current_color_length = (*current_color).mNumChars; + + S32 paragraph_offset = 0; //Offset into the paragraph text. + + // Wrap lines that are longer than the view is wide. + while( paragraph_offset < (S32)mParagraphText.length() && + mParagraphText[paragraph_offset] != 0) + { + S32 skip_chars; // skip '\n' + // Figure out if a word-wrapped line fits here. + LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset); + if (line_end != LLWString::npos) + { + skip_chars = 1; // skip '\n' + } + else + { + line_end = mParagraphText.size(); + skip_chars = 0; + } + + U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); + + if (drawable != 0) + { + F32 x_position = 0; //Screen X position of text. + + mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) ); + Line line; + + U32 left_to_draw = drawable; + U32 drawn = 0; + + while (left_to_draw >= current_color_length + && current_color != mParagraphColorSegments.end() ) + { + LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length ); + line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. + (*current_color).mColor, + x_position ) ); + + x_position += font->getWidth( color_text.c_str() ); //Set up next screen position. + + drawn += current_color_length; + left_to_draw -= current_color_length; + + current_color++; //Goto next paragraph color record. + + if (current_color != mParagraphColorSegments.end()) + { + current_color_length = (*current_color).mNumChars; + } + } + + if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() ) + { + LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw ); + + line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. + (*current_color).mColor, + x_position ) ); + + current_color_length -= left_to_draw; + } + mLines.push_back(line); //Append line to paragraph line list. + } + paragraph_offset += (drawable + skip_chars); + } } //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) +LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width) +: mParagraphText(str), mAddTime(add_time), mMaxWidth(-1) { - makeParagraphColorSegments(color); - updateLines( screen_width, font ); + makeParagraphColorSegments(color); + updateLines( screen_width, font ); } - + // called once per frame regardless of console visibility // static void LLConsole::updateClass() -{ - for (auto& con : instance_snapshot()) - { - con.update(); - } +{ + for (auto& con : instance_snapshot()) + { + con.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(); - } + { + 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(); + } } diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h index 04f5e71609..d3dc1bbfde 100644 --- a/indra/llui/llconsole.h +++ b/indra/llui/llconsole.h @@ -1,25 +1,25 @@ -/** +/** * @file llconsole.h * @brief a simple console-style output device * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,116 +38,116 @@ class LLConsole : public LLFixedBuffer, public LLUICtrl, public LLInstanceTracke { public: - typedef enum e_font_size - { - MONOSPACE = -1, - SMALL = 0, - BIG = 1 - } EFontSize; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<U32> max_lines; - Optional<F32> persist_time; - Optional<S32> font_size_index; - Params() - : max_lines("max_lines", LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")), - persist_time("persist_time", 0.f), // forever - font_size_index("font_size_index") - { - changeDefault(mouse_opaque, false); - } - }; + typedef enum e_font_size + { + MONOSPACE = -1, + SMALL = 0, + BIG = 1 + } EFontSize; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<U32> max_lines; + Optional<F32> persist_time; + Optional<S32> font_size_index; + Params() + : max_lines("max_lines", LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")), + persist_time("persist_time", 0.f), // forever + font_size_index("font_size_index") + { + changeDefault(mouse_opaque, false); + } + }; protected: - LLConsole(const Params&); - friend class LLUICtrlFactory; + LLConsole(const Params&); + 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. - //It is only the number of characters that are a color and the - //color. - struct ParagraphColorSegment - { - S32 mNumChars; - LLColor4 mColor; - }; - - //A line color segment is a chunk of text, the color associated - //with it, and the X Position it was calculated to begin at - //on the screen. X Positions are re-calculated if the - //screen changes size. - class LineColorSegment - { - public: - LineColorSegment(LLWString text, LLColor4 color, F32 xpos) : mText(text), mColor(color), mXPosition(xpos) {} - public: - LLWString mText; - LLColor4 mColor; - F32 mXPosition; - }; - - typedef std::list<LineColorSegment> line_color_segments_t; - - //A line is composed of one or more color segments. - class Line - { - public: - line_color_segments_t mLineColorSegments; - }; - - typedef std::list<Line> lines_t; - typedef std::list<ParagraphColorSegment> paragraph_color_segments_t; - - //A paragraph is a processed element containing the entire text of the - //message (used for recalculating positions on screen resize) - //The time this message was added to the console output - //The visual screen width of the longest line in this block - //And a list of one or more lines which are used to display this message. - class Paragraph - { - public: - Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width); - void makeParagraphColorSegments ( const LLColor4 &color); - void updateLines ( F32 screen_width, const LLFontGL* font, bool force_resize=false ); - public: - LLWString mParagraphText; //The entire text of the paragraph - paragraph_color_segments_t mParagraphColorSegments; - F32 mAddTime; //Time this paragraph was added to the display. - F32 mMaxWidth; //Width of the widest line of text in this paragraph. - lines_t mLines; - - }; - - //The console contains a deque of paragraphs which represent the individual messages. - typedef std::deque<Paragraph> paragraph_t; - paragraph_t mParagraphs; - - ~LLConsole(){}; - - // each line lasts this long after being added - void setLinePersistTime(F32 seconds); - - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - // -1 = monospace, 0 means small, font size = 1 means big - void setFontSize(S32 size_index); - - - // Overrides - /*virtual*/ void draw(); + // 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. + //It is only the number of characters that are a color and the + //color. + struct ParagraphColorSegment + { + S32 mNumChars; + LLColor4 mColor; + }; + + //A line color segment is a chunk of text, the color associated + //with it, and the X Position it was calculated to begin at + //on the screen. X Positions are re-calculated if the + //screen changes size. + class LineColorSegment + { + public: + LineColorSegment(LLWString text, LLColor4 color, F32 xpos) : mText(text), mColor(color), mXPosition(xpos) {} + public: + LLWString mText; + LLColor4 mColor; + F32 mXPosition; + }; + + typedef std::list<LineColorSegment> line_color_segments_t; + + //A line is composed of one or more color segments. + class Line + { + public: + line_color_segments_t mLineColorSegments; + }; + + typedef std::list<Line> lines_t; + typedef std::list<ParagraphColorSegment> paragraph_color_segments_t; + + //A paragraph is a processed element containing the entire text of the + //message (used for recalculating positions on screen resize) + //The time this message was added to the console output + //The visual screen width of the longest line in this block + //And a list of one or more lines which are used to display this message. + class Paragraph + { + public: + Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width); + void makeParagraphColorSegments ( const LLColor4 &color); + void updateLines ( F32 screen_width, const LLFontGL* font, bool force_resize=false ); + public: + LLWString mParagraphText; //The entire text of the paragraph + paragraph_color_segments_t mParagraphColorSegments; + F32 mAddTime; //Time this paragraph was added to the display. + F32 mMaxWidth; //Width of the widest line of text in this paragraph. + lines_t mLines; + + }; + + //The console contains a deque of paragraphs which represent the individual messages. + typedef std::deque<Paragraph> paragraph_t; + paragraph_t mParagraphs; + + ~LLConsole(){}; + + // each line lasts this long after being added + void setLinePersistTime(F32 seconds); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + // -1 = monospace, 0 means small, font size = 1 means big + void setFontSize(S32 size_index); + + + // Overrides + /*virtual*/ void draw(); private: - void update(); + void update(); - F32 mLinePersistTime; // Age at which to stop drawing. - F32 mFadeTime; // Age at which to start fading - const LLFontGL* mFont; - S32 mConsoleWidth; - S32 mConsoleHeight; + F32 mLinePersistTime; // Age at which to stop drawing. + F32 mFadeTime; // Age at which to start fading + const LLFontGL* mFont; + S32 mConsoleWidth; + S32 mConsoleHeight; }; diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index 1c33088e8d..f01d66382c 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcontainerview.cpp * @brief Container for all statistics info * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,257 +44,257 @@ static ContainerViewRegistry::Register<LLStatView> r2("stat_view"); static ContainerViewRegistry::Register<LLPanel> r3("panel", &LLPanel::fromXML); LLContainerView::LLContainerView(const LLContainerView::Params& p) -: LLView(p), - mShowLabel(p.show_label), - mLabel(p.label), - mDisplayChildren(p.display_children) +: LLView(p), + mShowLabel(p.show_label), + mLabel(p.label), + mDisplayChildren(p.display_children) { - mScrollContainer = NULL; + mScrollContainer = NULL; } LLContainerView::~LLContainerView() { - // Children all cleaned up by default view destructor. + // Children all cleaned up by default view destructor. } BOOL LLContainerView::postBuild() { - setDisplayChildren(mDisplayChildren); - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); - return TRUE; + setDisplayChildren(mDisplayChildren); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + return TRUE; } bool LLContainerView::addChild(LLView* child, S32 tab_group) { - bool res = LLView::addChild(child, tab_group); - if (res) - { - sendChildToBack(child); - } - return res; + bool res = LLView::addChild(child, tab_group); + if (res) + { + sendChildToBack(child); + } + return res; } BOOL LLContainerView::handleDoubleClick(S32 x, S32 y, MASK mask) { - return handleMouseDown(x, y, mask); + return handleMouseDown(x, y, mask); } BOOL LLContainerView::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - if (mDisplayChildren) - { - handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL); - } - if (!handled) - { - if( mShowLabel && (y >= getRect().getHeight() - 10) ) - { - setDisplayChildren(!mDisplayChildren); - reshape(getRect().getWidth(), getRect().getHeight(), FALSE); - handled = TRUE; - } - } - return handled; + BOOL handled = FALSE; + if (mDisplayChildren) + { + handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL); + } + if (!handled) + { + if( mShowLabel && (y >= getRect().getHeight() - 10) ) + { + setDisplayChildren(!mDisplayChildren); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + handled = TRUE; + } + } + return handled; } BOOL LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - if (mDisplayChildren) - { - handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL); - } - return handled; + BOOL handled = FALSE; + if (mDisplayChildren) + { + handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL); + } + return handled; } void LLContainerView::draw() { - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); - } - - // Draw the label - if (mShowLabel) - { - LLFontGL::getFontMonospace()->renderUTF8( - mLabel, 0, 2, getRect().getHeight() - 2, LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP); - } - - LLView::draw(); + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); + } + + // Draw the label + if (mShowLabel) + { + LLFontGL::getFontMonospace()->renderUTF8( + mLabel, 0, 2, getRect().getHeight() - 2, LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP); + } + + LLView::draw(); } void LLContainerView::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLRect scroller_rect; - scroller_rect.setOriginAndSize(0, 0, width, height); - - if (mScrollContainer) - { - scroller_rect = mScrollContainer->getContentWindowRect(); - } - else - { - // if we're uncontained - make height as small as possible - scroller_rect.mTop = 0; - } - - arrange(scroller_rect.getWidth(), scroller_rect.getHeight(), called_from_parent); - - // sometimes, after layout, our container will change size (scrollbars popping in and out) - // if so, attempt another layout - if (mScrollContainer) - { - LLRect new_container_rect = mScrollContainer->getContentWindowRect(); - - if ((new_container_rect.getWidth() != scroller_rect.getWidth()) || - (new_container_rect.getHeight() != scroller_rect.getHeight())) // the container size has changed, attempt to arrange again - { - arrange(new_container_rect.getWidth(), new_container_rect.getHeight(), called_from_parent); - } - } + LLRect scroller_rect; + scroller_rect.setOriginAndSize(0, 0, width, height); + + if (mScrollContainer) + { + scroller_rect = mScrollContainer->getContentWindowRect(); + } + else + { + // if we're uncontained - make height as small as possible + scroller_rect.mTop = 0; + } + + arrange(scroller_rect.getWidth(), scroller_rect.getHeight(), called_from_parent); + + // sometimes, after layout, our container will change size (scrollbars popping in and out) + // if so, attempt another layout + if (mScrollContainer) + { + LLRect new_container_rect = mScrollContainer->getContentWindowRect(); + + if ((new_container_rect.getWidth() != scroller_rect.getWidth()) || + (new_container_rect.getHeight() != scroller_rect.getHeight())) // the container size has changed, attempt to arrange again + { + arrange(new_container_rect.getWidth(), new_container_rect.getHeight(), called_from_parent); + } + } } void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent) { - // Determine the sizes and locations of all contained views - S32 total_height = 0; - S32 top, left, right, bottom; - //LLView *childp; - - // These will be used for the children - left = 10; - top = getRect().getHeight() - 4; - right = width - 2; - bottom = top; - - // Leave some space for the top label/grab handle - if (mShowLabel) - { - total_height += 20; - } - - if (mDisplayChildren) - { - // Determine total height - U32 child_height = 0; - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *childp = *child_iter; - if (!childp->getVisible()) - { - LL_WARNS() << "Incorrect visibility!" << LL_ENDL; - } - LLRect child_rect = childp->getRequiredRect(); - child_height += child_rect.getHeight(); - child_height += 2; - } - total_height += child_height; - } - - if (total_height < height) - total_height = height; - - LLRect my_rect = getRect(); - if (followsTop()) - { - my_rect.mBottom = my_rect.mTop - total_height; - } - else - { - my_rect.mTop = my_rect.mBottom + total_height; - } - - my_rect.mRight = my_rect.mLeft + width; - setRect(my_rect); - - top = total_height; - if (mShowLabel) - { - top -= 20; - } - - bottom = top; - - if (mDisplayChildren) - { - // Iterate through all children, and put in container from top down. - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *childp = *child_iter; - LLRect child_rect = childp->getRequiredRect(); - bottom -= child_rect.getHeight(); - LLRect r(left, bottom + child_rect.getHeight(), right, bottom); - childp->setRect(r); - childp->reshape(right - left, top - bottom); - top = bottom - 2; - bottom = top; - } - } - - if (!called_from_parent) - { - if (getParent()) - { - getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), FALSE); - } - } + // Determine the sizes and locations of all contained views + S32 total_height = 0; + S32 top, left, right, bottom; + //LLView *childp; + + // These will be used for the children + left = 10; + top = getRect().getHeight() - 4; + right = width - 2; + bottom = top; + + // Leave some space for the top label/grab handle + if (mShowLabel) + { + total_height += 20; + } + + if (mDisplayChildren) + { + // Determine total height + U32 child_height = 0; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + if (!childp->getVisible()) + { + LL_WARNS() << "Incorrect visibility!" << LL_ENDL; + } + LLRect child_rect = childp->getRequiredRect(); + child_height += child_rect.getHeight(); + child_height += 2; + } + total_height += child_height; + } + + if (total_height < height) + total_height = height; + + LLRect my_rect = getRect(); + if (followsTop()) + { + my_rect.mBottom = my_rect.mTop - total_height; + } + else + { + my_rect.mTop = my_rect.mBottom + total_height; + } + + my_rect.mRight = my_rect.mLeft + width; + setRect(my_rect); + + top = total_height; + if (mShowLabel) + { + top -= 20; + } + + bottom = top; + + if (mDisplayChildren) + { + // Iterate through all children, and put in container from top down. + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + LLRect child_rect = childp->getRequiredRect(); + bottom -= child_rect.getHeight(); + LLRect r(left, bottom + child_rect.getHeight(), right, bottom); + childp->setRect(r); + childp->reshape(right - left, top - bottom); + top = bottom - 2; + bottom = top; + } + } + + if (!called_from_parent) + { + if (getParent()) + { + getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), FALSE); + } + } } LLRect LLContainerView::getRequiredRect() { - LLRect req_rect; - //LLView *childp; - U32 total_height = 0; - - // Determine the sizes and locations of all contained views - - // Leave some space for the top label/grab handle - - if (mShowLabel) - { - total_height = 20; - } - - - if (mDisplayChildren) - { - // Determine total height - U32 child_height = 0; - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *childp = *child_iter; - LLRect child_rect = childp->getRequiredRect(); - child_height += child_rect.getHeight(); - child_height += 2; - } - - total_height += child_height; - } - req_rect.mTop = total_height; - return req_rect; + LLRect req_rect; + //LLView *childp; + U32 total_height = 0; + + // Determine the sizes and locations of all contained views + + // Leave some space for the top label/grab handle + + if (mShowLabel) + { + total_height = 20; + } + + + if (mDisplayChildren) + { + // Determine total height + U32 child_height = 0; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + LLRect child_rect = childp->getRequiredRect(); + child_height += child_rect.getHeight(); + child_height += 2; + } + + total_height += child_height; + } + req_rect.mTop = total_height; + return req_rect; } void LLContainerView::setLabel(const std::string& label) { - mLabel = label; + mLabel = label; } void LLContainerView::setDisplayChildren(BOOL displayChildren) { - mDisplayChildren = displayChildren; - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *childp = *child_iter; - childp->setVisible(mDisplayChildren); - } + mDisplayChildren = displayChildren; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + childp->setVisible(mDisplayChildren); + } } diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h index 8e75aaef6e..118d3a967c 100644 --- a/indra/llui/llcontainerview.h +++ b/indra/llui/llcontainerview.h @@ -1,25 +1,25 @@ -/** +/** * @file llcontainerview.h * @brief Container for all statistics info. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,59 +36,59 @@ class LLScrollContainer; struct ContainerViewRegistry : public LLChildRegistry<ContainerViewRegistry> { - LLSINGLETON_EMPTY_CTOR(ContainerViewRegistry); + LLSINGLETON_EMPTY_CTOR(ContainerViewRegistry); }; class LLContainerView : public LLView { public: - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Optional<std::string> label; - Optional<bool> show_label; - Optional<bool> display_children; - Params() - : label("label"), - show_label("show_label", FALSE), - display_children("display_children", TRUE) - { - changeDefault(mouse_opaque, false); - } - }; + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Optional<std::string> label; + Optional<bool> show_label; + Optional<bool> display_children; + Params() + : label("label"), + show_label("show_label", FALSE), + display_children("display_children", TRUE) + { + changeDefault(mouse_opaque, false); + } + }; + + // my valid children are stored in this registry + typedef ContainerViewRegistry child_registry_t; - // my valid children are stored in this registry - typedef ContainerViewRegistry child_registry_t; - protected: - LLContainerView(const Params& p); - friend class LLUICtrlFactory; + LLContainerView(const Params& p); + friend class LLUICtrlFactory; public: - ~LLContainerView(); + ~LLContainerView(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); - /*virtual*/ BOOL postBuild(); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); - - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. - void setLabel(const std::string& label); - void showLabel(BOOL show) { mShowLabel = show; } - void setDisplayChildren(BOOL displayChildren); - BOOL getDisplayChildren() { return mDisplayChildren; } - void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;} + void setLabel(const std::string& label); + void showLabel(BOOL show) { mShowLabel = show; } + void setDisplayChildren(BOOL displayChildren); + BOOL getDisplayChildren() { return mDisplayChildren; } + void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;} private: - LLScrollContainer* mScrollContainer; - void arrange(S32 width, S32 height, BOOL called_from_parent = TRUE); - BOOL mShowLabel; + LLScrollContainer* mScrollContainer; + void arrange(S32 width, S32 height, BOOL called_from_parent = TRUE); + BOOL mShowLabel; protected: - BOOL mDisplayChildren; - std::string mLabel; + BOOL mDisplayChildren; + std::string mLabel; }; #endif // LL_CONTAINERVIEW_ diff --git a/indra/llui/llctrlselectioninterface.cpp b/indra/llui/llctrlselectioninterface.cpp index 7e886aff48..10e5a75bff 100644 --- a/indra/llui/llctrlselectioninterface.cpp +++ b/indra/llui/llctrlselectioninterface.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llctrlselectioninterface.cpp * @brief Programmatic selection of items in a list. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,12 +35,12 @@ LLCtrlSelectionInterface::~LLCtrlSelectionInterface() BOOL LLCtrlSelectionInterface::selectByValue(LLSD value) { - return setSelectedByValue(value, TRUE); + return setSelectedByValue(value, TRUE); } BOOL LLCtrlSelectionInterface::deselectByValue(LLSD value) -{ - return setSelectedByValue(value, FALSE); +{ + return setSelectedByValue(value, FALSE); } @@ -50,12 +50,12 @@ LLCtrlListInterface::~LLCtrlListInterface() LLScrollListItem* LLCtrlListInterface::addSimpleElement(const std::string& value) { - return addSimpleElement(value, ADD_BOTTOM, LLSD()); + return addSimpleElement(value, ADD_BOTTOM, LLSD()); } LLScrollListItem* LLCtrlListInterface::addSimpleElement(const std::string& value, EAddPosition pos) { - return addSimpleElement(value, pos, LLSD()); + return addSimpleElement(value, pos, LLSD()); } // virtual diff --git a/indra/llui/llctrlselectioninterface.h b/indra/llui/llctrlselectioninterface.h index a7b089c8f9..56dd7a7415 100644 --- a/indra/llui/llctrlselectioninterface.h +++ b/indra/llui/llctrlselectioninterface.h @@ -1,25 +1,25 @@ -/** +/** * @file llctrlselectioninterface.h * @brief Programmatic selection of items in a list. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,67 +38,67 @@ class LLScrollListItem; class LLCtrlSelectionInterface { public: - virtual ~LLCtrlSelectionInterface(); - - enum EOperation - { - OP_DELETE = 1, - OP_SELECT, - OP_DESELECT, - }; + virtual ~LLCtrlSelectionInterface(); + + enum EOperation + { + OP_DELETE = 1, + OP_SELECT, + OP_DESELECT, + }; - virtual BOOL getCanSelect() const = 0; + virtual BOOL getCanSelect() const = 0; - virtual S32 getItemCount() const = 0; + virtual S32 getItemCount() const = 0; - virtual BOOL selectFirstItem() = 0; - virtual BOOL selectNthItem( S32 index ) = 0; - virtual BOOL selectItemRange( S32 first, S32 last ) = 0; + virtual BOOL selectFirstItem() = 0; + virtual BOOL selectNthItem( S32 index ) = 0; + virtual BOOL selectItemRange( S32 first, S32 last ) = 0; - virtual S32 getFirstSelectedIndex() const = 0; + virtual S32 getFirstSelectedIndex() const = 0; - // TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function - virtual BOOL setCurrentByID( const LLUUID& id ) = 0; - virtual LLUUID getCurrentID() const = 0; + // TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function + virtual BOOL setCurrentByID( const LLUUID& id ) = 0; + virtual LLUUID getCurrentID() const = 0; - BOOL selectByValue(const LLSD value); - BOOL deselectByValue(const LLSD value); - virtual BOOL setSelectedByValue(const LLSD& value, BOOL selected) = 0; - virtual LLSD getSelectedValue() = 0; + BOOL selectByValue(const LLSD value); + BOOL deselectByValue(const LLSD value); + virtual BOOL setSelectedByValue(const LLSD& value, BOOL selected) = 0; + virtual LLSD getSelectedValue() = 0; - virtual BOOL isSelected(const LLSD& value) const = 0; + virtual BOOL isSelected(const LLSD& value) const = 0; - virtual BOOL operateOnSelection(EOperation op) = 0; - virtual BOOL operateOnAll(EOperation op) = 0; + virtual BOOL operateOnSelection(EOperation op) = 0; + virtual BOOL operateOnAll(EOperation op) = 0; }; class LLCtrlListInterface : public LLCtrlSelectionInterface { public: - virtual ~LLCtrlListInterface(); - - virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; - virtual void clearColumns() = 0; - virtual void setColumnLabel(const std::string& column, const std::string& label) = 0; - // TomY TODO: Document this - virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0; - - LLScrollListItem* addSimpleElement(const std::string& value); // defaults to bottom - LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos); // defaults to no LLSD() id - virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) = 0; - - virtual void clearRows() = 0; - virtual void sortByColumn(const std::string& name, BOOL ascending) = 0; + virtual ~LLCtrlListInterface(); + + virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; + virtual void clearColumns() = 0; + virtual void setColumnLabel(const std::string& column, const std::string& label) = 0; + // TomY TODO: Document this + virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0; + + LLScrollListItem* addSimpleElement(const std::string& value); // defaults to bottom + LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos); // defaults to no LLSD() id + virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) = 0; + + virtual void clearRows() = 0; + virtual void sortByColumn(const std::string& name, BOOL ascending) = 0; }; class LLCtrlScrollInterface { public: - virtual ~LLCtrlScrollInterface(); - - virtual S32 getScrollPos() const = 0; - virtual void setScrollPos( S32 pos ) = 0; - virtual void scrollToShowSelected() = 0; + virtual ~LLCtrlScrollInterface(); + + virtual S32 getScrollPos() const = 0; + virtual void setScrollPos( S32 pos ) = 0; + virtual void scrollToShowSelected() = 0; }; #endif diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index c937d190c6..22e1ac4334 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldockablefloater.cpp * @brief Creates a panel of a specific kind for a toast * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,39 +35,39 @@ LLHandle<LLFloater> LLDockableFloater::sInstanceHandle; //static void LLDockableFloater::init(LLDockableFloater* thiz) { - thiz->setDocked(thiz->mDockControl.get() != NULL - && thiz->mDockControl.get()->isDockVisible()); - thiz->resetInstance(); + thiz->setDocked(thiz->mDockControl.get() != NULL + && thiz->mDockControl.get()->isDockVisible()); + thiz->resetInstance(); - // all dockable floaters should have close, dock and minimize buttons - thiz->setCanClose(TRUE); - thiz->setCanDock(true); - thiz->setCanMinimize(TRUE); - thiz->setOverlapsScreenChannel(false); - thiz->mForceDocking = false; + // all dockable floaters should have close, dock and minimize buttons + thiz->setCanClose(TRUE); + thiz->setCanDock(true); + thiz->setCanMinimize(TRUE); + thiz->setOverlapsScreenChannel(false); + thiz->mForceDocking = false; } LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, - const LLSD& key, const Params& params) : - LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true) + const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true) { - init(this); - mUseTongue = true; + init(this); + mUseTongue = true; } LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, - const LLSD& key, const Params& params) : - LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(uniqueDocking) + const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(uniqueDocking) { - init(this); - mUseTongue = true; + init(this); + mUseTongue = true; } LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, - bool useTongue, const LLSD& key, const Params& params) : - LLFloater(key, params), mDockControl(dockControl), mUseTongue(useTongue), mUniqueDocking(uniqueDocking) + bool useTongue, const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl), mUseTongue(useTongue), mUniqueDocking(uniqueDocking) { - init(this); + init(this); } LLDockableFloater::~LLDockableFloater() @@ -76,188 +76,188 @@ LLDockableFloater::~LLDockableFloater() BOOL LLDockableFloater::postBuild() { - // Remember we should force docking when the floater is opened for the first time - if (mIsDockedStateForcedCallback != NULL && mIsDockedStateForcedCallback()) - { - mForceDocking = true; - } + // Remember we should force docking when the floater is opened for the first time + if (mIsDockedStateForcedCallback != NULL && mIsDockedStateForcedCallback()) + { + mForceDocking = true; + } - mDockTongue = LLUI::getUIImage("Flyout_Pointer"); - LLFloater::setDocked(true); - return LLView::postBuild(); + mDockTongue = LLUI::getUIImage("Flyout_Pointer"); + LLFloater::setDocked(true); + return LLView::postBuild(); } //static void LLDockableFloater::toggleInstance(const LLSD& sdname) { - LLSD key; - std::string name = sdname.asString(); + LLSD key; + std::string name = sdname.asString(); - LLDockableFloater* instance = - dynamic_cast<LLDockableFloater*> (LLFloaterReg::findInstance(name)); - // if floater closed or docked - if (instance == NULL || (instance && instance->isDocked())) - { - LLFloaterReg::toggleInstance(name, key); - // restore button toggle state - if (instance != NULL) - { - instance->storeVisibilityControl(); - } - } - // if floater undocked - else if (instance != NULL) - { - instance->setMinimized(FALSE); - if (instance->getVisible()) - { - instance->setVisible(FALSE); - } - else - { - instance->setVisible(TRUE); - gFloaterView->bringToFront(instance); - } - } + LLDockableFloater* instance = + dynamic_cast<LLDockableFloater*> (LLFloaterReg::findInstance(name)); + // if floater closed or docked + if (instance == NULL || (instance && instance->isDocked())) + { + LLFloaterReg::toggleInstance(name, key); + // restore button toggle state + if (instance != NULL) + { + instance->storeVisibilityControl(); + } + } + // if floater undocked + else if (instance != NULL) + { + instance->setMinimized(FALSE); + if (instance->getVisible()) + { + instance->setVisible(FALSE); + } + else + { + instance->setVisible(TRUE); + gFloaterView->bringToFront(instance); + } + } } void LLDockableFloater::resetInstance() { - if (mUniqueDocking && sInstanceHandle.get() != this) - { - if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked()) - { - sInstanceHandle.get()->setVisible(FALSE); - } - sInstanceHandle = getHandle(); - } + if (mUniqueDocking && sInstanceHandle.get() != this) + { + if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked()) + { + sInstanceHandle.get()->setVisible(FALSE); + } + sInstanceHandle = getHandle(); + } } void LLDockableFloater::setVisible(BOOL visible) { - // Force docking if requested - if (visible && mForceDocking) - { - setCanDock(true); - setDocked(true); - mForceDocking = false; - } + // Force docking if requested + if (visible && mForceDocking) + { + setCanDock(true); + setDocked(true); + mForceDocking = false; + } - if(visible && isDocked()) - { - resetInstance(); - } + if(visible && isDocked()) + { + resetInstance(); + } - if (visible && mDockControl.get() != NULL) - { - mDockControl.get()->repositionDockable(); - } + if (visible && mDockControl.get() != NULL) + { + mDockControl.get()->repositionDockable(); + } - if (visible && !isMinimized()) - { - LLFloater::setFrontmost(getAutoFocus()); - } - LLFloater::setVisible(visible); + if (visible && !isMinimized()) + { + LLFloater::setFrontmost(getAutoFocus()); + } + LLFloater::setVisible(visible); } void LLDockableFloater::setMinimized(BOOL minimize) { - if(minimize && isDocked()) - { - // minimizing a docked floater just hides it - setVisible(FALSE); - } - else - { - LLFloater::setMinimized(minimize); - } + if(minimize && isDocked()) + { + // minimizing a docked floater just hides it + setVisible(FALSE); + } + else + { + LLFloater::setMinimized(minimize); + } } LLView * LLDockableFloater::getDockWidget() { - LLView * res = NULL; - if (getDockControl() != NULL) { - res = getDockControl()->getDock(); - } + LLView * res = NULL; + if (getDockControl() != NULL) { + res = getDockControl()->getDock(); + } - return res; + return res; } void LLDockableFloater::onDockHidden() { - setCanDock(FALSE); + setCanDock(FALSE); } void LLDockableFloater::onDockShown() { - if (!isMinimized()) - { - setCanDock(TRUE); - } + if (!isMinimized()) + { + setCanDock(TRUE); + } } void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) { - if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible()) - { - if (docked) - { - resetInstance(); - mDockControl.get()->on(); - } - else - { - mDockControl.get()->off(); - } + if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible()) + { + if (docked) + { + resetInstance(); + mDockControl.get()->on(); + } + else + { + mDockControl.get()->off(); + } - if (!docked && pop_on_undock) - { - // visually pop up a little bit to emphasize the undocking - translate(0, UNDOCK_LEAP_HEIGHT); - } - } + if (!docked && pop_on_undock) + { + // visually pop up a little bit to emphasize the undocking + translate(0, UNDOCK_LEAP_HEIGHT); + } + } - LLFloater::setDocked(docked, pop_on_undock); + LLFloater::setDocked(docked, pop_on_undock); } void LLDockableFloater::draw() { - if (mDockControl.get() != NULL) - { - mDockControl.get()->repositionDockable(); - if (isDocked()) - { - mDockControl.get()->drawToungue(); - } - } - LLFloater::draw(); + if (mDockControl.get() != NULL) + { + mDockControl.get()->repositionDockable(); + if (isDocked()) + { + mDockControl.get()->drawToungue(); + } + } + LLFloater::draw(); } void LLDockableFloater::setDockControl(LLDockControl* dockControl) { - mDockControl.reset(dockControl); - setDocked(isDocked()); + mDockControl.reset(dockControl); + setDocked(isDocked()); } const LLUIImagePtr& LLDockableFloater::getDockTongue(LLDockControl::DocAt dock_side) { - switch(dock_side) - { - case LLDockControl::LEFT: - mDockTongue = LLUI::getUIImage("Flyout_Left"); - break; - case LLDockControl::RIGHT: - mDockTongue = LLUI::getUIImage("Flyout_Right"); - break; - default: - mDockTongue = LLUI::getUIImage("Flyout_Pointer"); - break; - } + switch(dock_side) + { + case LLDockControl::LEFT: + mDockTongue = LLUI::getUIImage("Flyout_Left"); + break; + case LLDockControl::RIGHT: + mDockTongue = LLUI::getUIImage("Flyout_Right"); + break; + default: + mDockTongue = LLUI::getUIImage("Flyout_Pointer"); + break; + } - return mDockTongue; + return mDockTongue; } LLDockControl* LLDockableFloater::getDockControl() { - return mDockControl.get(); + return mDockControl.get(); } diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 5d90b3ef4e..e7ceb235a7 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -1,25 +1,25 @@ -/** +/** * @file lldockablefloater.h * @brief Creates a panel of a specific kind for a toast. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,115 +38,115 @@ */ class LLDockableFloater : public LLFloater { - static const U32 UNDOCK_LEAP_HEIGHT = 12; + static const U32 UNDOCK_LEAP_HEIGHT = 12; - static void init(LLDockableFloater* thiz); + static void init(LLDockableFloater* thiz); public: - LOG_CLASS(LLDockableFloater); - LLDockableFloater(LLDockControl* dockControl, const LLSD& key, - const Params& params = getDefaultParams()); - - /** - * Constructor. - * @param dockControl a pointer to the doc control instance - * @param uniqueDocking - a flag defines is docking should work as tab(at one - * moment only one docked floater can be shown), also this flag defines is dock - * tongue should be used. - * @params key a floater key. - * @params params a floater parameters - */ - LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, - const LLSD& key, const Params& params = getDefaultParams()); - - /** - * Constructor. - * @param dockControl a pointer to the doc control instance - * @param uniqueDocking - a flag defines is docking should work as tab(at one - * moment only one docked floater can be shown). - * @praram useTongue - a flag defines is dock tongue should be used. - * @params key a floater key. - * @params params a floater parameters - */ - LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, - bool useTongue, const LLSD& key, - const Params& params = getDefaultParams()); - - virtual ~LLDockableFloater(); - - static LLHandle<LLFloater> getInstanceHandle() { return sInstanceHandle; } - - static void toggleInstance(const LLSD& sdname); - - /** - * If descendant class overrides postBuild() in order to perform specific - * construction then it must still invoke its superclass' implementation. - */ - /* virtula */BOOL postBuild(); - /* virtual */void setDocked(bool docked, bool pop_on_undock = true); - /* virtual */void draw(); - - /** - * If descendant class overrides setVisible() then it must still invoke its - * superclass' implementation. - */ - /*virtual*/ void setVisible(BOOL visible); - - /** - * If descendant class overrides setMinimized() then it must still invoke its - * superclass' implementation. - */ - /*virtual*/ void setMinimized(BOOL minimize); - - LLView * getDockWidget(); - - virtual void onDockHidden(); - virtual void onDockShown(); - - LLDockControl* getDockControl(); - - /** - * Returns true if screen channel should consider floater's size when drawing toasts. - * - * By default returns false. - */ - virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); } - virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; } - - bool getUniqueDocking() { return mUniqueDocking; } - bool getUseTongue() { return mUseTongue; } - - void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;} + LOG_CLASS(LLDockableFloater); + LLDockableFloater(LLDockControl* dockControl, const LLSD& key, + const Params& params = getDefaultParams()); + + /** + * Constructor. + * @param dockControl a pointer to the doc control instance + * @param uniqueDocking - a flag defines is docking should work as tab(at one + * moment only one docked floater can be shown), also this flag defines is dock + * tongue should be used. + * @params key a floater key. + * @params params a floater parameters + */ + LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, + const LLSD& key, const Params& params = getDefaultParams()); + + /** + * Constructor. + * @param dockControl a pointer to the doc control instance + * @param uniqueDocking - a flag defines is docking should work as tab(at one + * moment only one docked floater can be shown). + * @praram useTongue - a flag defines is dock tongue should be used. + * @params key a floater key. + * @params params a floater parameters + */ + LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking, + bool useTongue, const LLSD& key, + const Params& params = getDefaultParams()); + + virtual ~LLDockableFloater(); + + static LLHandle<LLFloater> getInstanceHandle() { return sInstanceHandle; } + + static void toggleInstance(const LLSD& sdname); + + /** + * If descendant class overrides postBuild() in order to perform specific + * construction then it must still invoke its superclass' implementation. + */ + /* virtula */BOOL postBuild(); + /* virtual */void setDocked(bool docked, bool pop_on_undock = true); + /* virtual */void draw(); + + /** + * If descendant class overrides setVisible() then it must still invoke its + * superclass' implementation. + */ + /*virtual*/ void setVisible(BOOL visible); + + /** + * If descendant class overrides setMinimized() then it must still invoke its + * superclass' implementation. + */ + /*virtual*/ void setMinimized(BOOL minimize); + + LLView * getDockWidget(); + + virtual void onDockHidden(); + virtual void onDockShown(); + + LLDockControl* getDockControl(); + + /** + * Returns true if screen channel should consider floater's size when drawing toasts. + * + * By default returns false. + */ + virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); } + virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; } + + bool getUniqueDocking() { return mUniqueDocking; } + bool getUseTongue() { return mUseTongue; } + + void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;} private: - /** - * Provides unique of dockable floater. - * If dockable floater already exists it should be closed. - */ - void resetInstance(); + /** + * Provides unique of dockable floater. + * If dockable floater already exists it should be closed. + */ + void resetInstance(); protected: - void setDockControl(LLDockControl* dockControl); - const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP); + void setDockControl(LLDockControl* dockControl); + const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP); - // Checks if docking should be forced. - // It may be useful e.g. if floater created in mouselook mode (see EXT-5609) - boost::function<BOOL ()> mIsDockedStateForcedCallback; + // Checks if docking should be forced. + // It may be useful e.g. if floater created in mouselook mode (see EXT-5609) + boost::function<BOOL ()> mIsDockedStateForcedCallback; private: - std::unique_ptr<LLDockControl> mDockControl; - LLUIImagePtr mDockTongue; - static LLHandle<LLFloater> sInstanceHandle; - /** - * Provides possibility to define that dockable floaters can be docked - * non exclusively. - */ - bool mUniqueDocking; + std::unique_ptr<LLDockControl> mDockControl; + LLUIImagePtr mDockTongue; + static LLHandle<LLFloater> sInstanceHandle; + /** + * Provides possibility to define that dockable floaters can be docked + * non exclusively. + */ + bool mUniqueDocking; - bool mUseTongue; + bool mUseTongue; - bool mOverlapsScreenChannel; + bool mOverlapsScreenChannel; - // Force docking when the floater is being shown for the first time. - bool mForceDocking; + // Force docking when the floater is being shown for the first time. + bool mForceDocking; }; #endif /* LL_DOCKABLEFLOATER_H */ diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index bd42497cb6..bf0862e8a9 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldockcontrol.cpp * @brief Creates a panel of a specific kind for a toast * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,50 +30,50 @@ #include "lldockablefloater.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : - mDockableFloater(dockableFloater), - mDockTongue(dockTongue), - mDockTongueX(0), - mDockTongueY(0) + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : + mDockableFloater(dockableFloater), + mDockTongue(dockTongue), + mDockTongueX(0), + mDockTongueY(0) { - mDockAt = dockAt; - - if (dockWidget != NULL) - { - mDockWidgetHandle = dockWidget->getHandle(); - } - - if (dockableFloater->isDocked()) - { - on(); - } - else - { - off(); - } - - if (!(get_allowed_rect_callback)) - { - mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1); - } - else - { - mGetAllowedRectCallback = get_allowed_rect_callback; - } - - if (dockWidget != NULL) - { - repositionDockable(); - } - - if (getDock() != NULL) - { - mDockWidgetVisible = isDockVisible(); - } - else - { - mDockWidgetVisible = false; - } + mDockAt = dockAt; + + if (dockWidget != NULL) + { + mDockWidgetHandle = dockWidget->getHandle(); + } + + if (dockableFloater->isDocked()) + { + on(); + } + else + { + off(); + } + + if (!(get_allowed_rect_callback)) + { + mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1); + } + else + { + mGetAllowedRectCallback = get_allowed_rect_callback; + } + + if (dockWidget != NULL) + { + repositionDockable(); + } + + if (getDock() != NULL) + { + mDockWidgetVisible = isDockVisible(); + } + else + { + mDockWidgetVisible = false; + } } LLDockControl::~LLDockControl() @@ -82,302 +82,302 @@ LLDockControl::~LLDockControl() void LLDockControl::setDock(LLView* dockWidget) { - if (dockWidget != NULL) - { - mDockWidgetHandle = dockWidget->getHandle(); - repositionDockable(); - mDockWidgetVisible = isDockVisible(); - } - else - { - mDockWidgetHandle = LLHandle<LLView>(); - mDockWidgetVisible = false; - } + if (dockWidget != NULL) + { + mDockWidgetHandle = dockWidget->getHandle(); + repositionDockable(); + mDockWidgetVisible = isDockVisible(); + } + else + { + mDockWidgetHandle = LLHandle<LLView>(); + mDockWidgetVisible = false; + } } void LLDockControl::getAllowedRect(LLRect& rect) { - rect = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getRect(); + rect = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getRect(); } void LLDockControl::repositionDockable() { - if (!getDock()) return; - LLRect dockRect = getDock()->calcScreenRect(); - LLRect rootRect; - LLRect floater_rect = mDockableFloater->calcScreenRect(); - mGetAllowedRectCallback(rootRect); - - // recalculate dockable position if: - if (mPrevDockRect != dockRect //dock position changed - || mDockWidgetVisible != isDockVisible() //dock visibility changed - || mRootRect != rootRect //root view rect changed - || mFloaterRect != floater_rect //floater rect changed - || mRecalculateDockablePosition //recalculation is forced - ) - { - // undock dockable and off() if dock not visible - if (!isDockVisible()) - { - mDockableFloater->setDocked(false); - // force off() since dockable may not have dockControll at this time - off(); - LLDockableFloater* dockable_floater = - dynamic_cast<LLDockableFloater*> (mDockableFloater); - if(dockable_floater != NULL) - { - dockable_floater->onDockHidden(); - } - } - else - { - if(mEnabled) - { - moveDockable(); - } - LLDockableFloater* dockable_floater = - dynamic_cast<LLDockableFloater*> (mDockableFloater); - if(dockable_floater != NULL) - { - dockable_floater->onDockShown(); - } - } - - mPrevDockRect = dockRect; - mRootRect = rootRect; - mFloaterRect = floater_rect; - mRecalculateDockablePosition = false; - mDockWidgetVisible = isDockVisible(); - } + if (!getDock()) return; + LLRect dockRect = getDock()->calcScreenRect(); + LLRect rootRect; + LLRect floater_rect = mDockableFloater->calcScreenRect(); + mGetAllowedRectCallback(rootRect); + + // recalculate dockable position if: + if (mPrevDockRect != dockRect //dock position changed + || mDockWidgetVisible != isDockVisible() //dock visibility changed + || mRootRect != rootRect //root view rect changed + || mFloaterRect != floater_rect //floater rect changed + || mRecalculateDockablePosition //recalculation is forced + ) + { + // undock dockable and off() if dock not visible + if (!isDockVisible()) + { + mDockableFloater->setDocked(false); + // force off() since dockable may not have dockControll at this time + off(); + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockHidden(); + } + } + else + { + if(mEnabled) + { + moveDockable(); + } + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockShown(); + } + } + + mPrevDockRect = dockRect; + mRootRect = rootRect; + mFloaterRect = floater_rect; + mRecalculateDockablePosition = false; + mDockWidgetVisible = isDockVisible(); + } } bool LLDockControl::isDockVisible() { - bool res = true; - - if (getDock() != NULL) - { - //we should check all hierarchy - res = getDock()->isInVisibleChain(); - if (res) - { - LLRect dockRect = getDock()->calcScreenRect(); - - switch (mDockAt) - { - case LEFT: // to keep compiler happy - break; - case BOTTOM: - case TOP: - { - // check is dock inside parent rect - // assume that parent for all dockable floaters - // is the root view - LLRect dockParentRect = - getDock()->getRootView()->calcScreenRect(); - if (dockRect.mRight <= dockParentRect.mLeft - || dockRect.mLeft >= dockParentRect.mRight) - { - res = false; - } - break; - } - default: - break; - } - } - } - - return res; + bool res = true; + + if (getDock() != NULL) + { + //we should check all hierarchy + res = getDock()->isInVisibleChain(); + if (res) + { + LLRect dockRect = getDock()->calcScreenRect(); + + switch (mDockAt) + { + case LEFT: // to keep compiler happy + break; + case BOTTOM: + case TOP: + { + // check is dock inside parent rect + // assume that parent for all dockable floaters + // is the root view + LLRect dockParentRect = + getDock()->getRootView()->calcScreenRect(); + if (dockRect.mRight <= dockParentRect.mLeft + || dockRect.mLeft >= dockParentRect.mRight) + { + res = false; + } + break; + } + default: + break; + } + } + } + + return res; } void LLDockControl::moveDockable() { - // calculate new dockable position - LLRect dockRect = getDock()->calcScreenRect(); - LLRect rootRect; - mGetAllowedRectCallback(rootRect); - - bool use_tongue = false; - LLDockableFloater* dockable_floater = - dynamic_cast<LLDockableFloater*> (mDockableFloater); - if (dockable_floater != NULL) - { - use_tongue = dockable_floater->getUseTongue(); - } - - LLRect dockableRect = mDockableFloater->calcScreenRect(); - S32 x = 0; - S32 y = 0; - LLRect dockParentRect; - switch (mDockAt) - { - case LEFT: - - x = dockRect.mLeft - dockableRect.getWidth(); - y = dockRect.getCenterY() + dockableRect.getHeight() / 2; - - if (use_tongue) - { - x -= mDockTongue->getWidth(); - } - - mDockTongueX = dockableRect.mRight; - mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; - - break; - - case RIGHT: - - x = dockRect.mRight; - y = dockRect.getCenterY() + dockableRect.getHeight() / 2; - - if (use_tongue) - { - x += mDockTongue->getWidth(); - } - - mDockTongueX = dockRect.mRight; - mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; - - break; - - case TOP: - x = dockRect.getCenterX() - dockableRect.getWidth() / 2; - y = dockRect.mTop + dockableRect.getHeight(); - // unique docking used with dock tongue, so add tongue height to the Y coordinate - if (use_tongue) - { - y += mDockTongue->getHeight(); - - if ( y > rootRect.mTop) - { - y = rootRect.mTop; - } - } - - // check is dockable inside root view rect - if (x < rootRect.mLeft) - { - x = rootRect.mLeft; - } - if (x + dockableRect.getWidth() > rootRect.mRight) - { - x = rootRect.mRight - dockableRect.getWidth(); - } - - - // calculate dock tongue position - dockParentRect = getDock()->getParent()->calcScreenRect(); - if (dockRect.getCenterX() < dockParentRect.mLeft) - { - mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2; - } - else if (dockRect.getCenterX() > dockParentRect.mRight) - { - mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;; - } - else - { - mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; - } - mDockTongueY = dockRect.mTop; - - break; - case BOTTOM: - x = dockRect.getCenterX() - dockableRect.getWidth() / 2; - y = dockRect.mBottom; - // unique docking used with dock tongue, so add tongue height to the Y coordinate - if (use_tongue) - { - y -= mDockTongue->getHeight(); - } - - // check is dockable inside root view rect - if (x < rootRect.mLeft) - { - x = rootRect.mLeft; - } - if (x + dockableRect.getWidth() > rootRect.mRight) - { - x = rootRect.mRight - dockableRect.getWidth(); - } - - // calculate dock tongue position - dockParentRect = getDock()->getParent()->calcScreenRect(); - if (dockRect.getCenterX() < dockParentRect.mLeft) - { - mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2; - } - else if (dockRect.getCenterX() > dockParentRect.mRight) - { - mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;; - } - else - { - mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; - } - mDockTongueY = dockRect.mBottom - mDockTongue->getHeight(); - - break; - } - - S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom - mDockTongueY) - mDockTongue->getHeight(); - - // A floater should be shrunk so it doesn't cover a part of its docking tongue and - // there is a space between a dockable floater and a control to which it is docked. - if (use_tongue && dockableRect.getHeight() >= max_available_height) - { - dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height); - mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight()); - } - else - { - // move dockable - dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), - dockableRect.getHeight()); - } - - LLRect localDocableParentRect; - - mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect); - mDockableFloater->setRect(localDocableParentRect); - mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY); + // calculate new dockable position + LLRect dockRect = getDock()->calcScreenRect(); + LLRect rootRect; + mGetAllowedRectCallback(rootRect); + + bool use_tongue = false; + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if (dockable_floater != NULL) + { + use_tongue = dockable_floater->getUseTongue(); + } + + LLRect dockableRect = mDockableFloater->calcScreenRect(); + S32 x = 0; + S32 y = 0; + LLRect dockParentRect; + switch (mDockAt) + { + case LEFT: + + x = dockRect.mLeft - dockableRect.getWidth(); + y = dockRect.getCenterY() + dockableRect.getHeight() / 2; + + if (use_tongue) + { + x -= mDockTongue->getWidth(); + } + + mDockTongueX = dockableRect.mRight; + mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; + + break; + + case RIGHT: + + x = dockRect.mRight; + y = dockRect.getCenterY() + dockableRect.getHeight() / 2; + + if (use_tongue) + { + x += mDockTongue->getWidth(); + } + + mDockTongueX = dockRect.mRight; + mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2; + + break; + + case TOP: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + y = dockRect.mTop + dockableRect.getHeight(); + // unique docking used with dock tongue, so add tongue height to the Y coordinate + if (use_tongue) + { + y += mDockTongue->getHeight(); + + if ( y > rootRect.mTop) + { + y = rootRect.mTop; + } + } + + // check is dockable inside root view rect + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } + + + // calculate dock tongue position + dockParentRect = getDock()->getParent()->calcScreenRect(); + if (dockRect.getCenterX() < dockParentRect.mLeft) + { + mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2; + } + else if (dockRect.getCenterX() > dockParentRect.mRight) + { + mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;; + } + else + { + mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; + } + mDockTongueY = dockRect.mTop; + + break; + case BOTTOM: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + y = dockRect.mBottom; + // unique docking used with dock tongue, so add tongue height to the Y coordinate + if (use_tongue) + { + y -= mDockTongue->getHeight(); + } + + // check is dockable inside root view rect + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } + + // calculate dock tongue position + dockParentRect = getDock()->getParent()->calcScreenRect(); + if (dockRect.getCenterX() < dockParentRect.mLeft) + { + mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2; + } + else if (dockRect.getCenterX() > dockParentRect.mRight) + { + mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;; + } + else + { + mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; + } + mDockTongueY = dockRect.mBottom - mDockTongue->getHeight(); + + break; + } + + S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom - mDockTongueY) - mDockTongue->getHeight(); + + // A floater should be shrunk so it doesn't cover a part of its docking tongue and + // there is a space between a dockable floater and a control to which it is docked. + if (use_tongue && dockableRect.getHeight() >= max_available_height) + { + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height); + mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight()); + } + else + { + // move dockable + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), + dockableRect.getHeight()); + } + + LLRect localDocableParentRect; + + mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect); + mDockableFloater->setRect(localDocableParentRect); + mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY); } void LLDockControl::on() { - if (isDockVisible()) - { - mEnabled = true; - mRecalculateDockablePosition = true; - } + if (isDockVisible()) + { + mEnabled = true; + mRecalculateDockablePosition = true; + } } void LLDockControl::off() { - mEnabled = false; + mEnabled = false; } void LLDockControl::forceRecalculatePosition() { - mRecalculateDockablePosition = true; + mRecalculateDockablePosition = true; } void LLDockControl::drawToungue() { - bool use_tongue = false; - LLDockableFloater* dockable_floater = - dynamic_cast<LLDockableFloater*> (mDockableFloater); - if (dockable_floater != NULL) - { - use_tongue = dockable_floater->getUseTongue(); - } - - if (mEnabled && use_tongue) - { - mDockTongue->draw(mDockTongueX, mDockTongueY); - } + bool use_tongue = false; + LLDockableFloater* dockable_floater = + dynamic_cast<LLDockableFloater*> (mDockableFloater); + if (dockable_floater != NULL) + { + use_tongue = dockable_floater->getUseTongue(); + } + + if (mEnabled && use_tongue) + { + mDockTongue->draw(mDockTongueX, mDockTongueY); + } } diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 98a9c7236d..fb0bf7d251 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -1,25 +1,25 @@ -/** +/** * @file lldockcontrol.h * @brief Creates a panel of a specific kind for a toast. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,58 +39,58 @@ class LLDockControl { public: - enum DocAt - { - TOP, - LEFT, - RIGHT, - BOTTOM - }; + enum DocAt + { + TOP, + LEFT, + RIGHT, + BOTTOM + }; public: - // callback for a function getting a rect valid for control's position - typedef boost::function<void (LLRect& )> get_allowed_rect_callback_t; + // callback for a function getting a rect valid for control's position + typedef boost::function<void (LLRect& )> get_allowed_rect_callback_t; - LOG_CLASS(LLDockControl); - LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL); - virtual ~LLDockControl(); + LOG_CLASS(LLDockControl); + LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL); + virtual ~LLDockControl(); public: - void on(); - void off(); - void forceRecalculatePosition(); - void setDock(LLView* dockWidget); - LLView* getDock() - { - return mDockWidgetHandle.get(); - } - void repositionDockable(); - void drawToungue(); - bool isDockVisible(); + void on(); + void off(); + void forceRecalculatePosition(); + void setDock(LLView* dockWidget); + LLView* getDock() + { + return mDockWidgetHandle.get(); + } + void repositionDockable(); + void drawToungue(); + bool isDockVisible(); - // gets a rect that bounds possible positions for a dockable control (EXT-1111) - void getAllowedRect(LLRect& rect); + // gets a rect that bounds possible positions for a dockable control (EXT-1111) + void getAllowedRect(LLRect& rect); - S32 getTongueWidth() { return mDockTongue->getWidth(); } - S32 getTongueHeight() { return mDockTongue->getHeight(); } + S32 getTongueWidth() { return mDockTongue->getWidth(); } + S32 getTongueHeight() { return mDockTongue->getHeight(); } private: - virtual void moveDockable(); + virtual void moveDockable(); private: - get_allowed_rect_callback_t mGetAllowedRectCallback; - bool mEnabled; - bool mRecalculateDockablePosition; - bool mDockWidgetVisible; - DocAt mDockAt; - LLHandle<LLView> mDockWidgetHandle; - LLRect mPrevDockRect; - LLRect mRootRect; - LLRect mFloaterRect; - LLFloater* mDockableFloater; - LLUIImagePtr mDockTongue; - S32 mDockTongueX; - S32 mDockTongueY; + get_allowed_rect_callback_t mGetAllowedRectCallback; + bool mEnabled; + bool mRecalculateDockablePosition; + bool mDockWidgetVisible; + DocAt mDockAt; + LLHandle<LLView> mDockWidgetHandle; + LLRect mPrevDockRect; + LLRect mRootRect; + LLRect mFloaterRect; + LLFloater* mDockableFloater; + LLUIImagePtr mDockTongue; + S32 mDockTongueX; + S32 mDockTongueY; }; #endif /* LL_DOCKCONTROL_H */ diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 220f5ee825..dbec1d5d80 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldraghandle.cpp * @brief LLDragHandle base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,221 +50,221 @@ const S32 LEFT_PAD = BORDER_PAD + TITLE_HPAD + LEADING_PAD; S32 LLDragHandle::sSnapMargin = 5; LLDragHandle::LLDragHandle(const LLDragHandle::Params& p) -: LLView(p), - mDragLastScreenX( 0 ), - mDragLastScreenY( 0 ), - mLastMouseScreenX( 0 ), - mLastMouseScreenY( 0 ), - mTitleBox( NULL ), - mMaxTitleWidth( 0 ), - mForeground( TRUE ), - mDragHighlightColor(p.drag_highlight_color()), - mDragShadowColor(p.drag_shadow_color()) +: LLView(p), + mDragLastScreenX( 0 ), + mDragLastScreenY( 0 ), + mLastMouseScreenX( 0 ), + mLastMouseScreenY( 0 ), + mTitleBox( NULL ), + mMaxTitleWidth( 0 ), + mForeground( TRUE ), + mDragHighlightColor(p.drag_highlight_color()), + mDragShadowColor(p.drag_shadow_color()) { - static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); - sSnapMargin = snap_margin; + static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); + sSnapMargin = snap_margin; } LLDragHandle::~LLDragHandle() { gFocusMgr.removeKeyboardFocusWithoutCallback(this); - removeChild(mTitleBox); - delete mTitleBox; + removeChild(mTitleBox); + delete mTitleBox; } void LLDragHandle::initFromParams(const LLDragHandle::Params& p) { - LLView::initFromParams(p); - setTitle( p.label ); + LLView::initFromParams(p); + setTitle( p.label ); } -void LLDragHandle::setTitleVisible(BOOL visible) -{ - if(mTitleBox) - { - mTitleBox->setVisible(visible); - } +void LLDragHandle::setTitleVisible(BOOL visible) +{ + if(mTitleBox) + { + mTitleBox->setVisible(visible); + } } void LLDragHandleTop::setTitle(const std::string& title) { - std::string trimmed_title = title; - LLStringUtil::trim(trimmed_title); - - if( mTitleBox ) - { - mTitleBox->setText(trimmed_title); - } - else - { - const LLFontGL* font = LLFontGL::getFontSansSerif(); - LLTextBox::Params params; - params.name("Drag Handle Title"); - params.rect(getRect()); - params.initial_value(trimmed_title); - params.font(font); - params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); - params.font_shadow(LLFontGL::DROP_SHADOW_SOFT); - params.use_ellipses = true; - params.parse_urls = false; //cancel URL replacement in floater title - mTitleBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild( mTitleBox ); - } - - reshapeTitleBox(); + std::string trimmed_title = title; + LLStringUtil::trim(trimmed_title); + + if( mTitleBox ) + { + mTitleBox->setText(trimmed_title); + } + else + { + const LLFontGL* font = LLFontGL::getFontSansSerif(); + LLTextBox::Params params; + params.name("Drag Handle Title"); + params.rect(getRect()); + params.initial_value(trimmed_title); + params.font(font); + params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); + params.font_shadow(LLFontGL::DROP_SHADOW_SOFT); + params.use_ellipses = true; + params.parse_urls = false; //cancel URL replacement in floater title + mTitleBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild( mTitleBox ); + } + + reshapeTitleBox(); } std::string LLDragHandleTop::getTitle() const { - return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText(); + return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText(); } void LLDragHandleLeft::setTitle(const std::string& ) { - if( mTitleBox ) - { - removeChild(mTitleBox); - delete mTitleBox; - mTitleBox = NULL; - } - /* no title on left edge */ + if( mTitleBox ) + { + removeChild(mTitleBox); + delete mTitleBox; + mTitleBox = NULL; + } + /* no title on left edge */ } std::string LLDragHandleLeft::getTitle() const { - return LLStringUtil::null; + return LLStringUtil::null; } void LLDragHandleTop::draw() { - /* Disable lines. Can drag anywhere in most windows. JC - if( getVisible() && getEnabled() && mForeground) - { - const S32 BORDER_PAD = 2; - const S32 HPAD = 2; - const S32 VPAD = 2; - S32 left = BORDER_PAD + HPAD; - S32 top = getRect().getHeight() - 2 * VPAD; - S32 right = getRect().getWidth() - HPAD; -// S32 bottom = VPAD; - - // draw lines for drag areas - - const S32 LINE_SPACING = (DRAG_HANDLE_HEIGHT - 2 * VPAD) / 4; - S32 line = top - LINE_SPACING; - - LLRect title_rect = mTitleBox->getRect(); - S32 title_right = title_rect.mLeft + mTitleWidth; - BOOL show_right_side = title_right < getRect().getWidth(); - - for( S32 i=0; i<4; i++ ) - { - gl_line_2d(left, line+1, title_rect.mLeft - LEADING_PAD, line+1, mDragHighlightColor); - if( show_right_side ) - { - gl_line_2d(title_right, line+1, right, line+1, mDragHighlightColor); - } - - gl_line_2d(left, line, title_rect.mLeft - LEADING_PAD, line, mDragShadowColor); - if( show_right_side ) - { - gl_line_2d(title_right, line, right, line, mDragShadowColor); - } - line -= LINE_SPACING; - } - } - */ - - // Colorize the text to match the frontmost state - if (mTitleBox) - { - mTitleBox->setEnabled(getForeground()); - } - - LLView::draw(); + /* Disable lines. Can drag anywhere in most windows. JC + if( getVisible() && getEnabled() && mForeground) + { + const S32 BORDER_PAD = 2; + const S32 HPAD = 2; + const S32 VPAD = 2; + S32 left = BORDER_PAD + HPAD; + S32 top = getRect().getHeight() - 2 * VPAD; + S32 right = getRect().getWidth() - HPAD; +// S32 bottom = VPAD; + + // draw lines for drag areas + + const S32 LINE_SPACING = (DRAG_HANDLE_HEIGHT - 2 * VPAD) / 4; + S32 line = top - LINE_SPACING; + + LLRect title_rect = mTitleBox->getRect(); + S32 title_right = title_rect.mLeft + mTitleWidth; + BOOL show_right_side = title_right < getRect().getWidth(); + + for( S32 i=0; i<4; i++ ) + { + gl_line_2d(left, line+1, title_rect.mLeft - LEADING_PAD, line+1, mDragHighlightColor); + if( show_right_side ) + { + gl_line_2d(title_right, line+1, right, line+1, mDragHighlightColor); + } + + gl_line_2d(left, line, title_rect.mLeft - LEADING_PAD, line, mDragShadowColor); + if( show_right_side ) + { + gl_line_2d(title_right, line, right, line, mDragShadowColor); + } + line -= LINE_SPACING; + } + } + */ + + // Colorize the text to match the frontmost state + if (mTitleBox) + { + mTitleBox->setEnabled(getForeground()); + } + + LLView::draw(); } // assumes GL state is set for 2D void LLDragHandleLeft::draw() { - /* Disable lines. Can drag anywhere in most windows. JC - if( getVisible() && getEnabled() && mForeground ) - { - const S32 BORDER_PAD = 2; -// const S32 HPAD = 2; - const S32 VPAD = 2; - const S32 LINE_SPACING = 3; - - S32 left = BORDER_PAD + LINE_SPACING; - S32 top = getRect().getHeight() - 2 * VPAD; -// S32 right = getRect().getWidth() - HPAD; - S32 bottom = VPAD; - - // draw lines for drag areas - - // no titles yet - //LLRect title_rect = mTitleBox->getRect(); - //S32 title_right = title_rect.mLeft + mTitleWidth; - //BOOL show_right_side = title_right < getRect().getWidth(); - - S32 line = left; - for( S32 i=0; i<4; i++ ) - { - gl_line_2d(line, top, line, bottom, mDragHighlightColor); - - gl_line_2d(line+1, top, line+1, bottom, mDragShadowColor); - - line += LINE_SPACING; - } - } - */ - - // Colorize the text to match the frontmost state - if (mTitleBox) - { - mTitleBox->setEnabled(getForeground()); - } - - LLView::draw(); + /* Disable lines. Can drag anywhere in most windows. JC + if( getVisible() && getEnabled() && mForeground ) + { + const S32 BORDER_PAD = 2; +// const S32 HPAD = 2; + const S32 VPAD = 2; + const S32 LINE_SPACING = 3; + + S32 left = BORDER_PAD + LINE_SPACING; + S32 top = getRect().getHeight() - 2 * VPAD; +// S32 right = getRect().getWidth() - HPAD; + S32 bottom = VPAD; + + // draw lines for drag areas + + // no titles yet + //LLRect title_rect = mTitleBox->getRect(); + //S32 title_right = title_rect.mLeft + mTitleWidth; + //BOOL show_right_side = title_right < getRect().getWidth(); + + S32 line = left; + for( S32 i=0; i<4; i++ ) + { + gl_line_2d(line, top, line, bottom, mDragHighlightColor); + + gl_line_2d(line+1, top, line+1, bottom, mDragShadowColor); + + line += LINE_SPACING; + } + } + */ + + // Colorize the text to match the frontmost state + if (mTitleBox) + { + mTitleBox->setEnabled(getForeground()); + } + + LLView::draw(); } void LLDragHandleTop::reshapeTitleBox() { - static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0); - if( ! mTitleBox) - { - return; - } - const LLFontGL* font = LLFontGL::getFontSansSerif(); - S32 title_width = getRect().getWidth(); - title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); - S32 title_height = font->getLineHeight(); - LLRect title_rect; - title_rect.setLeftTopAndSize( - LEFT_PAD, - getRect().getHeight() - title_vpad, - title_width, - title_height); - - // calls reshape on mTitleBox - mTitleBox->setShape( title_rect ); + static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0); + if( ! mTitleBox) + { + return; + } + const LLFontGL* font = LLFontGL::getFontSansSerif(); + S32 title_width = getRect().getWidth(); + title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); + S32 title_height = font->getLineHeight(); + LLRect title_rect; + title_rect.setLeftTopAndSize( + LEFT_PAD, + getRect().getHeight() - title_vpad, + title_width, + title_height); + + // calls reshape on mTitleBox + mTitleBox->setShape( title_rect ); } void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLView::reshape(width, height, called_from_parent); - reshapeTitleBox(); + LLView::reshape(width, height, called_from_parent); + reshapeTitleBox(); } void LLDragHandleLeft::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLView::reshape(width, height, called_from_parent); + LLView::reshape(width, height, called_from_parent); } //------------------------------------------------------------- @@ -273,115 +273,115 @@ void LLDragHandleLeft::reshape(S32 width, S32 height, BOOL called_from_parent) BOOL LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask) { - // Route future Mouse messages here preemptively. (Release on mouse up.) - // No handler needed for focus lost since this clas has no state that depends on it. - gFocusMgr.setMouseCapture(this); + // Route future Mouse messages here preemptively. (Release on mouse up.) + // No handler needed for focus lost since this clas has no state that depends on it. + gFocusMgr.setMouseCapture(this); - localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); - mLastMouseScreenX = mDragLastScreenX; - mLastMouseScreenY = mDragLastScreenY; + localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); + mLastMouseScreenX = mDragLastScreenX; + mLastMouseScreenY = mDragLastScreenY; - // Note: don't pass on to children - return TRUE; + // Note: don't pass on to children + return TRUE; } BOOL LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask) { - if( hasMouseCapture() ) - { - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - } - - // Note: don't pass on to children - return TRUE; + if( hasMouseCapture() ) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + } + + // Note: don't pass on to children + return TRUE; } BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // We only handle the click if the click both started and ended within us - if( hasMouseCapture() ) - { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - // Resize the parent - S32 delta_x = screen_x - mDragLastScreenX; - S32 delta_y = screen_y - mDragLastScreenY; - - // if dragging a docked floater we want to undock - LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); - if (parent && parent->isDocked()) - { - const S32 SLOP = 12; - - if (delta_y <= -SLOP || - delta_y >= SLOP) - { - parent->setDocked(false, false); - return TRUE; - } - else - { - return FALSE; - } - } - - LLRect original_rect = getParent()->getRect(); - LLRect translated_rect = getParent()->getRect(); - translated_rect.translate(delta_x, delta_y); - // temporarily slam dragged window to new position - getParent()->setRect(translated_rect); - S32 pre_snap_x = getParent()->getRect().mLeft; - S32 pre_snap_y = getParent()->getRect().mBottom; - mDragLastScreenX = screen_x; - mDragLastScreenY = screen_y; - - LLRect new_rect; - LLCoordGL mouse_dir; - // use hysteresis on mouse motion to preserve user intent when mouse stops moving - mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; - mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; - mLastMouseDir = mouse_dir; - mLastMouseScreenX = screen_x; - mLastMouseScreenY = screen_y; - - LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin); - - getParent()->setSnappedTo(snap_view); - delta_x = new_rect.mLeft - pre_snap_x; - delta_y = new_rect.mBottom - pre_snap_y; - translated_rect.translate(delta_x, delta_y); - - // restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc - getParent()->setRect(original_rect); - getParent()->setShape(translated_rect, true); - - mDragLastScreenX += delta_x; - mDragLastScreenY += delta_y; - - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" <<LL_ENDL; - handled = TRUE; - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; - handled = TRUE; - } - - // Note: don't pass on to children - - return handled; + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + // Resize the parent + S32 delta_x = screen_x - mDragLastScreenX; + S32 delta_y = screen_y - mDragLastScreenY; + + // if dragging a docked floater we want to undock + LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); + if (parent && parent->isDocked()) + { + const S32 SLOP = 12; + + if (delta_y <= -SLOP || + delta_y >= SLOP) + { + parent->setDocked(false, false); + return TRUE; + } + else + { + return FALSE; + } + } + + LLRect original_rect = getParent()->getRect(); + LLRect translated_rect = getParent()->getRect(); + translated_rect.translate(delta_x, delta_y); + // temporarily slam dragged window to new position + getParent()->setRect(translated_rect); + S32 pre_snap_x = getParent()->getRect().mLeft; + S32 pre_snap_y = getParent()->getRect().mBottom; + mDragLastScreenX = screen_x; + mDragLastScreenY = screen_y; + + LLRect new_rect; + LLCoordGL mouse_dir; + // use hysteresis on mouse motion to preserve user intent when mouse stops moving + mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; + mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; + mLastMouseDir = mouse_dir; + mLastMouseScreenX = screen_x; + mLastMouseScreenY = screen_y; + + LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin); + + getParent()->setSnappedTo(snap_view); + delta_x = new_rect.mLeft - pre_snap_x; + delta_y = new_rect.mBottom - pre_snap_y; + translated_rect.translate(delta_x, delta_y); + + // restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc + getParent()->setRect(original_rect); + getParent()->setShape(translated_rect, true); + + mDragLastScreenX += delta_x; + mDragLastScreenY += delta_y; + + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" <<LL_ENDL; + handled = TRUE; + } + else + { + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + handled = TRUE; + } + + // Note: don't pass on to children + + return handled; } void LLDragHandle::setValue(const LLSD& value) { - setTitle(value.asString()); + setTitle(value.asString()); } diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h index e095e577b1..f61dae8dc3 100644 --- a/indra/llui/lldraghandle.h +++ b/indra/llui/lldraghandle.h @@ -1,25 +1,25 @@ -/** +/** * @file lldraghandle.h * @brief LLDragHandle base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,64 +39,64 @@ class LLTextBox; class LLDragHandle : public LLView { public: - struct Params - : public LLInitParam::Block<Params, LLView::Params> - { - Optional<std::string> label; - Optional<LLUIColor> drag_highlight_color; - Optional<LLUIColor> drag_shadow_color; - - Params() - : label("label"), - drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")), - drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark")) - { - changeDefault(mouse_opaque, true); - changeDefault(follows.flags, FOLLOWS_ALL); - } - }; - void initFromParams(const Params&); - - virtual ~LLDragHandle(); - - virtual void setValue(const LLSD& value); - - void setForeground(BOOL b) { mForeground = b; } - BOOL getForeground() const { return mForeground; } - void setMaxTitleWidth(S32 max_width) {mMaxTitleWidth = llmin(max_width, mMaxTitleWidth); } - S32 getMaxTitleWidth() const { return mMaxTitleWidth; } - void setButtonsRect(const LLRect& rect){ mButtonsRect = rect; } - LLRect getButtonsRect() { return mButtonsRect; } - void setTitleVisible(BOOL visible); - - virtual void setTitle( const std::string& title ) = 0; - virtual std::string getTitle() const = 0; - - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + struct Params + : public LLInitParam::Block<Params, LLView::Params> + { + Optional<std::string> label; + Optional<LLUIColor> drag_highlight_color; + Optional<LLUIColor> drag_shadow_color; + + Params() + : label("label"), + drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")), + drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark")) + { + changeDefault(mouse_opaque, true); + changeDefault(follows.flags, FOLLOWS_ALL); + } + }; + void initFromParams(const Params&); + + virtual ~LLDragHandle(); + + virtual void setValue(const LLSD& value); + + void setForeground(BOOL b) { mForeground = b; } + BOOL getForeground() const { return mForeground; } + void setMaxTitleWidth(S32 max_width) {mMaxTitleWidth = llmin(max_width, mMaxTitleWidth); } + S32 getMaxTitleWidth() const { return mMaxTitleWidth; } + void setButtonsRect(const LLRect& rect){ mButtonsRect = rect; } + LLRect getButtonsRect() { return mButtonsRect; } + void setTitleVisible(BOOL visible); + + virtual void setTitle( const std::string& title ) = 0; + virtual std::string getTitle() const = 0; + + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); protected: - LLDragHandle(const Params&); - friend class LLUICtrlFactory; - + LLDragHandle(const Params&); + friend class LLUICtrlFactory; + protected: - LLTextBox* mTitleBox; - + LLTextBox* mTitleBox; + private: - LLRect mButtonsRect; - S32 mDragLastScreenX; - S32 mDragLastScreenY; - S32 mLastMouseScreenX; - S32 mLastMouseScreenY; - LLCoordGL mLastMouseDir; - LLUIColor mDragHighlightColor; - LLUIColor mDragShadowColor; - S32 mMaxTitleWidth; - BOOL mForeground; - - // Pixels near the edge to snap floaters. - static S32 sSnapMargin; + LLRect mButtonsRect; + S32 mDragLastScreenX; + S32 mDragLastScreenY; + S32 mLastMouseScreenX; + S32 mLastMouseScreenY; + LLCoordGL mLastMouseDir; + LLUIColor mDragHighlightColor; + LLUIColor mDragShadowColor; + S32 mMaxTitleWidth; + BOOL mForeground; + + // Pixels near the edge to snap floaters. + static S32 sSnapMargin; }; @@ -105,16 +105,16 @@ class LLDragHandleTop : public LLDragHandle { protected: - LLDragHandleTop(const Params& p) : LLDragHandle(p) {} - friend class LLUICtrlFactory; + LLDragHandleTop(const Params& p) : LLDragHandle(p) {} + friend class LLUICtrlFactory; public: - virtual void setTitle( const std::string& title ); - virtual std::string getTitle() const; - virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void setTitle( const std::string& title ); + virtual std::string getTitle() const; + virtual void draw(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); private: - void reshapeTitleBox(); + void reshapeTitleBox(); }; @@ -123,13 +123,13 @@ class LLDragHandleLeft : public LLDragHandle { protected: - LLDragHandleLeft(const Params& p) : LLDragHandle(p) {} - friend class LLUICtrlFactory; + LLDragHandleLeft(const Params& p) : LLDragHandle(p) {} + friend class LLUICtrlFactory; public: - virtual void setTitle( const std::string& title ); - virtual std::string getTitle() const; - virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void setTitle( const std::string& title ); + virtual std::string getTitle() const; + virtual void draw(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); }; diff --git a/indra/llui/lleditmenuhandler.cpp b/indra/llui/lleditmenuhandler.cpp index d48237e377..402628bc6b 100644 --- a/indra/llui/lleditmenuhandler.cpp +++ b/indra/llui/lleditmenuhandler.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lleditmenuhandler.cpp * @authors Aaron Yonas, James Cook * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,8 +33,8 @@ LLEditMenuHandler* LLEditMenuHandler::gEditMenuHandler = NULL; LLEditMenuHandler::~LLEditMenuHandler() { - if (gEditMenuHandler == this) - { - gEditMenuHandler = NULL; - } + if (gEditMenuHandler == this) + { + gEditMenuHandler = NULL; + } } diff --git a/indra/llui/lleditmenuhandler.h b/indra/llui/lleditmenuhandler.h index cd4fea8c52..f516b0f2e2 100644 --- a/indra/llui/lleditmenuhandler.h +++ b/indra/llui/lleditmenuhandler.h @@ -1,25 +1,25 @@ -/** +/** * @file lleditmenuhandler.h * @authors Aaron Yonas, James Cook * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,40 +31,40 @@ class LLEditMenuHandler { public: - // this is needed even though this is just an interface class. - virtual ~LLEditMenuHandler(); - - virtual void undo() {}; - virtual BOOL canUndo() const { return FALSE; } - - virtual void redo() {}; - virtual BOOL canRedo() const { return FALSE; } - - virtual void cut() {}; - virtual BOOL canCut() const { return FALSE; } - - virtual void copy() {}; - virtual BOOL canCopy() const { return FALSE; } - - virtual void paste() {}; - virtual BOOL canPaste() const { return FALSE; } - - // "delete" is a keyword - virtual void doDelete() {}; - virtual BOOL canDoDelete() const { return FALSE; } - - virtual void selectAll() {}; - virtual BOOL canSelectAll() const { return FALSE; } - - virtual void deselect() {}; - virtual BOOL canDeselect() const { return FALSE; } + // this is needed even though this is just an interface class. + virtual ~LLEditMenuHandler(); + + virtual void undo() {}; + virtual BOOL canUndo() const { return FALSE; } + + virtual void redo() {}; + virtual BOOL canRedo() const { return FALSE; } + + virtual void cut() {}; + virtual BOOL canCut() const { return FALSE; } + + virtual void copy() {}; + virtual BOOL canCopy() const { return FALSE; } + + virtual void paste() {}; + virtual BOOL canPaste() const { return FALSE; } + + // "delete" is a keyword + virtual void doDelete() {}; + virtual BOOL canDoDelete() const { return FALSE; } + + virtual void selectAll() {}; + virtual BOOL canSelectAll() const { return FALSE; } + + virtual void deselect() {}; + virtual BOOL canDeselect() const { return FALSE; } - // TODO: Instead of being a public data member, it would be better to hide it altogether - // and have a "set" method and then a bunch of static versions of the cut, copy, paste - // methods, etc that operate on the current global instance. That would drastically - // simplify the existing code that accesses this global variable by putting all the - // null checks in the one implementation of those static methods. -MG - static LLEditMenuHandler* gEditMenuHandler; + // TODO: Instead of being a public data member, it would be better to hide it altogether + // and have a "set" method and then a bunch of static versions of the cut, copy, paste + // methods, etc that operate on the current global instance. That would drastically + // simplify the existing code that accesses this global variable by putting all the + // null checks in the one implementation of those static methods. -MG + static LLEditMenuHandler* gEditMenuHandler; }; diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 89e6ddf987..fbe313924c 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -46,124 +46,124 @@ constexpr S32 HELPER_FLOATER_OFFSET_Y = 0; std::string LLEmojiHelper::getToolTip(llwchar ch) const { - return LLEmojiDictionary::instance().getNameFromEmoji(ch); + return LLEmojiDictionary::instance().getNameFromEmoji(ch); } bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const { - return mHostHandle.get() == ctrl_p; + return mHostHandle.get() == ctrl_p; } // static bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos) { - // If the cursor is currently on a colon start the check one character further back - S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1; - - auto isPartOfShortcode = [](llwchar ch) { - switch (ch) - { - case L'-': - case L'_': - case L'+': - return true; - default: - return LLStringOps::isAlnum(ch); - } - }; - while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1])) - { - shortCodePos--; - } - - bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2); - if (pShortCodePos) - *pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1; - return isShortCode; + // If the cursor is currently on a colon start the check one character further back + S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1; + + auto isPartOfShortcode = [](llwchar ch) { + switch (ch) + { + case L'-': + case L'_': + case L'+': + return true; + default: + return LLStringOps::isAlnum(ch); + } + }; + while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1])) + { + shortCodePos--; + } + + bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2); + if (pShortCodePos) + *pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1; + return isShortCode; } void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> cb) { - // Commit immediately if the user already typed a full shortcode - if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code)) - { - cb(emojiDescrp->Character); - hideHelper(); - return; - } - - if (mHelperHandle.isDead()) - { - LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); - mHelperHandle = pHelperFloater->getHandle(); - mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); - } - setHostCtrl(hostctrl_p); - mEmojiCommitCb = cb; - - S32 floater_x, floater_y; - if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) - { - LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; - return; - } - - LLFloater* pHelperFloater = mHelperHandle.get(); - LLRect rect = pHelperFloater->getRect(); - S32 left = floater_x - HELPER_FLOATER_OFFSET_X; - S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); - rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight()); - pHelperFloater->setRect(rect); - pHelperFloater->openFloater(LLSD().with("hint", short_code)); + // Commit immediately if the user already typed a full shortcode + if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code)) + { + cb(emojiDescrp->Character); + hideHelper(); + return; + } + + if (mHelperHandle.isDead()) + { + LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); + mHelperHandle = pHelperFloater->getHandle(); + mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); + } + setHostCtrl(hostctrl_p); + mEmojiCommitCb = cb; + + S32 floater_x, floater_y; + if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) + { + LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; + return; + } + + LLFloater* pHelperFloater = mHelperHandle.get(); + LLRect rect = pHelperFloater->getRect(); + S32 left = floater_x - HELPER_FLOATER_OFFSET_X; + S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); + rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight()); + pHelperFloater->setRect(rect); + pHelperFloater->openFloater(LLSD().with("hint", short_code)); } void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict) { - mIsHideDisabled &= !strict; - if (mIsHideDisabled || (ctrl_p && !isActive(ctrl_p))) - { - return; - } + mIsHideDisabled &= !strict; + if (mIsHideDisabled || (ctrl_p && !isActive(ctrl_p))) + { + return; + } - setHostCtrl(nullptr); + setHostCtrl(nullptr); } bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask) { - if (mHelperHandle.isDead() || !isActive(ctrl_p)) - { - return false; - } + if (mHelperHandle.isDead() || !isActive(ctrl_p)) + { + return false; + } - return mHelperHandle.get()->handleKey(key, mask, true); + return mHelperHandle.get()->handleKey(key, mask, true); } void LLEmojiHelper::onCommitEmoji(llwchar emoji) { - if (!mHostHandle.isDead() && mEmojiCommitCb) - { - mEmojiCommitCb(emoji); - } + if (!mHostHandle.isDead() && mEmojiCommitCb) + { + mEmojiCommitCb(emoji); + } } void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p) { - const LLUICtrl* pCurHostCtrl = mHostHandle.get(); - if (pCurHostCtrl != hostctrl_p) - { - mHostCtrlFocusLostConn.disconnect(); - mHostHandle.markDead(); - mEmojiCommitCb = {}; - - if (!mHelperHandle.isDead()) - { - mHelperHandle.get()->closeFloater(); - } - - if (hostctrl_p) - { - mHostHandle = hostctrl_p->getHandle(); - mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); })); - } - } + const LLUICtrl* pCurHostCtrl = mHostHandle.get(); + if (pCurHostCtrl != hostctrl_p) + { + mHostCtrlFocusLostConn.disconnect(); + mHostHandle.markDead(); + mEmojiCommitCb = {}; + + if (!mHelperHandle.isDead()) + { + mHelperHandle.get()->closeFloater(); + } + + if (hostctrl_p) + { + mHostHandle = hostctrl_p->getHandle(); + mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); })); + } + } } diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h index e826ff93e6..2834b06061 100644 --- a/indra/llui/llemojihelper.h +++ b/indra/llui/llemojihelper.h @@ -36,31 +36,31 @@ class LLUICtrl; class LLEmojiHelper : public LLSingleton<LLEmojiHelper> { - LLSINGLETON(LLEmojiHelper) {} - ~LLEmojiHelper() override {} + LLSINGLETON(LLEmojiHelper) {} + ~LLEmojiHelper() override {} public: - // General - std::string getToolTip(llwchar ch) const; - bool isActive(const LLUICtrl* ctrl_p) const; - static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); - void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> commit_cb); - void hideHelper(const LLUICtrl* ctrl_p = nullptr, bool strict = false); - void setIsHideDisabled(bool disabled) { mIsHideDisabled = disabled; }; + // General + std::string getToolTip(llwchar ch) const; + bool isActive(const LLUICtrl* ctrl_p) const; + static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); + void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> commit_cb); + void hideHelper(const LLUICtrl* ctrl_p = nullptr, bool strict = false); + void setIsHideDisabled(bool disabled) { mIsHideDisabled = disabled; }; - // Eventing - bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); - void onCommitEmoji(llwchar emoji); + // Eventing + bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); + void onCommitEmoji(llwchar emoji); protected: - LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } - void setHostCtrl(LLUICtrl* hostctrl_p); + LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } + void setHostCtrl(LLUICtrl* hostctrl_p); private: - LLHandle<LLUICtrl> mHostHandle; - LLHandle<LLFloater> mHelperHandle; - boost::signals2::connection mHostCtrlFocusLostConn; - boost::signals2::connection mHelperCommitConn; - std::function<void(llwchar)> mEmojiCommitCb; - bool mIsHideDisabled; + LLHandle<LLUICtrl> mHostHandle; + LLHandle<LLFloater> mHelperHandle; + boost::signals2::connection mHostCtrlFocusLostConn; + boost::signals2::connection mHelperCommitConn; + std::function<void(llwchar)> mEmojiCommitCb; + bool mIsHideDisabled; }; diff --git a/indra/llui/llf32uictrl.cpp b/indra/llui/llf32uictrl.cpp index d186f085b4..52954ebbbb 100644 --- a/indra/llui/llf32uictrl.cpp +++ b/indra/llui/llf32uictrl.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-08 * @brief Implementation for llf32uictrl. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,13 +36,13 @@ // other Linden headers LLF32UICtrl::LLF32UICtrl(const Params& p) -: LLUICtrl(p), - mInitialValue(p.initial_value().asReal()), - mMinValue(p.min_value), - mMaxValue(p.max_value), +: LLUICtrl(p), + mInitialValue(p.initial_value().asReal()), + mMinValue(p.min_value), + mMaxValue(p.max_value), mIncrement(p.increment) { - mViewModel->setValue(p.initial_value); + mViewModel->setValue(p.initial_value); } F32 LLF32UICtrl::getValueF32() const diff --git a/indra/llui/llf32uictrl.h b/indra/llui/llf32uictrl.h index 6e648f9102..08b9ec7716 100644 --- a/indra/llui/llf32uictrl.h +++ b/indra/llui/llf32uictrl.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-08 * @brief Base class for float-valued LLUICtrl widgets - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,42 +36,42 @@ class LLF32UICtrl: public LLUICtrl public: struct Params: public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<F32> min_value, - max_value, - increment; + Optional<F32> min_value, + max_value, + increment; - Params() - : min_value("min_val", 0.f), - max_value("max_val", 1.f), - increment("increment", 0.1f) - {} + Params() + : min_value("min_val", 0.f), + max_value("max_val", 1.f), + increment("increment", 0.1f) + {} }; protected: LLF32UICtrl(const Params& p); public: - virtual F32 getValueF32() const; + virtual F32 getValueF32() const; - virtual void setValue(const LLSD& value ) { mViewModel->setValue(value); } - virtual LLSD getValue() const { return LLSD(getValueF32()); } + virtual void setValue(const LLSD& value ) { mViewModel->setValue(value); } + virtual LLSD getValue() const { return LLSD(getValueF32()); } - virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } - virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } - virtual F32 getInitialValue() const { return mInitialValue; } - virtual F32 getMinValue() const { return mMinValue; } - virtual F32 getMaxValue() const { return mMaxValue; } - virtual F32 getIncrement() const { return mIncrement; } - virtual void setMinValue(F32 min_value) { mMinValue = min_value; } - virtual void setMaxValue(F32 max_value) { mMaxValue = max_value; } - virtual void setIncrement(F32 increment) { mIncrement = increment;} + virtual F32 getInitialValue() const { return mInitialValue; } + virtual F32 getMinValue() const { return mMinValue; } + virtual F32 getMaxValue() const { return mMaxValue; } + virtual F32 getIncrement() const { return mIncrement; } + virtual void setMinValue(F32 min_value) { mMinValue = min_value; } + virtual void setMaxValue(F32 max_value) { mMaxValue = max_value; } + virtual void setIncrement(F32 increment) { mIncrement = increment;} protected: - F32 mInitialValue; - F32 mMinValue; - F32 mMaxValue; - F32 mIncrement; + F32 mInitialValue; + F32 mMinValue; + F32 mMaxValue; + F32 mIncrement; }; #endif /* ! defined(LL_LLF32UICTRL_H) */ diff --git a/indra/llui/llfiltereditor.cpp b/indra/llui/llfiltereditor.cpp index d62874d793..7a5f342cd5 100644 --- a/indra/llui/llfiltereditor.cpp +++ b/indra/llui/llfiltereditor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfiltereditor.cpp * @brief LLFilterEditor implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,20 +27,20 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #include "llfiltereditor.h" LLFilterEditor::LLFilterEditor(const LLFilterEditor::Params& p) -: LLSearchEditor(p) +: LLSearchEditor(p) { - setCommitOnFocusLost(FALSE); // we'll commit on every keystroke, don't re-commit when we take focus away (i.e. we go to interact with the actual results!) + setCommitOnFocusLost(FALSE); // we'll commit on every keystroke, don't re-commit when we take focus away (i.e. we go to interact with the actual results!) } void LLFilterEditor::handleKeystroke() { - this->LLSearchEditor::handleKeystroke(); + this->LLSearchEditor::handleKeystroke(); - // Commit on every keystroke. - onCommit(); + // Commit on every keystroke. + onCommit(); } diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index 52cad3bff4..686827d94c 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -1,34 +1,34 @@ -/** +/** * @file llfiltereditor.h * @brief Text editor widget that represents a filter operation * - * Features: - * Text entry of a single line (text, delete, left and right arrow, insert, return). - * Callbacks either on every keystroke or just on the return key. - * Focus (allow multiple text entry widgets) - * Clipboard (cut, copy, and paste) - * Horizontal scrolling to allow strings longer than widget size allows - * Pre-validation (limit which keys can be used) - * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * Features: + * Text entry of a single line (text, delete, left and right arrow, insert, return). + * Callbacks either on every keystroke or just on the return key. + * Focus (allow multiple text entry widgets) + * Clipboard (cut, copy, and paste) + * Horizontal scrolling to allow strings longer than widget size allows + * Pre-validation (limit which keys can be used) + * Optional line history so previous entries can be recalled by CTRL UP/DOWN * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,15 +41,15 @@ class LLFilterEditor : public LLSearchEditor { public: - struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params> - {}; + struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params> + {}; virtual ~LLFilterEditor() {} protected: - LLFilterEditor(const Params&); - friend class LLUICtrlFactory; + LLFilterEditor(const Params&); + friend class LLUICtrlFactory; - /*virtual*/ void handleKeystroke(); + /*virtual*/ void handleKeystroke(); }; #endif // LL_FILTEREDITOR_H diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 39793316f4..2de05f04c5 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -28,71 +28,71 @@ #include "llui.h" LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) -: LLEventTimer(period), - mCallback(cb), - mCurrentTickCount(0), +: LLEventTimer(period), + mCallback(cb), + mCurrentTickCount(0), mIsFlashingInProgress(false), mIsCurrentlyHighlighted(false), mUnset(false) { - mEventTimer.stop(); + mEventTimer.stop(); - // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. - // Due to Timer is implemented as derived class from EventTimer it is impossible to change period - // in runtime. So, both settings are made as required restart. - mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); - if (mPeriod <= 0) - { - mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); - } + // By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973. + // Due to Timer is implemented as derived class from EventTimer it is impossible to change period + // in runtime. So, both settings are made as required restart. + mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); + if (mPeriod <= 0) + { + mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"); + } } void LLFlashTimer::unset() { - mUnset = true; - mCallback = NULL; + mUnset = true; + mCallback = NULL; } BOOL LLFlashTimer::tick() { - mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; + mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted; - if (mCallback) - { - mCallback(mIsCurrentlyHighlighted); - } + if (mCallback) + { + mCallback(mIsCurrentlyHighlighted); + } - if (++mCurrentTickCount >= mFlashCount) - { - stopFlashing(); - } + if (++mCurrentTickCount >= mFlashCount) + { + stopFlashing(); + } - return mUnset; + return mUnset; } void LLFlashTimer::startFlashing() { - mIsFlashingInProgress = true; - mIsCurrentlyHighlighted = true; - mEventTimer.start(); + mIsFlashingInProgress = true; + mIsCurrentlyHighlighted = true; + mEventTimer.start(); } void LLFlashTimer::stopFlashing() { - mEventTimer.stop(); - mIsFlashingInProgress = false; - mIsCurrentlyHighlighted = false; - mCurrentTickCount = 0; + mEventTimer.stop(); + mIsFlashingInProgress = false; + mIsCurrentlyHighlighted = false; + mCurrentTickCount = 0; } bool LLFlashTimer::isFlashingInProgress() { - return mIsFlashingInProgress; + return mIsFlashingInProgress; } bool LLFlashTimer::isCurrentlyHighlighted() { - return mIsCurrentlyHighlighted; + return mIsCurrentlyHighlighted; } diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index db8d49f009..037e32ac50 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -34,41 +34,41 @@ class LLFlashTimer : public LLEventTimer { public: - typedef boost::function<void (bool)> callback_t; + typedef boost::function<void (bool)> callback_t; - /** - * Constructor. - * - * @param count - how many times callback should be called (twice to not change original state) - * @param period - how frequently callback should be called - * @param cb - callback to be called each tick - */ - LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); - ~LLFlashTimer() {}; + /** + * Constructor. + * + * @param count - how many times callback should be called (twice to not change original state) + * @param period - how frequently callback should be called + * @param cb - callback to be called each tick + */ + LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); + ~LLFlashTimer() {}; - /*virtual*/ BOOL tick(); + /*virtual*/ BOOL tick(); - void startFlashing(); - void stopFlashing(); + void startFlashing(); + void stopFlashing(); - bool isFlashingInProgress(); - bool isCurrentlyHighlighted(); - /* - * Use this instead of deleting this object. - * The next call to tick() will return true and that will destroy this object. - */ - void unset(); + bool isFlashingInProgress(); + bool isCurrentlyHighlighted(); + /* + * Use this instead of deleting this object. + * The next call to tick() will return true and that will destroy this object. + */ + void unset(); private: - callback_t mCallback; - /** - * How many times parent will blink. - */ - S32 mFlashCount; - S32 mCurrentTickCount; - bool mIsCurrentlyHighlighted; - bool mIsFlashingInProgress; - bool mUnset; + callback_t mCallback; + /** + * How many times parent will blink. + */ + S32 mFlashCount; + S32 mCurrentTickCount; + bool mIsCurrentlyHighlighted; + bool mIsFlashingInProgress; + bool mUnset; }; #endif /* LL_FLASHTIMER_H */ diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index fd4c33df30..cd866f1625 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llflatlistview.cpp * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,76 +33,76 @@ static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("flat_list_view"); -const LLSD SELECTED_EVENT = LLSD().with("selected", true); -const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); +const LLSD SELECTED_EVENT = LLSD().with("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); //forward declaration bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2); LLFlatListView::Params::Params() -: item_pad("item_pad"), - allow_select("allow_select"), - multi_select("multi_select"), - keep_one_selected("keep_one_selected"), - keep_selection_visible_on_reshape("keep_selection_visible_on_reshape",false), - no_items_text("no_items_text") +: item_pad("item_pad"), + allow_select("allow_select"), + multi_select("multi_select"), + keep_one_selected("keep_one_selected"), + keep_selection_visible_on_reshape("keep_selection_visible_on_reshape",false), + no_items_text("no_items_text") {}; void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { - S32 delta = height - getRect().getHeight(); - LLScrollContainer::reshape(width, height, called_from_parent); - setItemsNoScrollWidth(width); - rearrangeItems(); - - if(delta!= 0 && mKeepSelectionVisibleOnReshape) - { - ensureSelectedVisible(); - } + S32 delta = height - getRect().getHeight(); + LLScrollContainer::reshape(width, height, called_from_parent); + setItemsNoScrollWidth(width); + rearrangeItems(); + + if(delta!= 0 && mKeepSelectionVisibleOnReshape) + { + ensureSelectedVisible(); + } } const LLRect& LLFlatListView::getItemsRect() const { - return mItemsPanel->getRect(); + return mItemsPanel->getRect(); } bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/) { - if (!item) return false; - if (value.isUndefined()) return false; - - //force uniqueness of items, easiest check but unreliable - if (item->getParent() == mItemsPanel) return false; - - item_pair_t* new_pair = new item_pair_t(item, value); - switch (pos) - { - case ADD_TOP: - mItemPairs.push_front(new_pair); - //in LLView::draw() children are iterated in backorder - mItemsPanel->addChildInBack(item); - break; - case ADD_BOTTOM: - mItemPairs.push_back(new_pair); - mItemsPanel->addChild(item); - break; - default: - break; - } - - //_4 is for MASK - item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); - item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); - - // Children don't accept the focus - item->setTabStop(false); - - if (rearrange) - { - rearrangeItems(); - notifyParentItemsRectChanged(); - } - return true; + if (!item) return false; + if (value.isUndefined()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item->getParent() == mItemsPanel) return false; + + item_pair_t* new_pair = new item_pair_t(item, value); + switch (pos) + { + case ADD_TOP: + mItemPairs.push_front(new_pair); + //in LLView::draw() children are iterated in backorder + mItemsPanel->addChildInBack(item); + break; + case ADD_BOTTOM: + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item); + break; + default: + break; + } + + //_4 is for MASK + item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + // Children don't accept the focus + item->setTabStop(false); + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + return true; } bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= true*/) @@ -183,263 +183,263 @@ bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= tr bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value /*= LLUUID::null*/) { - if (!after_item) return false; - if (!item_to_add) return false; - if (value.isUndefined()) return false; - - if (mItemPairs.empty()) return false; - - //force uniqueness of items, easiest check but unreliable - if (item_to_add->getParent() == mItemsPanel) return false; - - item_pair_t* after_pair = getItemPair(after_item); - if (!after_pair) return false; - - item_pair_t* new_pair = new item_pair_t(item_to_add, value); - if (after_pair == mItemPairs.back()) - { - mItemPairs.push_back(new_pair); - mItemsPanel->addChild(item_to_add); - } - else - { - pairs_iterator_t it = mItemPairs.begin(); - for (; it != mItemPairs.end(); ++it) - { - if (*it == after_pair) - { - // insert new elements before the element at position of passed iterator. - mItemPairs.insert(++it, new_pair); - mItemsPanel->addChild(item_to_add); - break; - } - } - } - - //_4 is for MASK - item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); - item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); - - rearrangeItems(); - notifyParentItemsRectChanged(); - return true; + if (!after_item) return false; + if (!item_to_add) return false; + if (value.isUndefined()) return false; + + if (mItemPairs.empty()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item_to_add->getParent() == mItemsPanel) return false; + + item_pair_t* after_pair = getItemPair(after_item); + if (!after_pair) return false; + + item_pair_t* new_pair = new item_pair_t(item_to_add, value); + if (after_pair == mItemPairs.back()) + { + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item_to_add); + } + else + { + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + if (*it == after_pair) + { + // insert new elements before the element at position of passed iterator. + mItemPairs.insert(++it, new_pair); + mItemsPanel->addChild(item_to_add); + break; + } + } + } + + //_4 is for MASK + item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + rearrangeItems(); + notifyParentItemsRectChanged(); + return true; } bool LLFlatListView::removeItem(LLPanel* item, bool rearrange) { - if (!item) return false; - if (item->getParent() != mItemsPanel) return false; - - item_pair_t* item_pair = getItemPair(item); - if (!item_pair) return false; + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; - return removeItemPair(item_pair, rearrange); + return removeItemPair(item_pair, rearrange); } bool LLFlatListView::removeItemByValue(const LLSD& value, bool rearrange) { - if (value.isUndefined()) return false; - - item_pair_t* item_pair = getItemPair(value); - if (!item_pair) return false; + if (value.isUndefined()) return false; - return removeItemPair(item_pair, rearrange); + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return removeItemPair(item_pair, rearrange); } bool LLFlatListView::removeItemByUUID(const LLUUID& uuid, bool rearrange) { - return removeItemByValue(LLSD(uuid), rearrange); + return removeItemByValue(LLSD(uuid), rearrange); } LLPanel* LLFlatListView::getItemByValue(const LLSD& value) const { - if (value.isUndefined()) return NULL; + if (value.isUndefined()) return NULL; - item_pair_t* pair = getItemPair(value); - if (pair) return pair->first; - return NULL; + item_pair_t* pair = getItemPair(value); + if (pair) return pair->first; + return NULL; } bool LLFlatListView::selectItem(LLPanel* item, bool select /*= true*/) { - if (!item) return false; - if (item->getParent() != mItemsPanel) return false; - - item_pair_t* item_pair = getItemPair(item); - if (!item_pair) return false; + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; - return selectItemPair(item_pair, select); + return selectItemPair(item_pair, select); } bool LLFlatListView::selectItemByValue(const LLSD& value, bool select /*= true*/) { - if (value.isUndefined()) return false; + if (value.isUndefined()) return false; - item_pair_t* item_pair = getItemPair(value); - if (!item_pair) return false; + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; - return selectItemPair(item_pair, select); + return selectItemPair(item_pair, select); } bool LLFlatListView::selectItemByUUID(const LLUUID& uuid, bool select /* = true*/) { - return selectItemByValue(LLSD(uuid), select); + return selectItemByValue(LLSD(uuid), select); } LLSD LLFlatListView::getSelectedValue() const { - if (mSelectedItemPairs.empty()) return LLSD(); + if (mSelectedItemPairs.empty()) return LLSD(); - item_pair_t* first_selected_pair = mSelectedItemPairs.front(); - return first_selected_pair->second; + item_pair_t* first_selected_pair = mSelectedItemPairs.front(); + return first_selected_pair->second; } void LLFlatListView::getSelectedValues(std::vector<LLSD>& selected_values) const { - if (mSelectedItemPairs.empty()) return; + if (mSelectedItemPairs.empty()) return; - for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) - { - selected_values.push_back((*it)->second); - } + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_values.push_back((*it)->second); + } } LLUUID LLFlatListView::getSelectedUUID() const { - const LLSD& value = getSelectedValue(); - if (value.isDefined() && value.isUUID()) - { - return value.asUUID(); - } - else - { - return LLUUID::null; - } + const LLSD& value = getSelectedValue(); + if (value.isDefined() && value.isUUID()) + { + return value.asUUID(); + } + else + { + return LLUUID::null; + } } void LLFlatListView::getSelectedUUIDs(uuid_vec_t& selected_uuids) const { - if (mSelectedItemPairs.empty()) return; + if (mSelectedItemPairs.empty()) return; - for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) - { - selected_uuids.push_back((*it)->second.asUUID()); - } + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_uuids.push_back((*it)->second.asUUID()); + } } LLPanel* LLFlatListView::getSelectedItem() const { - if (mSelectedItemPairs.empty()) return NULL; + if (mSelectedItemPairs.empty()) return NULL; - return mSelectedItemPairs.front()->first; + return mSelectedItemPairs.front()->first; } void LLFlatListView::getSelectedItems(std::vector<LLPanel*>& selected_items) const { - if (mSelectedItemPairs.empty()) return; + if (mSelectedItemPairs.empty()) return; - for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) - { - selected_items.push_back((*it)->first); - } + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_items.push_back((*it)->first); + } } void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) { - if (mSelectedItemPairs.empty()) return; + if (mSelectedItemPairs.empty()) return; - for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) - { - item_pair_t* pair_to_deselect = *it; - LLPanel* item = pair_to_deselect->first; - item->setValue(UNSELECTED_EVENT); - } + for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* pair_to_deselect = *it; + LLPanel* item = pair_to_deselect->first; + item->setValue(UNSELECTED_EVENT); + } - mSelectedItemPairs.clear(); + mSelectedItemPairs.clear(); - if (mCommitOnSelectionChange && !no_commit_on_deselection) - { - onCommit(); - } + if (mCommitOnSelectionChange && !no_commit_on_deselection) + { + onCommit(); + } - // Stretch selected item rect to ensure it won't be clipped - mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); } void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) { - mNoItemsCommentTextbox->setValue(comment_text); + mNoItemsCommentTextbox->setValue(comment_text); } U32 LLFlatListView::size(const bool only_visible_items) const { - if (only_visible_items) - { - U32 size = 0; - for (pairs_const_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) - { - if ((*iter)->first->getVisible()) - ++size; - } - return size; - } - else - { - return mItemPairs.size(); - } + if (only_visible_items) + { + U32 size = 0; + for (pairs_const_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + if ((*iter)->first->getVisible()) + ++size; + } + return size; + } + else + { + return mItemPairs.size(); + } } void LLFlatListView::clear() { - // This will clear mSelectedItemPairs, calling all appropriate callbacks. - resetSelection(); - - // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. - for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - mItemsPanel->removeChild((*it)->first); - (*it)->first->die(); - delete *it; - } - mItemPairs.clear(); - - // also set items panel height to zero. Reshape it to allow reshaping of non-item children - LLRect rc = mItemsPanel->getRect(); - rc.mBottom = rc.mTop; - mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); - mItemsPanel->setRect(rc); - - setNoItemsCommentVisible(true); - notifyParentItemsRectChanged(); + // This will clear mSelectedItemPairs, calling all appropriate callbacks. + resetSelection(); + + // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + mItemsPanel->removeChild((*it)->first); + (*it)->first->die(); + delete *it; + } + mItemPairs.clear(); + + // also set items panel height to zero. Reshape it to allow reshaping of non-item children + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + + setNoItemsCommentVisible(true); + notifyParentItemsRectChanged(); } void LLFlatListView::sort() { - if (!mItemComparator) - { - LL_WARNS() << "No comparator specified for sorting FlatListView items." << LL_ENDL; - return; - } - - mItemPairs.sort(ComparatorAdaptor(*mItemComparator)); - rearrangeItems(); + if (!mItemComparator) + { + LL_WARNS() << "No comparator specified for sorting FlatListView items." << LL_ENDL; + return; + } + + mItemPairs.sort(ComparatorAdaptor(*mItemComparator)); + rearrangeItems(); } bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value) { - if (old_value.isUndefined() || new_value.isUndefined()) return false; - if (llsds_are_equal(old_value, new_value)) return false; + if (old_value.isUndefined() || new_value.isUndefined()) return false; + if (llsds_are_equal(old_value, new_value)) return false; - item_pair_t* item_pair = getItemPair(old_value); - if (!item_pair) return false; + item_pair_t* item_pair = getItemPair(old_value); + if (!item_pair) return false; - item_pair->second = new_value; - return true; + item_pair->second = new_value; + return true; } ////////////////////////////////////////////////////////////////////////// @@ -447,7 +447,7 @@ bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value) ////////////////////////////////////////////////////////////////////////// LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) -: LLScrollContainer(p) +: LLScrollContainer(p) , mItemComparator(NULL) , mItemsPanel(NULL) , mItemPad(p.item_pad) @@ -460,857 +460,857 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) , mIsConsecutiveSelection(false) , mKeepSelectionVisibleOnReshape(p.keep_selection_visible_on_reshape) { - mBorderThickness = getBorderWidth(); - - LLRect scroll_rect = getRect(); - LLRect items_rect; - - setItemsNoScrollWidth(scroll_rect.getWidth()); - items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); - - LLPanel::Params pp; - pp.rect(items_rect); - mItemsPanel = LLUICtrlFactory::create<LLPanel> (pp); - addChild(mItemsPanel); - - //we don't need to stretch in vertical direction on reshaping by a parent - //no bottom following! - mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); - - LLViewBorder::Params params; - params.name("scroll border"); - params.rect(getLastSelectedItemRect()); - params.visible(false); - 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); - } + mBorderThickness = getBorderWidth(); + + LLRect scroll_rect = getRect(); + LLRect items_rect; + + setItemsNoScrollWidth(scroll_rect.getWidth()); + items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); + + LLPanel::Params pp; + pp.rect(items_rect); + mItemsPanel = LLUICtrlFactory::create<LLPanel> (pp); + addChild(mItemsPanel); + + //we don't need to stretch in vertical direction on reshaping by a parent + //no bottom following! + mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + LLViewBorder::Params params; + params.name("scroll border"); + params.rect(getLastSelectedItemRect()); + params.visible(false); + 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); + } }; LLFlatListView::~LLFlatListView() { - for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - mItemsPanel->removeChild((*it)->first); - (*it)->first->die(); - delete *it; - } - mItemPairs.clear(); + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + mItemsPanel->removeChild((*it)->first); + (*it)->first->die(); + delete *it; + } + mItemPairs.clear(); } // virtual void LLFlatListView::draw() { - // Highlight border if a child of this container has keyboard focus - if( mSelectedItemsBorder->getVisible() ) - { - mSelectedItemsBorder->setKeyboardFocusHighlight( hasFocus() ); - } - LLScrollContainer::draw(); + // Highlight border if a child of this container has keyboard focus + if( mSelectedItemsBorder->getVisible() ) + { + mSelectedItemsBorder->setKeyboardFocusHighlight( hasFocus() ); + } + LLScrollContainer::draw(); } // virtual BOOL LLFlatListView::postBuild() { - setTabStop(true); - return LLScrollContainer::postBuild(); + setTabStop(true); + return LLScrollContainer::postBuild(); } void LLFlatListView::rearrangeItems() { - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - setNoItemsCommentVisible(0==size()); + setNoItemsCommentVisible(0==size()); - if (mItemPairs.empty()) return; + if (mItemPairs.empty()) return; - //calculating required height - assuming items can be of different height - //list should accommodate all its items - S32 height = 0; + //calculating required height - assuming items can be of different height + //list should accommodate all its items + S32 height = 0; - S32 invisible_children_count = 0; - pairs_iterator_t it = mItemPairs.begin(); - for (; it != mItemPairs.end(); ++it) - { - LLPanel* item = (*it)->first; + S32 invisible_children_count = 0; + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + LLPanel* item = (*it)->first; - // skip invisible child - if (!item->getVisible()) - { - ++invisible_children_count; - continue; - } + // skip invisible child + if (!item->getVisible()) + { + ++invisible_children_count; + continue; + } - height += item->getRect().getHeight(); - } + height += item->getRect().getHeight(); + } - // add paddings between items, excluding invisible ones - height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); + // add paddings between items, excluding invisible ones + height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); - LLRect rc = mItemsPanel->getRect(); - S32 width = mItemsNoScrollWidth; + LLRect rc = mItemsPanel->getRect(); + S32 width = mItemsNoScrollWidth; - // update width to avoid horizontal scrollbar - if (height > getRect().getHeight() - 2 * mBorderThickness) - width -= scrollbar_size; + // update width to avoid horizontal scrollbar + if (height > getRect().getHeight() - 2 * mBorderThickness) + width -= scrollbar_size; - //changes the bottom, end of the list goes down in the scroll container - rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); - mItemsPanel->setRect(rc); + //changes the bottom, end of the list goes down in the scroll container + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); + mItemsPanel->setRect(rc); - //reshaping items - S32 item_new_top = height; - pairs_iterator_t it2, first_it = mItemPairs.begin(); - for (it2 = first_it; it2 != mItemPairs.end(); ++it2) - { - LLPanel* item = (*it2)->first; + //reshaping items + S32 item_new_top = height; + pairs_iterator_t it2, first_it = mItemPairs.begin(); + for (it2 = first_it; it2 != mItemPairs.end(); ++it2) + { + LLPanel* item = (*it2)->first; - // skip invisible child - if (!item->getVisible()) - continue; + // skip invisible child + if (!item->getVisible()) + continue; - LLRect rc = item->getRect(); - rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); - item->reshape(rc.getWidth(), rc.getHeight()); - item->setRect(rc); + LLRect rc = item->getRect(); + rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); + item->reshape(rc.getWidth(), rc.getHeight()); + item->setRect(rc); - // move top for next item in list - item_new_top -= (rc.getHeight() + mItemPad); - } + // move top for next item in list + item_new_top -= (rc.getHeight() + mItemPad); + } - // Stretch selected item rect to ensure it won't be clipped - mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); } void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) { - if (!item_pair) return; - - if (!item_pair->first) - { - LL_WARNS() << "Attempt to selet an item pair containing null panel item" << LL_ENDL; - return; - } - - setFocus(TRUE); - - bool select_item = !isSelected(item_pair); - - //*TODO find a better place for that enforcing stuff - if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; - - if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) - && mMultipleSelection && !mSelectedItemPairs.empty() ) - { - item_pair_t* last_selected_pair = mSelectedItemPairs.back(); - - // If item_pair is already selected - do nothing - if (last_selected_pair == item_pair) - return; - - bool grab_items = false; - bool reverse = false; - pairs_list_t pairs_to_select; - - // Pick out items from list between last selected and current clicked item_pair. - for (pairs_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) - { - item_pair_t* cur = *iter; - if (cur == last_selected_pair || cur == item_pair) - { - // We've got reverse selection if last grabed item isn't a new selection. - reverse = grab_items && (cur != item_pair); - grab_items = !grab_items; - // Skip last selected and current clicked item pairs. - continue; - } - if (!cur->first->getVisible()) - { - // Skip invisible item pairs. - continue; - } - if (grab_items) - { - pairs_to_select.push_back(cur); - } - } - - if (reverse) - { - pairs_to_select.reverse(); - } - - pairs_to_select.push_back(item_pair); - - for (pairs_iterator_t - iter = pairs_to_select.begin(), - iter_end = pairs_to_select.end(); - iter != iter_end; ++iter) - { - item_pair_t* pair_to_select = *iter; - if (isSelected(pair_to_select)) - { - // Item was already selected but there is a need to keep order from last selected pair to new selection. - // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). - mSelectedItemPairs.remove(pair_to_select); - mSelectedItemPairs.push_back(pair_to_select); - } - else - { - selectItemPair(pair_to_select, true); - } - } - - if (!select_item) - { - // Update last selected item border. - mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); - } - return; - } - - //no need to do additional commit on selection reset - if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true); - - //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it - if (mask & MASK_CONTROL) - selectItemPair(item_pair, select_item); - else - selectItemPair(item_pair, true); + if (!item_pair) return; + + if (!item_pair->first) + { + LL_WARNS() << "Attempt to selet an item pair containing null panel item" << LL_ENDL; + return; + } + + setFocus(TRUE); + + bool select_item = !isSelected(item_pair); + + //*TODO find a better place for that enforcing stuff + if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; + + if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) + && mMultipleSelection && !mSelectedItemPairs.empty() ) + { + item_pair_t* last_selected_pair = mSelectedItemPairs.back(); + + // If item_pair is already selected - do nothing + if (last_selected_pair == item_pair) + return; + + bool grab_items = false; + bool reverse = false; + pairs_list_t pairs_to_select; + + // Pick out items from list between last selected and current clicked item_pair. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* cur = *iter; + if (cur == last_selected_pair || cur == item_pair) + { + // We've got reverse selection if last grabed item isn't a new selection. + reverse = grab_items && (cur != item_pair); + grab_items = !grab_items; + // Skip last selected and current clicked item pairs. + continue; + } + if (!cur->first->getVisible()) + { + // Skip invisible item pairs. + continue; + } + if (grab_items) + { + pairs_to_select.push_back(cur); + } + } + + if (reverse) + { + pairs_to_select.reverse(); + } + + pairs_to_select.push_back(item_pair); + + for (pairs_iterator_t + iter = pairs_to_select.begin(), + iter_end = pairs_to_select.end(); + iter != iter_end; ++iter) + { + item_pair_t* pair_to_select = *iter; + if (isSelected(pair_to_select)) + { + // Item was already selected but there is a need to keep order from last selected pair to new selection. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(pair_to_select); + mSelectedItemPairs.push_back(pair_to_select); + } + else + { + selectItemPair(pair_to_select, true); + } + } + + if (!select_item) + { + // Update last selected item border. + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + } + return; + } + + //no need to do additional commit on selection reset + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true); + + //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it + if (mask & MASK_CONTROL) + selectItemPair(item_pair, select_item); + else + selectItemPair(item_pair, true); } void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask) { - if (!item_pair) - return; + if (!item_pair) + return; - // Forbid deselecting of items on right mouse button click if mMultipleSelection flag is set on, - // because some of derived classes may have context menu and selected items must be kept. - if ( !(mask & MASK_CONTROL) && mMultipleSelection && isSelected(item_pair) ) - return; + // Forbid deselecting of items on right mouse button click if mMultipleSelection flag is set on, + // because some of derived classes may have context menu and selected items must be kept. + if ( !(mask & MASK_CONTROL) && mMultipleSelection && isSelected(item_pair) ) + return; - // else got same behavior as at onItemMouseClick - onItemMouseClick(item_pair, mask); + // else got same behavior as at onItemMouseClick + onItemMouseClick(item_pair, mask); } BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) { - BOOL reset_selection = (mask != MASK_SHIFT); - BOOL handled = FALSE; - switch (key) - { - case KEY_RETURN: - { - if (mSelectedItemPairs.size() && mask == MASK_NONE) - { - mOnReturnSignal(this, getValue()); - handled = TRUE; - } - break; - } - case KEY_UP: - { - if ( !selectNextItemPair(true, reset_selection) && reset_selection) - { - // If case we are in accordion tab notify parent to go to the previous accordion - if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed - resetSelection(); - } - break; - } - case KEY_DOWN: - { - if ( !selectNextItemPair(false, reset_selection) && reset_selection) - { - // If case we are in accordion tab notify parent to go to the next accordion - if( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed - resetSelection(); - } - break; - } - case KEY_ESCAPE: - { - if (mask == MASK_NONE) - { - setFocus(FALSE); // pass focus to the game area (EXT-8357) - } - break; - } - default: - break; - } - - if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() ) - { - ensureSelectedVisible(); - /* - LLRect visible_rc = getVisibleContentRect(); - LLRect selected_rc = getLastSelectedItemRect(); - - if ( !visible_rc.contains (selected_rc) ) - { - // But scroll in Items panel coordinates - scrollToShowRect(selected_rc); - } - - // In case we are in accordion tab notify parent to show selected rectangle - LLRect screen_rc; - localRectToScreen(selected_rc, &screen_rc); - notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));*/ - - handled = TRUE; - } - - return handled ? handled : LLScrollContainer::handleKeyHere(key, mask); + BOOL reset_selection = (mask != MASK_SHIFT); + BOOL handled = FALSE; + switch (key) + { + case KEY_RETURN: + { + if (mSelectedItemPairs.size() && mask == MASK_NONE) + { + mOnReturnSignal(this, getValue()); + handled = TRUE; + } + break; + } + case KEY_UP: + { + if ( !selectNextItemPair(true, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the previous accordion + if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + resetSelection(); + } + break; + } + case KEY_DOWN: + { + if ( !selectNextItemPair(false, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the next accordion + if( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed + resetSelection(); + } + break; + } + case KEY_ESCAPE: + { + if (mask == MASK_NONE) + { + setFocus(FALSE); // pass focus to the game area (EXT-8357) + } + break; + } + default: + break; + } + + if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() ) + { + ensureSelectedVisible(); + /* + LLRect visible_rc = getVisibleContentRect(); + LLRect selected_rc = getLastSelectedItemRect(); + + if ( !visible_rc.contains (selected_rc) ) + { + // But scroll in Items panel coordinates + scrollToShowRect(selected_rc); + } + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(selected_rc, &screen_rc); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));*/ + + handled = TRUE; + } + + return handled ? handled : LLScrollContainer::handleKeyHere(key, mask); } LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const { - llassert(item); - - for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - item_pair_t* item_pair = *it; - if (item_pair->first == item) return item_pair; - } - return NULL; + llassert(item); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (item_pair->first == item) return item_pair; + } + return NULL; } //compares two LLSD's bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2) { - llassert(llsd_1.isDefined()); - llassert(llsd_2.isDefined()); - - if (llsd_1.type() != llsd_2.type()) return false; - - if (!llsd_1.isMap()) - { - if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); - - //assumptions that string representaion is enough for other types - return llsd_1.asString() == llsd_2.asString(); - } - - if (llsd_1.size() != llsd_2.size()) return false; - - LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); - LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); - for (S32 i = 0; i < llsd_1.size(); ++i) - { - if ((*llsd_1_it).first != (*llsd_2_it).first) return false; - if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; - ++llsd_1_it; - ++llsd_2_it; - } - return true; + llassert(llsd_1.isDefined()); + llassert(llsd_2.isDefined()); + + if (llsd_1.type() != llsd_2.type()) return false; + + if (!llsd_1.isMap()) + { + if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); + + //assumptions that string representaion is enough for other types + return llsd_1.asString() == llsd_2.asString(); + } + + if (llsd_1.size() != llsd_2.size()) return false; + + LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); + LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); + for (S32 i = 0; i < llsd_1.size(); ++i) + { + if ((*llsd_1_it).first != (*llsd_2_it).first) return false; + if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; + ++llsd_1_it; + ++llsd_2_it; + } + return true; } LLFlatListView::item_pair_t* LLFlatListView::getItemPair(const LLSD& value) const { - llassert(value.isDefined()); - - for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - item_pair_t* item_pair = *it; - if (llsds_are_equal(item_pair->second, value)) return item_pair; - } - return NULL; + llassert(value.isDefined()); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (llsds_are_equal(item_pair->second, value)) return item_pair; + } + return NULL; } bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) { - llassert(item_pair); - - if (!mAllowSelection && select) return false; - - if (isSelected(item_pair) == select) return true; //already in specified selection state - if (select) - { - mSelectedItemPairs.push_back(item_pair); - } - else - { - mSelectedItemPairs.remove(item_pair); - } - - //a way of notifying panel of selection state changes - LLPanel* item = item_pair->first; - item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); - - if (mCommitOnSelectionChange) - { - onCommit(); - } - - // Stretch selected item rect to ensure it won't be clipped - mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); - // By default mark it as not consecutive selection - mIsConsecutiveSelection = false; - - return true; + llassert(item_pair); + + if (!mAllowSelection && select) return false; + + if (isSelected(item_pair) == select) return true; //already in specified selection state + if (select) + { + mSelectedItemPairs.push_back(item_pair); + } + else + { + mSelectedItemPairs.remove(item_pair); + } + + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // By default mark it as not consecutive selection + mIsConsecutiveSelection = false; + + return true; } void LLFlatListView::scrollToShowFirstSelectedItem() { - if (!mSelectedItemPairs.size()) return; + if (!mSelectedItemPairs.size()) return; - LLRect selected_rc = mSelectedItemPairs.front()->first->getRect(); + LLRect selected_rc = mSelectedItemPairs.front()->first->getRect(); - if (selected_rc.isValid()) - { - scrollToShowRect(selected_rc); - } + if (selected_rc.isValid()) + { + scrollToShowRect(selected_rc); + } } LLRect LLFlatListView::getLastSelectedItemRect() { - if (!mSelectedItemPairs.size()) - { - return LLRect::null; - } + if (!mSelectedItemPairs.size()) + { + return LLRect::null; + } - return mSelectedItemPairs.back()->first->getRect(); + return mSelectedItemPairs.back()->first->getRect(); } -void LLFlatListView::selectFirstItem () +void LLFlatListView::selectFirstItem () { - // No items - no actions! - if (0 == size()) return; - - // Select first visible item - for (pairs_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) - { - // skip invisible items - if ( (*iter)->first->getVisible() ) - { - selectItemPair(*iter, true); - ensureSelectedVisible(); - break; - } - } + // No items - no actions! + if (0 == size()) return; + + // Select first visible item + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + // skip invisible items + if ( (*iter)->first->getVisible() ) + { + selectItemPair(*iter, true); + ensureSelectedVisible(); + break; + } + } } -void LLFlatListView::selectLastItem () +void LLFlatListView::selectLastItem () { - // No items - no actions! - if (0 == size()) return; - - // Select last visible item - for (pairs_list_t::reverse_iterator - r_iter = mItemPairs.rbegin(), - r_iter_end = mItemPairs.rend(); - r_iter != r_iter_end; ++r_iter) - { - // skip invisible items - if ( (*r_iter)->first->getVisible() ) - { - selectItemPair(*r_iter, true); - ensureSelectedVisible(); - break; - } - } + // No items - no actions! + if (0 == size()) return; + + // Select last visible item + for (pairs_list_t::reverse_iterator + r_iter = mItemPairs.rbegin(), + r_iter_end = mItemPairs.rend(); + r_iter != r_iter_end; ++r_iter) + { + // skip invisible items + if ( (*r_iter)->first->getVisible() ) + { + selectItemPair(*r_iter, true); + ensureSelectedVisible(); + break; + } + } } void LLFlatListView::ensureSelectedVisible() { - LLRect selected_rc = getLastSelectedItemRect(); + LLRect selected_rc = getLastSelectedItemRect(); - if ( selected_rc.isValid() ) - { - scrollToShowRect(selected_rc); - } + if ( selected_rc.isValid() ) + { + scrollToShowRect(selected_rc); + } } // virtual bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) { - // No items - no actions! - if ( 0 == size() ) - return false; - - if (!mIsConsecutiveSelection) - { - // Leave only one item selected if list has not consecutive selection - if (mSelectedItemPairs.size() && !reset_selection) - { - item_pair_t* cur_sel_pair = mSelectedItemPairs.back(); - resetSelection(); - selectItemPair (cur_sel_pair, true); - } - } - - if ( mSelectedItemPairs.size() ) - { - item_pair_t* to_sel_pair = NULL; - item_pair_t* cur_sel_pair = NULL; - - // Take the last selected pair - cur_sel_pair = mSelectedItemPairs.back(); - // Bases on given direction choose next item to select - if ( is_up_direction ) - { - // Find current selected item position in mItemPairs list - pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); - - for (;++sel_it != mItemPairs.rend();) - { - // skip invisible items - if ( (*sel_it)->first->getVisible() ) - { - to_sel_pair = *sel_it; - break; - } - } - } - else - { - // Find current selected item position in mItemPairs list - pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); - - for (;++sel_it != mItemPairs.end();) - { - // skip invisible items - if ( (*sel_it)->first->getVisible() ) - { - to_sel_pair = *sel_it; - break; - } - } - } - - if ( to_sel_pair ) - { - bool select = true; - if ( reset_selection ) - { - // Reset current selection if we were asked about it - resetSelection(); - } - else - { - // If item already selected and no reset request than we should deselect last selected item. - select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); - } - // Select/Deselect next item - selectItemPair(select ? to_sel_pair : cur_sel_pair, select); - // Mark it as consecutive selection - mIsConsecutiveSelection = true; - return true; - } - } - else - { - // If there weren't selected items then choose the first one bases on given direction - // Force selection to first item - if (is_up_direction) - selectLastItem(); - else - selectFirstItem(); - // Mark it as consecutive selection - mIsConsecutiveSelection = true; - return true; - } - - return false; + // No items - no actions! + if ( 0 == size() ) + return false; + + if (!mIsConsecutiveSelection) + { + // Leave only one item selected if list has not consecutive selection + if (mSelectedItemPairs.size() && !reset_selection) + { + item_pair_t* cur_sel_pair = mSelectedItemPairs.back(); + resetSelection(); + selectItemPair (cur_sel_pair, true); + } + } + + if ( mSelectedItemPairs.size() ) + { + item_pair_t* to_sel_pair = NULL; + item_pair_t* cur_sel_pair = NULL; + + // Take the last selected pair + cur_sel_pair = mSelectedItemPairs.back(); + // Bases on given direction choose next item to select + if ( is_up_direction ) + { + // Find current selected item position in mItemPairs list + pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); + + for (;++sel_it != mItemPairs.rend();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + else + { + // Find current selected item position in mItemPairs list + pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); + + for (;++sel_it != mItemPairs.end();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + + if ( to_sel_pair ) + { + bool select = true; + if ( reset_selection ) + { + // Reset current selection if we were asked about it + resetSelection(); + } + else + { + // If item already selected and no reset request than we should deselect last selected item. + select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); + } + // Select/Deselect next item + selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + } + else + { + // If there weren't selected items then choose the first one bases on given direction + // Force selection to first item + if (is_up_direction) + selectLastItem(); + else + selectFirstItem(); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + + return false; } BOOL LLFlatListView::canSelectAll() const { - return 0 != size() && mAllowSelection && mMultipleSelection; + return 0 != size() && mAllowSelection && mMultipleSelection; } void LLFlatListView::selectAll() { - if (!mAllowSelection || !mMultipleSelection) - return; - - mSelectedItemPairs.clear(); - - for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - item_pair_t* item_pair = *it; - mSelectedItemPairs.push_back(item_pair); - //a way of notifying panel of selection state changes - LLPanel* item = item_pair->first; - item->setValue(SELECTED_EVENT); - } - - if (mCommitOnSelectionChange) - { - onCommit(); - } - - // Stretch selected item rect to ensure it won't be clipped - mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + if (!mAllowSelection || !mMultipleSelection) + return; + + mSelectedItemPairs.clear(); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + mSelectedItemPairs.push_back(item_pair); + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(SELECTED_EVENT); + } + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); } bool LLFlatListView::isSelected(item_pair_t* item_pair) const { - llassert(item_pair); + llassert(item_pair); - pairs_const_iterator_t it_end = mSelectedItemPairs.end(); - return std::find(mSelectedItemPairs.begin(), it_end, item_pair) != it_end; + pairs_const_iterator_t it_end = mSelectedItemPairs.end(); + return std::find(mSelectedItemPairs.begin(), it_end, item_pair) != it_end; } bool LLFlatListView::removeItemPair(item_pair_t* item_pair, bool rearrange) { - llassert(item_pair); - - bool deleted = false; - bool selection_changed = false; - for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - item_pair_t* _item_pair = *it; - if (_item_pair == item_pair) - { - mItemPairs.erase(it); - deleted = true; - break; - } - } - - if (!deleted) return false; - - for (pairs_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) - { - item_pair_t* selected_item_pair = *it; - if (selected_item_pair == item_pair) - { - it = mSelectedItemPairs.erase(it); - selection_changed = true; - break; - } - } - - mItemsPanel->removeChild(item_pair->first); - item_pair->first->die(); - delete item_pair; - - if (rearrange) - { - rearrangeItems(); - notifyParentItemsRectChanged(); - } - - if (selection_changed && mCommitOnSelectionChange) - { - onCommit(); - } - - return true; + llassert(item_pair); + + bool deleted = false; + bool selection_changed = false; + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* _item_pair = *it; + if (_item_pair == item_pair) + { + mItemPairs.erase(it); + deleted = true; + break; + } + } + + if (!deleted) return false; + + for (pairs_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* selected_item_pair = *it; + if (selected_item_pair == item_pair) + { + it = mSelectedItemPairs.erase(it); + selection_changed = true; + break; + } + } + + mItemsPanel->removeChild(item_pair->first); + item_pair->first->die(); + delete item_pair; + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + + if (selection_changed && mCommitOnSelectionChange) + { + onCommit(); + } + + return true; } void LLFlatListView::notifyParentItemsRectChanged() { - S32 comment_height = 0; + S32 comment_height = 0; - // 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 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; - } + // 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(); + LLRect req_rect = getItemsRect(); - // get maximum of items total height and comment text height - req_rect.setOriginAndSize(req_rect.mLeft, req_rect.mBottom, req_rect.getWidth(), llmax(req_rect.getHeight(), comment_height)); + // get maximum of items total height and comment text height + req_rect.setOriginAndSize(req_rect.mLeft, req_rect.mBottom, req_rect.getWidth(), llmax(req_rect.getHeight(), comment_height)); - // take into account border size. - req_rect.stretch(getBorderWidth()); + // take into account border size. + req_rect.stretch(getBorderWidth()); - if (req_rect == mPrevNotifyParentRect) - return; + if (req_rect == mPrevNotifyParentRect) + return; - mPrevNotifyParentRect = req_rect; + mPrevNotifyParentRect = req_rect; - LLSD params; - params["action"] = "size_changes"; - params["width"] = req_rect.getWidth(); - params["height"] = req_rect.getHeight(); + LLSD params; + params["action"] = "size_changes"; + params["width"] = req_rect.getWidth(); + params["height"] = req_rect.getHeight(); - if (getParent()) // dummy widgets don't have a parent - getParent()->notifyParent(params); + if (getParent()) // dummy widgets don't have a parent + getParent()->notifyParent(params); } void LLFlatListView::setNoItemsCommentVisible(bool visible) const { - if (mNoItemsCommentTextbox) - { - mSelectedItemsBorder->setVisible(!visible); - mNoItemsCommentTextbox->setVisible(visible); - } + if (mNoItemsCommentTextbox) + { + mSelectedItemsBorder->setVisible(!visible); + mNoItemsCommentTextbox->setVisible(visible); + } } void LLFlatListView::getItems(std::vector<LLPanel*>& items) const { - if (mItemPairs.empty()) return; + if (mItemPairs.empty()) return; - items.clear(); - for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - items.push_back((*it)->first); - } + items.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + items.push_back((*it)->first); + } } void LLFlatListView::getValues(std::vector<LLSD>& values) const { - if (mItemPairs.empty()) return; + if (mItemPairs.empty()) return; - values.clear(); - for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) - { - values.push_back((*it)->second); - } + values.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + values.push_back((*it)->second); + } } // virtual void LLFlatListView::onFocusReceived() { - if (size()) - { - mSelectedItemsBorder->setVisible(TRUE); - } - gEditMenuHandler = this; + if (size()) + { + mSelectedItemsBorder->setVisible(TRUE); + } + gEditMenuHandler = this; } // virtual void LLFlatListView::onFocusLost() { - mSelectedItemsBorder->setVisible(FALSE); - // Route menu back to the default - if (gEditMenuHandler == this) - { - gEditMenuHandler = NULL; - } + mSelectedItemsBorder->setVisible(FALSE); + // Route menu back to the default + if (gEditMenuHandler == this) + { + gEditMenuHandler = NULL; + } } -//virtual +//virtual S32 LLFlatListView::notify(const LLSD& info) { - if (info.has("action")) - { - std::string str_action = info["action"]; - if (str_action == "select_first") - { - setFocus(true); - selectFirstItem(); - return 1; - } - else if (str_action == "select_last") - { - setFocus(true); - selectLastItem(); - return 1; - } - } - else if (info.has("rearrange")) - { - rearrangeItems(); - notifyParentItemsRectChanged(); - return 1; - } - - return 0; + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + return 1; + } + else if (str_action == "select_last") + { + setFocus(true); + selectLastItem(); + return 1; + } + } + else if (info.has("rearrange")) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + return 1; + } + + return 0; } void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items) { - LLSD action; - action.with("detach", LLSD()); - // Clear detached_items list - detached_items.clear(); - // Go through items and detach valid items, remove them from items panel - // and add to detached_items. - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) - { - LLPanel* pItem = (*iter)->first; - if (1 == pItem->notify(action)) - { - selectItemPair((*iter), false); - mItemsPanel->removeChild(pItem); - detached_items.push_back(pItem); - } - iter++; - } - if (!detached_items.empty()) - { - // Some items were detached, clean ourself from unusable memory - if (detached_items.size() == mItemPairs.size()) - { - // This way will be faster if all items were disconnected - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) - { - (*iter)->first = NULL; - delete *iter; - iter++; - } - mItemPairs.clear(); - // Also set items panel height to zero. - // Reshape it to allow reshaping of non-item children. - LLRect rc = mItemsPanel->getRect(); - rc.mBottom = rc.mTop; - mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); - mItemsPanel->setRect(rc); - setNoItemsCommentVisible(true); - } - else - { - std::vector<LLPanel*>::const_iterator - detached_iter = detached_items.begin(), - detached_iter_end = detached_items.end(); - while (detached_iter < detached_iter_end) - { - LLPanel* pDetachedItem = *detached_iter; - pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); - while (iter != iter_end) - { - item_pair_t* item_pair = *iter; - if (item_pair->first == pDetachedItem) - { - mItemPairs.erase(iter); - item_pair->first = NULL; - delete item_pair; - break; - } - iter++; - } - detached_iter++; - } - rearrangeItems(); - } - notifyParentItemsRectChanged(); - } + LLSD action; + action.with("detach", LLSD()); + // Clear detached_items list + detached_items.clear(); + // Go through items and detach valid items, remove them from items panel + // and add to detached_items. + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) + { + LLPanel* pItem = (*iter)->first; + if (1 == pItem->notify(action)) + { + selectItemPair((*iter), false); + mItemsPanel->removeChild(pItem); + detached_items.push_back(pItem); + } + iter++; + } + if (!detached_items.empty()) + { + // Some items were detached, clean ourself from unusable memory + if (detached_items.size() == mItemPairs.size()) + { + // This way will be faster if all items were disconnected + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) + { + (*iter)->first = NULL; + delete *iter; + iter++; + } + mItemPairs.clear(); + // Also set items panel height to zero. + // Reshape it to allow reshaping of non-item children. + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + setNoItemsCommentVisible(true); + } + else + { + std::vector<LLPanel*>::const_iterator + detached_iter = detached_items.begin(), + detached_iter_end = detached_items.end(); + while (detached_iter < detached_iter_end) + { + LLPanel* pDetachedItem = *detached_iter; + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) + { + item_pair_t* item_pair = *iter; + if (item_pair->first == pDetachedItem) + { + mItemPairs.erase(iter); + item_pair->first = NULL; + delete item_pair; + break; + } + iter++; + } + detached_iter++; + } + rearrangeItems(); + } + notifyParentItemsRectChanged(); + } } @@ -1324,7 +1324,7 @@ LLFlatListViewEx::Params::Params() } LLFlatListViewEx::LLFlatListViewEx(const Params& p) -: LLFlatListView(p) +: LLFlatListView(p) , mNoFilteredItemsMsg(p.no_filtered_items_msg) , mNoItemsMsg(p.no_items_msg) , mForceShowingUnmatchedItems(false) @@ -1334,41 +1334,41 @@ LLFlatListViewEx::LLFlatListViewEx(const Params& p) void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) { - bool items_filtered = !filter_string.empty(); - if (items_filtered) - { - // items were filtered - LLStringUtil::format_map_t args; - args["[SEARCH_TERM]"] = LLURI::escape(filter_string); - std::string text = mNoFilteredItemsMsg; - LLStringUtil::format(text, args); - setNoItemsCommentText(text); - } - else - { - // list does not contain any items at all - setNoItemsCommentText(mNoItemsMsg); - } + bool items_filtered = !filter_string.empty(); + if (items_filtered) + { + // items were filtered + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = mNoFilteredItemsMsg; + LLStringUtil::format(text, args); + setNoItemsCommentText(text); + } + else + { + // list does not contain any items at all + setNoItemsCommentText(mNoItemsMsg); + } } bool LLFlatListViewEx::getForceShowingUnmatchedItems() { - return mForceShowingUnmatchedItems; + return mForceShowingUnmatchedItems; } void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) { - mForceShowingUnmatchedItems = show; + mForceShowingUnmatchedItems = show; } void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent) { - if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) - { - mFilterSubString = filter_str; - updateNoItemsMessage(mFilterSubString); - filterItems(false, notify_parent); - } + if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) + { + mFilterSubString = filter_str; + updateNoItemsMessage(mFilterSubString); + filterItems(false, notify_parent); + } } bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) @@ -1376,49 +1376,49 @@ bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) if (!item) return false; - BOOL visible = TRUE; - - // 0 signifies that filter is matched, - // i.e. we don't hide items that don't support 'match_filter' action, separators etc. - if (0 == item->notify(action)) - { - mHasMatchedItems = true; - } - else - { - // TODO: implement (re)storing of current selection. - if (!mForceShowingUnmatchedItems) - { - selectItem(item, false); - visible = FALSE; - } - } - - if (item->getVisible() != visible) - { - item->setVisible(visible); - return true; - } - - return false; + BOOL visible = TRUE; + + // 0 signifies that filter is matched, + // i.e. we don't hide items that don't support 'match_filter' action, separators etc. + if (0 == item->notify(action)) + { + mHasMatchedItems = true; + } + else + { + // TODO: implement (re)storing of current selection. + if (!mForceShowingUnmatchedItems) + { + selectItem(item, false); + visible = FALSE; + } + } + + if (item->getVisible() != visible) + { + item->setVisible(visible); + return true; + } + + return false; } void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) { - std::string cur_filter = mFilterSubString; - LLStringUtil::toUpper(cur_filter); + std::string cur_filter = mFilterSubString; + LLStringUtil::toUpper(cur_filter); - LLSD action; - action.with("match_filter", cur_filter); + LLSD action; + action.with("match_filter", cur_filter); - mHasMatchedItems = false; - bool visibility_changed = false; - pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end(); - while (iter != iter_end) - { - LLPanel* pItem = (*(iter++))->first; - visibility_changed |= updateItemVisibility(pItem, action); - } + mHasMatchedItems = false; + bool visibility_changed = false; + pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end(); + while (iter != iter_end) + { + LLPanel* pItem = (*(iter++))->first; + visibility_changed |= updateItemVisibility(pItem, action); + } if (re_sort) { @@ -1433,7 +1433,7 @@ void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) bool LLFlatListViewEx::hasMatchedItems() { - return mHasMatchedItems; + return mHasMatchedItems; } //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index adb0e3e553..ba269a7d78 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -1,25 +1,25 @@ -/** +/** * @file llflatlistview.h * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,14 +37,14 @@ * LLSD can be associated with each added item, it can keep data from an item in digested form. * Associated LLSD's can be of any type (singular, a map etc.). * Items (LLPanel's subclasses) can be of different height. - * The list is LLPanel created in itself and grows in height while new items are added. - * + * The list is LLPanel created in itself and grows in height while new items are added. + * * The control can manage selection of its items when the flag "allow_select" is set. Also ability to select - * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag + * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag * is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items) * since any item of the list was selected. * - * Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to + * Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to * manage the list of pick items. * * ASSUMPTIONS AND STUFF @@ -54,392 +54,392 @@ */ class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler { - LOG_CLASS(LLFlatListView); + LOG_CLASS(LLFlatListView); public: - /** - * Abstract comparator for comparing flat list items in a form of LLPanel - */ - class ItemComparator - { - public: - ItemComparator() {}; - virtual ~ItemComparator() {}; - - /** Returns true if item1 < item2, false otherwise */ - virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0; - }; - - /** - * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed - */ - class ItemReverseComparator : public ItemComparator - { - public: - ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {}; - virtual ~ItemReverseComparator() {}; - - virtual bool compare(const LLPanel* item1, const LLPanel* item2) const - { - return mComparator.compare(item2, item1); - } - - private: - const ItemComparator& mComparator; - }; - - - struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params> - { - /** turning on/off selection support */ - Optional<bool> allow_select; - - /** turning on/off multiple selection (works while clicking and holding CTRL)*/ - Optional<bool> multi_select; - - /** don't allow to deselect all selected items (for mouse events on items only) */ - Optional<bool> keep_one_selected; - - /** try to keep selection visible after reshape */ - Optional<bool> keep_selection_visible_on_reshape; - - /** padding between items */ - Optional<U32> item_pad; - - /** textbox with info message when list is empty*/ - Optional<LLTextBox::Params> no_items_text; - - Params(); - }; - - // disable traversal when finding widget to hand focus off to - /*virtual*/ BOOL canFocusChildren() const { return FALSE; } - - /** - * Connects callback to signal called when Return key is pressed. - */ - boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } - - /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - /** Returns full rect of child panel */ - const LLRect& getItemsRect() const; - - LLRect getRequiredRect() { return getItemsRect(); } - - /** Returns distance between items */ - const S32 getItemsPad() { return mItemPad; } - - /** - * Adds and item and LLSD value associated with it to the list at specified position - * @return true if the item was added, false otherwise - */ - virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true); - - /** - * Insert item_to_add along with associated value to the list right after the after_item. - * @return true if the item was successfully added, false otherwise - */ - virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null); - - /** - * Remove specified item - * @return true if the item was removed, false otherwise - */ - virtual bool removeItem(LLPanel* item, bool rearrange = true); - - /** - * Remove an item specified by value - * @return true if the item was removed, false otherwise - */ - virtual bool removeItemByValue(const LLSD& value, bool rearrange = true); - - /** - * Remove an item specified by uuid - * @return true if the item was removed, false otherwise - */ - virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true); - - /** - * Get an item by value - * @return the item as LLPanel if associated with value, NULL otherwise - */ - virtual LLPanel* getItemByValue(const LLSD& value) const; - - template<class T> - T* getTypedItemByValue(const LLSD& value) const - { - return dynamic_cast<T*>(getItemByValue(value)); - } - - /** - * Select or deselect specified item based on select - * @return true if succeed, false otherwise - */ - virtual bool selectItem(LLPanel* item, bool select = true); - - /** - * Select or deselect an item by associated value based on select - * @return true if succeed, false otherwise - */ - virtual bool selectItemByValue(const LLSD& value, bool select = true); - - /** - * Select or deselect an item by associated uuid based on select - * @return true if succeed, false otherwise - */ - virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true); - - /** - * Get all panels stored in the list. - */ - virtual void getItems(std::vector<LLPanel*>& items) const; - - /** - * Get all items values. - */ - virtual void getValues(std::vector<LLSD>& values) const; - - /** - * Get LLSD associated with the first selected item - */ - virtual LLSD getSelectedValue() const; - - /** - * Get LLSD's associated with selected items. - * @param selected_values std::vector being populated with LLSD associated with selected items - */ - virtual void getSelectedValues(std::vector<LLSD>& selected_values) const; - - - /** - * Get LLUUID associated with selected item - * @return LLUUID if such was associated with selected item - */ - virtual LLUUID getSelectedUUID() const; - - /** - * Get LLUUIDs associated with selected items - * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items - */ - virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const; - - /** Get the top selected item */ - virtual LLPanel* getSelectedItem() const; - - /** - * Get selected items - * @param selected_items An std::vector being populated with pointers to selected items - */ - virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const; - - - /** - * Resets selection of items. - * - * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true" - * argument for current Flat List. - * @param no_commit_on_deselection - if true onCommit callback will not be called - */ - virtual void resetSelection(bool no_commit_on_deselection = false); - - /** - * Sets comment text which will be shown in the list is it is empty. - * - * Textbox to hold passed text is created while this method is called at the first time. - * - * @param comment_text - string to be shown as a comment. - */ - void setNoItemsCommentText( const std::string& comment_text); - - /** Turn on/off multiple selection support */ - void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } - - /** Turn on/off selection support */ - void setAllowSelection(bool can_select) { mAllowSelection = can_select; } - - /** Sets flag whether onCommit should be fired if selection was changed */ - // FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly. - void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } - - /** Get number of selected items in the list */ - U32 numSelected() const {return mSelectedItemPairs.size(); } - - /** Get number of (visible) items in the list */ - U32 size(const bool only_visible_items = true) const; - - /** Removes all items from the list */ - virtual void clear(); - - /** - * Removes all items that can be detached from the list but doesn't destroy - * them, caller responsible to manage items after they are detached. - * Detachable item should accept "detach" action via notify() method, - * where it disconnect all callbacks, does other valuable routines and - * return 1. - */ - void detachItems(std::vector<LLPanel*>& detached_items); - - /** - * Set comparator to use for future sorts. - * - * This class does NOT manage lifetime of the comparator - * but assumes that the comparator is always alive. - */ - void setComparator(const ItemComparator* comp) { mItemComparator = comp; } - void sort(); - - bool updateValue(const LLSD& old_value, const LLSD& new_value); - - void scrollToShowFirstSelectedItem(); - - void selectFirstItem (); - void selectLastItem (); - - virtual S32 notify(const LLSD& info) ; - - virtual ~LLFlatListView(); + /** + * Abstract comparator for comparing flat list items in a form of LLPanel + */ + class ItemComparator + { + public: + ItemComparator() {}; + virtual ~ItemComparator() {}; + + /** Returns true if item1 < item2, false otherwise */ + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0; + }; + + /** + * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed + */ + class ItemReverseComparator : public ItemComparator + { + public: + ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {}; + virtual ~ItemReverseComparator() {}; + + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const + { + return mComparator.compare(item2, item1); + } + + private: + const ItemComparator& mComparator; + }; + + + struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params> + { + /** turning on/off selection support */ + Optional<bool> allow_select; + + /** turning on/off multiple selection (works while clicking and holding CTRL)*/ + Optional<bool> multi_select; + + /** don't allow to deselect all selected items (for mouse events on items only) */ + Optional<bool> keep_one_selected; + + /** try to keep selection visible after reshape */ + Optional<bool> keep_selection_visible_on_reshape; + + /** padding between items */ + Optional<U32> item_pad; + + /** textbox with info message when list is empty*/ + Optional<LLTextBox::Params> no_items_text; + + Params(); + }; + + // disable traversal when finding widget to hand focus off to + /*virtual*/ BOOL canFocusChildren() const { return FALSE; } + + /** + * Connects callback to signal called when Return key is pressed. + */ + boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } + + /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + /** Returns full rect of child panel */ + const LLRect& getItemsRect() const; + + LLRect getRequiredRect() { return getItemsRect(); } + + /** Returns distance between items */ + const S32 getItemsPad() { return mItemPad; } + + /** + * Adds and item and LLSD value associated with it to the list at specified position + * @return true if the item was added, false otherwise + */ + virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true); + + /** + * Insert item_to_add along with associated value to the list right after the after_item. + * @return true if the item was successfully added, false otherwise + */ + virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null); + + /** + * Remove specified item + * @return true if the item was removed, false otherwise + */ + virtual bool removeItem(LLPanel* item, bool rearrange = true); + + /** + * Remove an item specified by value + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByValue(const LLSD& value, bool rearrange = true); + + /** + * Remove an item specified by uuid + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true); + + /** + * Get an item by value + * @return the item as LLPanel if associated with value, NULL otherwise + */ + virtual LLPanel* getItemByValue(const LLSD& value) const; + + template<class T> + T* getTypedItemByValue(const LLSD& value) const + { + return dynamic_cast<T*>(getItemByValue(value)); + } + + /** + * Select or deselect specified item based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItem(LLPanel* item, bool select = true); + + /** + * Select or deselect an item by associated value based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByValue(const LLSD& value, bool select = true); + + /** + * Select or deselect an item by associated uuid based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true); + + /** + * Get all panels stored in the list. + */ + virtual void getItems(std::vector<LLPanel*>& items) const; + + /** + * Get all items values. + */ + virtual void getValues(std::vector<LLSD>& values) const; + + /** + * Get LLSD associated with the first selected item + */ + virtual LLSD getSelectedValue() const; + + /** + * Get LLSD's associated with selected items. + * @param selected_values std::vector being populated with LLSD associated with selected items + */ + virtual void getSelectedValues(std::vector<LLSD>& selected_values) const; + + + /** + * Get LLUUID associated with selected item + * @return LLUUID if such was associated with selected item + */ + virtual LLUUID getSelectedUUID() const; + + /** + * Get LLUUIDs associated with selected items + * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items + */ + virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const; + + /** Get the top selected item */ + virtual LLPanel* getSelectedItem() const; + + /** + * Get selected items + * @param selected_items An std::vector being populated with pointers to selected items + */ + virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const; + + + /** + * Resets selection of items. + * + * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true" + * argument for current Flat List. + * @param no_commit_on_deselection - if true onCommit callback will not be called + */ + virtual void resetSelection(bool no_commit_on_deselection = false); + + /** + * Sets comment text which will be shown in the list is it is empty. + * + * Textbox to hold passed text is created while this method is called at the first time. + * + * @param comment_text - string to be shown as a comment. + */ + void setNoItemsCommentText( const std::string& comment_text); + + /** Turn on/off multiple selection support */ + void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } + + /** Turn on/off selection support */ + void setAllowSelection(bool can_select) { mAllowSelection = can_select; } + + /** Sets flag whether onCommit should be fired if selection was changed */ + // FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly. + void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } + + /** Get number of selected items in the list */ + U32 numSelected() const {return mSelectedItemPairs.size(); } + + /** Get number of (visible) items in the list */ + U32 size(const bool only_visible_items = true) const; + + /** Removes all items from the list */ + virtual void clear(); + + /** + * Removes all items that can be detached from the list but doesn't destroy + * them, caller responsible to manage items after they are detached. + * Detachable item should accept "detach" action via notify() method, + * where it disconnect all callbacks, does other valuable routines and + * return 1. + */ + void detachItems(std::vector<LLPanel*>& detached_items); + + /** + * Set comparator to use for future sorts. + * + * This class does NOT manage lifetime of the comparator + * but assumes that the comparator is always alive. + */ + void setComparator(const ItemComparator* comp) { mItemComparator = comp; } + void sort(); + + bool updateValue(const LLSD& old_value, const LLSD& new_value); + + void scrollToShowFirstSelectedItem(); + + void selectFirstItem (); + void selectLastItem (); + + virtual S32 notify(const LLSD& info) ; + + virtual ~LLFlatListView(); protected: - /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ - typedef std::pair<LLPanel*, LLSD> item_pair_t; + /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ + typedef std::pair<LLPanel*, LLSD> item_pair_t; - typedef std::list<item_pair_t*> pairs_list_t; - typedef pairs_list_t::iterator pairs_iterator_t; - typedef pairs_list_t::const_iterator pairs_const_iterator_t; + typedef std::list<item_pair_t*> pairs_list_t; + typedef pairs_list_t::iterator pairs_iterator_t; + typedef pairs_list_t::const_iterator pairs_const_iterator_t; - /** An adapter for a ItemComparator */ - struct ComparatorAdaptor - { - ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {}; + /** An adapter for a ItemComparator */ + struct ComparatorAdaptor + { + ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {}; - bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) - { - return mComparator.compare(item_pair1->first, item_pair2->first); - } + bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) + { + return mComparator.compare(item_pair1->first, item_pair2->first); + } - const ItemComparator& mComparator; - }; + const ItemComparator& mComparator; + }; - friend class LLUICtrlFactory; - LLFlatListView(const LLFlatListView::Params& p); + friend class LLUICtrlFactory; + LLFlatListView(const LLFlatListView::Params& p); - /** Manage selection on mouse events */ - void onItemMouseClick(item_pair_t* item_pair, MASK mask); + /** Manage selection on mouse events */ + void onItemMouseClick(item_pair_t* item_pair, MASK mask); - void onItemRightMouseClick(item_pair_t* item_pair, MASK mask); + void onItemRightMouseClick(item_pair_t* item_pair, MASK mask); - /** - * Updates position of items. - * It does not take into account invisible items. - */ - virtual void rearrangeItems(); + /** + * Updates position of items. + * It does not take into account invisible items. + */ + virtual void rearrangeItems(); - virtual item_pair_t* getItemPair(LLPanel* item) const; + virtual item_pair_t* getItemPair(LLPanel* item) const; - virtual item_pair_t* getItemPair(const LLSD& value) const; + virtual item_pair_t* getItemPair(const LLSD& value) const; - virtual bool selectItemPair(item_pair_t* item_pair, bool select); + virtual bool selectItemPair(item_pair_t* item_pair, bool select); - virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); + virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); - virtual BOOL canSelectAll() const; - virtual void selectAll(); + virtual BOOL canSelectAll() const; + virtual void selectAll(); - virtual bool isSelected(item_pair_t* item_pair) const; + virtual bool isSelected(item_pair_t* item_pair) const; - virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange); + virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange); - bool addItemPairs(pairs_list_t panel_list, bool rearrange = true); + bool addItemPairs(pairs_list_t panel_list, bool rearrange = true); - /** - * Notify parent about changed size of internal controls with "size_changes" action - * - * Size includes Items Rect width and either Items Rect height or comment text height. - * Comment text height is included if comment text is set and visible. - * List border size is also included into notified size. - */ - void notifyParentItemsRectChanged(); + /** + * Notify parent about changed size of internal controls with "size_changes" action + * + * Size includes Items Rect width and either Items Rect height or comment text height. + * Comment text height is included if comment text is set and visible. + * List border size is also included into notified size. + */ + void notifyParentItemsRectChanged(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL postBuild(); + virtual BOOL postBuild(); - virtual void onFocusReceived(); + virtual void onFocusReceived(); - virtual void onFocusLost(); + virtual void onFocusLost(); - virtual void draw(); + virtual void draw(); - LLRect getLastSelectedItemRect(); + LLRect getLastSelectedItemRect(); - void ensureSelectedVisible(); + void ensureSelectedVisible(); - const pairs_list_t& getItemPairs() { return mItemPairs; } + const pairs_list_t& getItemPairs() { return mItemPairs; } private: - void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} + void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} - void setNoItemsCommentVisible(bool visible) const; + void setNoItemsCommentVisible(bool visible) const; protected: - /** Comparator to use when sorting the list. */ - const ItemComparator* mItemComparator; + /** Comparator to use when sorting the list. */ + const ItemComparator* mItemComparator; private: - LLPanel* mItemsPanel; + LLPanel* mItemsPanel; - S32 mItemsNoScrollWidth; + S32 mItemsNoScrollWidth; - S32 mBorderThickness; + S32 mBorderThickness; - /** Items padding */ - S32 mItemPad; + /** Items padding */ + S32 mItemPad; - /** Selection support flag */ - bool mAllowSelection; + /** Selection support flag */ + bool mAllowSelection; - /** Multiselection support flag, ignored if selection is not supported */ - bool mMultipleSelection; + /** Multiselection support flag, ignored if selection is not supported */ + bool mMultipleSelection; - /** - * Flag specified whether onCommit be called if selection is changed in the list. - * - * Can be ignored in the resetSelection() method. - * @see resetSelection() - */ - bool mCommitOnSelectionChange; + /** + * Flag specified whether onCommit be called if selection is changed in the list. + * + * Can be ignored in the resetSelection() method. + * @see resetSelection() + */ + bool mCommitOnSelectionChange; - bool mKeepOneItemSelected; + bool mKeepOneItemSelected; - bool mIsConsecutiveSelection; + bool mIsConsecutiveSelection; - bool mKeepSelectionVisibleOnReshape; + bool mKeepSelectionVisibleOnReshape; - /** All pairs of the list */ - pairs_list_t mItemPairs; + /** All pairs of the list */ + pairs_list_t mItemPairs; - /** Selected pairs for faster access */ - pairs_list_t mSelectedItemPairs; + /** Selected pairs for faster access */ + pairs_list_t mSelectedItemPairs; - /** - * Rectangle contained previous size of items parent notified last time. - * Is used to reduce amount of parentNotify() calls if size was not changed. - */ - LLRect mPrevNotifyParentRect; + /** + * Rectangle contained previous size of items parent notified last time. + * Is used to reduce amount of parentNotify() calls if size was not changed. + */ + LLRect mPrevNotifyParentRect; - LLTextBox* mNoItemsCommentTextbox; + LLTextBox* mNoItemsCommentTextbox; - LLViewBorder* mSelectedItemsBorder; + LLViewBorder* mSelectedItemsBorder; - commit_signal_t mOnReturnSignal; + commit_signal_t mOnReturnSignal; }; /** @@ -457,79 +457,79 @@ private: class LLFlatListViewEx : public LLFlatListView { public: - LOG_CLASS(LLFlatListViewEx); - - struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> - { - /** - * Contains a message for empty list when it does not contain any items at all. - */ - Optional<std::string> no_items_msg; - - /** - * Contains a message for empty list when its items are removed by filtering. - */ - Optional<std::string> no_filtered_items_msg; - Params(); - }; - - // *WORKAROUND: two methods to overload appropriate Params due to localization issue: - // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 - void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } - void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } - - bool getForceShowingUnmatchedItems(); - - void setForceShowingUnmatchedItems(bool show); - - /** - * Sets up new filter string and filters the list. - */ - void setFilterSubString(const std::string& filter_str, bool notify_parent); - std::string getFilterSubString() { return mFilterSubString; } - - /** - * Filters the list, rearranges and notifies parent about shape changes. - * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. - */ - void filterItems(bool re_sort, bool notify_parent); - - /** - * Returns true if last call of filterItems() found at least one matching item - */ - bool hasMatchedItems(); + LOG_CLASS(LLFlatListViewEx); + + struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> + { + /** + * Contains a message for empty list when it does not contain any items at all. + */ + Optional<std::string> no_items_msg; + + /** + * Contains a message for empty list when its items are removed by filtering. + */ + Optional<std::string> no_filtered_items_msg; + Params(); + }; + + // *WORKAROUND: two methods to overload appropriate Params due to localization issue: + // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 + void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } + void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + + bool getForceShowingUnmatchedItems(); + + void setForceShowingUnmatchedItems(bool show); + + /** + * Sets up new filter string and filters the list. + */ + void setFilterSubString(const std::string& filter_str, bool notify_parent); + std::string getFilterSubString() { return mFilterSubString; } + + /** + * Filters the list, rearranges and notifies parent about shape changes. + * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. + */ + void filterItems(bool re_sort, bool notify_parent); + + /** + * Returns true if last call of filterItems() found at least one matching item + */ + bool hasMatchedItems(); protected: - LLFlatListViewEx(const Params& p); - - /** - * Applies a message for empty list depend on passed argument. - * - * @param filter_string - if is not empty, message for filtered items will be set, otherwise for - * completely empty list. Value of filter string will be passed as search_term in SLURL. - */ - void updateNoItemsMessage(const std::string& filter_string); - - /** - * Applies visibility acording to action and LLFlatListView settings. - * - * @param item - item we are changing - * @param item - action - parameters to determin visibility from - */ - bool updateItemVisibility(LLPanel* item, const LLSD &action); + LLFlatListViewEx(const Params& p); + + /** + * Applies a message for empty list depend on passed argument. + * + * @param filter_string - if is not empty, message for filtered items will be set, otherwise for + * completely empty list. Value of filter string will be passed as search_term in SLURL. + */ + void updateNoItemsMessage(const std::string& filter_string); + + /** + * Applies visibility acording to action and LLFlatListView settings. + * + * @param item - item we are changing + * @param item - action - parameters to determin visibility from + */ + bool updateItemVisibility(LLPanel* item, const LLSD &action); private: - std::string mNoFilteredItemsMsg; - std::string mNoItemsMsg; - std::string mFilterSubString; - /** - * Show list items that don't match current filter - */ - bool mForceShowingUnmatchedItems; - /** - * True if last call of filterItems() found at least one matching item - */ - bool mHasMatchedItems; + std::string mNoFilteredItemsMsg; + std::string mNoItemsMsg; + std::string mFilterSubString; + /** + * Show list items that don't match current filter + */ + bool mForceShowingUnmatchedItems; + /** + * True if last call of filterItems() found at least one matching item + */ + bool mHasMatchedItems; }; #endif diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index c7b04c905c..75254f80d8 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloater.cpp * @brief LLFloater base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,7 +44,7 @@ #include "llresizebar.h" #include "llresizehandle.h" #include "llkeyboard.h" -#include "llmenugl.h" // MENU_BAR_HEIGHT +#include "llmenugl.h" // MENU_BAR_HEIGHT #include "llmodaldialog.h" #include "lltextbox.h" #include "llresmgr.h" @@ -70,23 +70,23 @@ const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f; namespace LLInitParam { - void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() - { - declare("relative", LLFloaterEnums::POSITIONING_RELATIVE); - declare("cascading", LLFloaterEnums::POSITIONING_CASCADING); - declare("centered", LLFloaterEnums::POSITIONING_CENTERED); - declare("specified", LLFloaterEnums::POSITIONING_SPECIFIED); - } + void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() + { + declare("relative", LLFloaterEnums::POSITIONING_RELATIVE); + declare("cascading", LLFloaterEnums::POSITIONING_CASCADING); + declare("centered", LLFloaterEnums::POSITIONING_CENTERED); + declare("specified", LLFloaterEnums::POSITIONING_SPECIFIED); + } } -std::string LLFloater::sButtonNames[BUTTON_COUNT] = +std::string LLFloater::sButtonNames[BUTTON_COUNT] = { - "llfloater_close_btn", //BUTTON_CLOSE - "llfloater_restore_btn", //BUTTON_RESTORE - "llfloater_minimize_btn", //BUTTON_MINIMIZE - "llfloater_tear_off_btn", //BUTTON_TEAR_OFF - "llfloater_dock_btn", //BUTTON_DOCK - "llfloater_help_btn" //BUTTON_HELP + "llfloater_close_btn", //BUTTON_CLOSE + "llfloater_restore_btn", //BUTTON_RESTORE + "llfloater_minimize_btn", //BUTTON_MINIMIZE + "llfloater_tear_off_btn", //BUTTON_TEAR_OFF + "llfloater_dock_btn", //BUTTON_DOCK + "llfloater_help_btn" //BUTTON_HELP }; std::string LLFloater::sButtonToolTips[BUTTON_COUNT]; @@ -94,29 +94,29 @@ std::string LLFloater::sButtonToolTips[BUTTON_COUNT]; std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= { #ifdef LL_DARWIN - "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE #else - "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE #endif - "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE - "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE - "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF - "BUTTON_DOCK", - "BUTTON_HELP" + "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE + "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE + "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF + "BUTTON_DOCK", + "BUTTON_HELP" }; LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = { - LLFloater::onClickClose, //BUTTON_CLOSE - LLFloater::onClickMinimize, //BUTTON_RESTORE - LLFloater::onClickMinimize, //BUTTON_MINIMIZE - LLFloater::onClickTearOff, //BUTTON_TEAR_OFF - LLFloater::onClickDock, //BUTTON_DOCK - LLFloater::onClickHelp //BUTTON_HELP + LLFloater::onClickClose, //BUTTON_CLOSE + LLFloater::onClickMinimize, //BUTTON_RESTORE + LLFloater::onClickMinimize, //BUTTON_MINIMIZE + LLFloater::onClickTearOff, //BUTTON_TEAR_OFF + LLFloater::onClickDock, //BUTTON_DOCK + LLFloater::onClickHelp //BUTTON_HELP }; LLMultiFloater* LLFloater::sHostp = NULL; -BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting +BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting LLFloaterView* gFloaterView = NULL; @@ -133,108 +133,108 @@ LLFloaterView* gFloaterView = NULL; //static bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b) { - if (a.type() != b.type()) - { - //LL_ERRS() << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << LL_ENDL; - return false; - } - else if (a.isUndefined()) - return false; - else if (a.isInteger()) - return a.asInteger() < b.asInteger(); - else if (a.isReal()) - return a.asReal() < b.asReal(); - else if (a.isString()) - return a.asString() < b.asString(); - else if (a.isUUID()) - return a.asUUID() < b.asUUID(); - else if (a.isDate()) - return a.asDate() < b.asDate(); - else if (a.isURI()) - return a.asString() < b.asString(); // compare URIs as strings - else if (a.isBoolean()) - return a.asBoolean() < b.asBoolean(); - else - return false; // no valid operation for Binary + if (a.type() != b.type()) + { + //LL_ERRS() << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << LL_ENDL; + return false; + } + else if (a.isUndefined()) + return false; + else if (a.isInteger()) + return a.asInteger() < b.asInteger(); + else if (a.isReal()) + return a.asReal() < b.asReal(); + else if (a.isString()) + return a.asString() < b.asString(); + else if (a.isUUID()) + return a.asUUID() < b.asUUID(); + else if (a.isDate()) + return a.asDate() < b.asDate(); + else if (a.isURI()) + return a.asString() < b.asString(); // compare URIs as strings + else if (a.isBoolean()) + return a.asBoolean() < b.asBoolean(); + else + return false; // no valid operation for Binary } |*==========================================================================*/ bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b) { - return llsd_equals(a, b); + return llsd_equals(a, b); } //************************************ LLFloater::Params::Params() -: title("title"), - short_title("short_title"), - single_instance("single_instance", false), - reuse_instance("reuse_instance", false), - can_resize("can_resize", false), - can_minimize("can_minimize", true), - can_close("can_close", true), - can_drag_on_left("can_drag_on_left", false), - can_tear_off("can_tear_off", true), - save_dock_state("save_dock_state", false), - save_rect("save_rect", false), - save_visibility("save_visibility", false), - can_dock("can_dock", false), - show_title("show_title", true), - auto_close("auto_close", false), - positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE), - header_height("header_height", 0), - legacy_header_height("legacy_header_height", 0), - close_image("close_image"), - restore_image("restore_image"), - minimize_image("minimize_image"), - tear_off_image("tear_off_image"), - dock_image("dock_image"), - help_image("help_image"), - close_pressed_image("close_pressed_image"), - restore_pressed_image("restore_pressed_image"), - minimize_pressed_image("minimize_pressed_image"), - tear_off_pressed_image("tear_off_pressed_image"), - dock_pressed_image("dock_pressed_image"), - help_pressed_image("help_pressed_image"), - open_callback("open_callback"), - close_callback("close_callback"), - follows("follows"), - rel_x("rel_x", 0), - rel_y("rel_y", 0) -{ - changeDefault(visible, false); -} - - -//static +: title("title"), + short_title("short_title"), + single_instance("single_instance", false), + reuse_instance("reuse_instance", false), + can_resize("can_resize", false), + can_minimize("can_minimize", true), + can_close("can_close", true), + can_drag_on_left("can_drag_on_left", false), + can_tear_off("can_tear_off", true), + save_dock_state("save_dock_state", false), + save_rect("save_rect", false), + save_visibility("save_visibility", false), + can_dock("can_dock", false), + show_title("show_title", true), + auto_close("auto_close", false), + positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE), + header_height("header_height", 0), + legacy_header_height("legacy_header_height", 0), + close_image("close_image"), + restore_image("restore_image"), + minimize_image("minimize_image"), + tear_off_image("tear_off_image"), + dock_image("dock_image"), + help_image("help_image"), + close_pressed_image("close_pressed_image"), + restore_pressed_image("restore_pressed_image"), + minimize_pressed_image("minimize_pressed_image"), + tear_off_pressed_image("tear_off_pressed_image"), + dock_pressed_image("dock_pressed_image"), + help_pressed_image("help_pressed_image"), + open_callback("open_callback"), + close_callback("close_callback"), + follows("follows"), + rel_x("rel_x", 0), + rel_y("rel_y", 0) +{ + changeDefault(visible, false); +} + + +//static const LLFloater::Params& LLFloater::getDefaultParams() { - return LLUICtrlFactory::getDefaultParams<LLFloater>(); + return LLUICtrlFactory::getDefaultParams<LLFloater>(); } //static void LLFloater::initClass() { - // translate tooltips for floater buttons - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] ); - } + // translate tooltips for floater buttons + for (S32 i = 0; i < BUTTON_COUNT; i++) + { + sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] ); + } LLControlVariable* ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("ActiveFloaterTransparency").get(); - if (ctrl) - { - ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency)); - updateActiveFloaterTransparency(); - } + if (ctrl) + { + ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency)); + updateActiveFloaterTransparency(); + } ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("InactiveFloaterTransparency").get(); - if (ctrl) - { - ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency)); - updateInactiveFloaterTransparency(); - } + if (ctrl) + { + ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency)); + updateInactiveFloaterTransparency(); + } } @@ -242,142 +242,142 @@ void LLFloater::initClass() static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater"); LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) -: LLPanel(), // intentionally do not pass params here, see initFromParams - mDragHandle(NULL), - mTitle(p.title), - mShortTitle(p.short_title), - mSingleInstance(p.single_instance), - mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default - mKey(key), - mCanTearOff(p.can_tear_off), - mCanMinimize(p.can_minimize), - mCanClose(p.can_close), - mDragOnLeft(p.can_drag_on_left), - mResizable(p.can_resize), - mAutoClose(p.auto_close), - mPositioning(p.positioning), - mMinWidth(p.min_width), - mMinHeight(p.min_height), - mHeaderHeight(p.header_height), - mLegacyHeaderHeight(p.legacy_header_height), - mDefaultRectForGroup(true), - mMinimized(FALSE), - mForeground(FALSE), - mFirstLook(TRUE), - mButtonScale(1.0f), - mAutoFocus(TRUE), // automatically take focus when opened - mCanDock(false), - mDocked(false), - mTornOff(false), - mHasBeenDraggedWhileMinimized(FALSE), - mPreviousMinimizedBottom(0), - mPreviousMinimizedLeft(0), - mDefaultRelativeX(p.rel_x), - mDefaultRelativeY(p.rel_y), - mMinimizeSignal(NULL) -// mNotificationContext(NULL) -{ - mPosition.setFloater(*this); -// mNotificationContext = new LLFloaterNotificationContext(getHandle()); - - // Clicks stop here. - setMouseOpaque(TRUE); - - // Floaters always draw their background, unlike every other panel. - setBackgroundVisible(TRUE); - - // Floaters start not minimized. When minimized, they save their - // prior rectangle to be used on restore. - mExpandedRect.set(0,0,0,0); - - memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool)); - memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*)); - - addDragHandle(); - addResizeCtrls(); - - initFromParams(p); - - initFloater(p); +: LLPanel(), // intentionally do not pass params here, see initFromParams + mDragHandle(NULL), + mTitle(p.title), + mShortTitle(p.short_title), + mSingleInstance(p.single_instance), + mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default + mKey(key), + mCanTearOff(p.can_tear_off), + mCanMinimize(p.can_minimize), + mCanClose(p.can_close), + mDragOnLeft(p.can_drag_on_left), + mResizable(p.can_resize), + mAutoClose(p.auto_close), + mPositioning(p.positioning), + mMinWidth(p.min_width), + mMinHeight(p.min_height), + mHeaderHeight(p.header_height), + mLegacyHeaderHeight(p.legacy_header_height), + mDefaultRectForGroup(true), + mMinimized(FALSE), + mForeground(FALSE), + mFirstLook(TRUE), + mButtonScale(1.0f), + mAutoFocus(TRUE), // automatically take focus when opened + mCanDock(false), + mDocked(false), + mTornOff(false), + mHasBeenDraggedWhileMinimized(FALSE), + mPreviousMinimizedBottom(0), + mPreviousMinimizedLeft(0), + mDefaultRelativeX(p.rel_x), + mDefaultRelativeY(p.rel_y), + mMinimizeSignal(NULL) +// mNotificationContext(NULL) +{ + mPosition.setFloater(*this); +// mNotificationContext = new LLFloaterNotificationContext(getHandle()); + + // Clicks stop here. + setMouseOpaque(TRUE); + + // Floaters always draw their background, unlike every other panel. + setBackgroundVisible(TRUE); + + // Floaters start not minimized. When minimized, they save their + // prior rectangle to be used on restore. + mExpandedRect.set(0,0,0,0); + + memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool)); + memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*)); + + addDragHandle(); + addResizeCtrls(); + + initFromParams(p); + + initFloater(p); } // Note: Floaters constructed from XML call init() twice! void LLFloater::initFloater(const Params& p) { - // Close button. - if (mCanClose) - { - mButtonsEnabled[BUTTON_CLOSE] = TRUE; - } + // Close button. + if (mCanClose) + { + mButtonsEnabled[BUTTON_CLOSE] = TRUE; + } - // Help button: '?' - //SL-14050 Disable all Help question marks - mButtonsEnabled[BUTTON_HELP] = FALSE; - - // Minimize button only for top draggers - if ( !mDragOnLeft && mCanMinimize ) - { - mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; - } + // Help button: '?' + //SL-14050 Disable all Help question marks + mButtonsEnabled[BUTTON_HELP] = FALSE; - if(mCanDock) - { - mButtonsEnabled[BUTTON_DOCK] = TRUE; - } + // Minimize button only for top draggers + if ( !mDragOnLeft && mCanMinimize ) + { + mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; + } - buildButtons(p); + if(mCanDock) + { + mButtonsEnabled[BUTTON_DOCK] = TRUE; + } - // Floaters are created in the invisible state - setVisible(FALSE); + buildButtons(p); - if (!getParent()) - { - gFloaterView->addChild(this); - } + // Floaters are created in the invisible state + setVisible(FALSE); + + if (!getParent()) + { + gFloaterView->addChild(this); + } } void LLFloater::addDragHandle() { - if (!mDragHandle) - { - if (mDragOnLeft) - { - LLDragHandleLeft::Params p; - p.name("drag"); - p.follows.flags(FOLLOWS_ALL); - p.label(mTitle); - mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p); - } - else // drag on top - { - LLDragHandleTop::Params p; - p.name("Drag Handle"); - p.follows.flags(FOLLOWS_ALL); - p.label(mTitle); - mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p); - } - addChild(mDragHandle); - } - layoutDragHandle(); - applyTitle(); + if (!mDragHandle) + { + if (mDragOnLeft) + { + LLDragHandleLeft::Params p; + p.name("drag"); + p.follows.flags(FOLLOWS_ALL); + p.label(mTitle); + mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p); + } + else // drag on top + { + LLDragHandleTop::Params p; + p.name("Drag Handle"); + p.follows.flags(FOLLOWS_ALL); + p.label(mTitle); + mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p); + } + addChild(mDragHandle); + } + layoutDragHandle(); + applyTitle(); } void LLFloater::layoutDragHandle() { - static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); - S32 close_box_size = mCanClose ? floater_close_box_size : 0; - - LLRect rect; - if (mDragOnLeft) - { - rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size); - } - else // drag on top - { - rect = getLocalRect(); - } - mDragHandle->setShape(rect); - updateTitleButtons(); + static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); + S32 close_box_size = mCanClose ? floater_close_box_size : 0; + + LLRect rect; + if (mDragOnLeft) + { + rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size); + } + else // drag on top + { + rect = getLocalRect(); + } + mDragHandle->setShape(rect); + updateTitleButtons(); } // static @@ -395,120 +395,120 @@ void LLFloater::updateInactiveFloaterTransparency() } void LLFloater::addResizeCtrls() -{ - // Resize bars (sides) - LLResizeBar::Params p; - p.name("resizebar_left"); - p.resizing_view(this); - p.min_size(mMinWidth); - p.side(LLResizeBar::LEFT); - mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p); - addChild( mResizeBar[LLResizeBar::LEFT] ); - - p.name("resizebar_top"); - p.min_size(mMinHeight); - p.side(LLResizeBar::TOP); - - mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p); - addChild( mResizeBar[LLResizeBar::TOP] ); - - p.name("resizebar_right"); - p.min_size(mMinWidth); - p.side(LLResizeBar::RIGHT); - mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p); - addChild( mResizeBar[LLResizeBar::RIGHT] ); - - p.name("resizebar_bottom"); - p.min_size(mMinHeight); - p.side(LLResizeBar::BOTTOM); - mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p); - addChild( mResizeBar[LLResizeBar::BOTTOM] ); - - // Resize handles (corners) - LLResizeHandle::Params handle_p; - // handles must not be mouse-opaque, otherwise they block hover events - // to other buttons like the close box. JC - handle_p.mouse_opaque(false); - handle_p.min_width(mMinWidth); - handle_p.min_height(mMinHeight); - handle_p.corner(LLResizeHandle::RIGHT_BOTTOM); - mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); - addChild(mResizeHandle[0]); - - handle_p.corner(LLResizeHandle::RIGHT_TOP); - mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); - addChild(mResizeHandle[1]); - - handle_p.corner(LLResizeHandle::LEFT_BOTTOM); - mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); - addChild(mResizeHandle[2]); - - handle_p.corner(LLResizeHandle::LEFT_TOP); - mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); - addChild(mResizeHandle[3]); - - layoutResizeCtrls(); +{ + // Resize bars (sides) + LLResizeBar::Params p; + p.name("resizebar_left"); + p.resizing_view(this); + p.min_size(mMinWidth); + p.side(LLResizeBar::LEFT); + mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p); + addChild( mResizeBar[LLResizeBar::LEFT] ); + + p.name("resizebar_top"); + p.min_size(mMinHeight); + p.side(LLResizeBar::TOP); + + mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p); + addChild( mResizeBar[LLResizeBar::TOP] ); + + p.name("resizebar_right"); + p.min_size(mMinWidth); + p.side(LLResizeBar::RIGHT); + mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p); + addChild( mResizeBar[LLResizeBar::RIGHT] ); + + p.name("resizebar_bottom"); + p.min_size(mMinHeight); + p.side(LLResizeBar::BOTTOM); + mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p); + addChild( mResizeBar[LLResizeBar::BOTTOM] ); + + // Resize handles (corners) + LLResizeHandle::Params handle_p; + // handles must not be mouse-opaque, otherwise they block hover events + // to other buttons like the close box. JC + handle_p.mouse_opaque(false); + handle_p.min_width(mMinWidth); + handle_p.min_height(mMinHeight); + handle_p.corner(LLResizeHandle::RIGHT_BOTTOM); + mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); + addChild(mResizeHandle[0]); + + handle_p.corner(LLResizeHandle::RIGHT_TOP); + mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); + addChild(mResizeHandle[1]); + + handle_p.corner(LLResizeHandle::LEFT_BOTTOM); + mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); + addChild(mResizeHandle[2]); + + handle_p.corner(LLResizeHandle::LEFT_TOP); + mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p); + addChild(mResizeHandle[3]); + + layoutResizeCtrls(); } void LLFloater::layoutResizeCtrls() { - LLRect rect; + LLRect rect; - // Resize bars (sides) - const S32 RESIZE_BAR_THICKNESS = 3; - rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0); - mResizeBar[LLResizeBar::LEFT]->setRect(rect); + // Resize bars (sides) + const S32 RESIZE_BAR_THICKNESS = 3; + rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0); + mResizeBar[LLResizeBar::LEFT]->setRect(rect); - rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS); - mResizeBar[LLResizeBar::TOP]->setRect(rect); + rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS); + mResizeBar[LLResizeBar::TOP]->setRect(rect); - rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0); - mResizeBar[LLResizeBar::RIGHT]->setRect(rect); + rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0); + mResizeBar[LLResizeBar::RIGHT]->setRect(rect); - rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0); - mResizeBar[LLResizeBar::BOTTOM]->setRect(rect); + rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0); + mResizeBar[LLResizeBar::BOTTOM]->setRect(rect); - // Resize handles (corners) - rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0); - mResizeHandle[0]->setRect(rect); + // Resize handles (corners) + rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0); + mResizeHandle[0]->setRect(rect); - rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT); - mResizeHandle[1]->setRect(rect); - - rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ); - mResizeHandle[2]->setRect(rect); + rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT); + mResizeHandle[1]->setRect(rect); - rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ); - mResizeHandle[3]->setRect(rect); + rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ); + mResizeHandle[2]->setRect(rect); + + rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ); + mResizeHandle[3]->setRect(rect); } void LLFloater::enableResizeCtrls(bool enable, bool width, bool height) { - mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width); - mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width); + mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width); + mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width); + + mResizeBar[LLResizeBar::TOP]->setVisible(enable && height); + mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height); - mResizeBar[LLResizeBar::TOP]->setVisible(enable && height); - mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height); - - mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width); - mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width); - - mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height); - mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height); + mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width); + mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width); - for (S32 i = 0; i < 4; ++i) - { - mResizeHandle[i]->setVisible(enable && width && height); - mResizeHandle[i]->setEnabled(enable && width && height); - } + mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height); + mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height); + + for (S32 i = 0; i < 4; ++i) + { + mResizeHandle[i]->setVisible(enable && width && height); + mResizeHandle[i]->setEnabled(enable && width && height); + } } void LLFloater::destroy() { - // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before - // it was deleted via LLMortician::updateClass(). See EXT-8458. - LLFloaterReg::removeInstance(mInstanceName, mKey); - die(); + // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before + // it was deleted via LLMortician::updateClass(). See EXT-8458. + LLFloaterReg::removeInstance(mInstanceName, mKey); + die(); } // virtual @@ -520,250 +520,250 @@ LLFloater::~LLFloater() // in case of single instance we can remove new one by accident LLFloaterReg::removeInstance(mInstanceName, mKey); } - - if( gFocusMgr.childHasKeyboardFocus(this)) - { - // Just in case we might still have focus here, release it. - releaseFocus(); - } - // This is important so that floaters with persistent rects (i.e., those - // created with rect control rather than an LLRect) are restored in their - // correct, non-minimized positions. - setMinimized( FALSE ); + if( gFocusMgr.childHasKeyboardFocus(this)) + { + // Just in case we might still have focus here, release it. + releaseFocus(); + } - delete mDragHandle; - for (S32 i = 0; i < 4; i++) - { - delete mResizeBar[i]; - delete mResizeHandle[i]; - } + // This is important so that floaters with persistent rects (i.e., those + // created with rect control rather than an LLRect) are restored in their + // correct, non-minimized positions. + setMinimized( FALSE ); + + delete mDragHandle; + for (S32 i = 0; i < 4; i++) + { + delete mResizeBar[i]; + delete mResizeHandle[i]; + } - setVisible(false); // We're not visible if we're destroyed - storeVisibilityControl(); - storeDockStateControl(); - delete mMinimizeSignal; + setVisible(false); // We're not visible if we're destroyed + storeVisibilityControl(); + storeDockStateControl(); + delete mMinimizeSignal; } void LLFloater::storeRectControl() { - if (!mRectControl.empty()) - { - getControlGroup()->setRect( mRectControl, getRect() ); - } - if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) - { - getControlGroup()->setF32( mPosXControl, mPosition.mX ); - } - if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) - { - getControlGroup()->setF32( mPosYControl, mPosition.mY ); - } + if (!mRectControl.empty()) + { + getControlGroup()->setRect( mRectControl, getRect() ); + } + if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) + { + getControlGroup()->setF32( mPosXControl, mPosition.mX ); + } + if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE) + { + getControlGroup()->setF32( mPosYControl, mPosition.mY ); + } } void LLFloater::storeVisibilityControl() { - if( !sQuitting && mVisibilityControl.size() > 1 ) - { - getControlGroup()->setBOOL( mVisibilityControl, getVisible() ); - } + if( !sQuitting && mVisibilityControl.size() > 1 ) + { + getControlGroup()->setBOOL( mVisibilityControl, getVisible() ); + } } void LLFloater::storeDockStateControl() { - if( !sQuitting && mDocStateControl.size() > 1 ) - { - getControlGroup()->setBOOL( mDocStateControl, isDocked() ); - } + if( !sQuitting && mDocStateControl.size() > 1 ) + { + getControlGroup()->setBOOL( mDocStateControl, isDocked() ); + } } // static std::string LLFloater::getControlName(const std::string& name, const LLSD& key) { - std::string ctrl_name = name; + std::string ctrl_name = name; - // Add the key to the control name if appropriate. - if (key.isString() && !key.asString().empty()) - { - ctrl_name += "_" + key.asString(); - } + // Add the key to the control name if appropriate. + if (key.isString() && !key.asString().empty()) + { + ctrl_name += "_" + key.asString(); + } - return ctrl_name; + return ctrl_name; } // static -LLControlGroup* LLFloater::getControlGroup() +LLControlGroup* LLFloater::getControlGroup() { - // Floater size, position, visibility, etc are saved in per-account settings. - return LLUI::getInstance()->mSettingGroups["account"]; + // Floater size, position, visibility, etc are saved in per-account settings. + return LLUI::getInstance()->mSettingGroups["account"]; } void LLFloater::setVisible( BOOL visible ) { - LLPanel::setVisible(visible); // calls onVisibilityChange() - if( visible && mFirstLook ) - { - mFirstLook = FALSE; - } + LLPanel::setVisible(visible); // calls onVisibilityChange() + if( visible && mFirstLook ) + { + mFirstLook = FALSE; + } - if( !visible ) - { - LLUI::getInstance()->removePopup(this); + if( !visible ) + { + LLUI::getInstance()->removePopup(this); - if( gFocusMgr.childHasMouseCapture( this ) ) - { - gFocusMgr.setMouseCapture(NULL); - } - } + if( gFocusMgr.childHasMouseCapture( this ) ) + { + gFocusMgr.setMouseCapture(NULL); + } + } - for(handle_set_iter_t dependent_it = mDependents.begin(); - dependent_it != mDependents.end(); ) - { - LLFloater* floaterp = dependent_it->get(); + for(handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); ) + { + LLFloater* floaterp = dependent_it->get(); - if (floaterp) - { - floaterp->setVisible(visible); - } - ++dependent_it; - } + if (floaterp) + { + floaterp->setVisible(visible); + } + ++dependent_it; + } - storeVisibilityControl(); + storeVisibilityControl(); } void LLFloater::setIsSingleInstance(BOOL is_single_instance) { - mSingleInstance = is_single_instance; - if (!mIsReuseInitialized) - { - mReuseInstance = is_single_instance; // reuse single-instance floaters by default - } + mSingleInstance = is_single_instance; + if (!mIsReuseInitialized) + { + mReuseInstance = is_single_instance; // reuse single-instance floaters by default + } } // virtual void LLFloater::onVisibilityChange ( BOOL new_visibility ) { - if (new_visibility) - { - if (getHost()) - getHost()->setFloaterFlashing(this, FALSE); - } - LLPanel::onVisibilityChange ( new_visibility ); + if (new_visibility) + { + if (getHost()) + getHost()->setFloaterFlashing(this, FALSE); + } + LLPanel::onVisibilityChange ( new_visibility ); } void LLFloater::openFloater(const LLSD& key) { LL_INFOS() << "Opening floater " << getName() << " full path: " << getPathname() << LL_ENDL; - LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string - - mKey = key; // in case we need to open ourselves again - - if (getSoundFlags() != SILENT - // don't play open sound for hosted (tabbed) windows - && !getHost() - && !getFloaterHost() - && (!getVisible() || isMinimized())) - { - make_ui_sound("UISndWindowOpen"); - } - - //RN: for now, we don't allow rehosting from one multifloater to another - // just need to fix the bugs - if (getFloaterHost() != NULL && getHost() == NULL) - { - // needs a host - // only select tabs if window they are hosted in is visible - getFloaterHost()->addFloater(this, getFloaterHost()->getVisible()); - } - - if (getHost() != NULL) - { - getHost()->setMinimized(FALSE); - getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); - getHost()->showFloater(this); - } - else - { - LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName); - if (!floater_to_stack) - { - floater_to_stack = LLFloaterReg::getLastFloaterCascading(); - } - applyControlsAndPosition(floater_to_stack); - setMinimized(FALSE); - setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); - } - - mOpenSignal(this, key); - onOpen(key); - - dirtyRect(); + LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string + + mKey = key; // in case we need to open ourselves again + + if (getSoundFlags() != SILENT + // don't play open sound for hosted (tabbed) windows + && !getHost() + && !getFloaterHost() + && (!getVisible() || isMinimized())) + { + make_ui_sound("UISndWindowOpen"); + } + + //RN: for now, we don't allow rehosting from one multifloater to another + // just need to fix the bugs + if (getFloaterHost() != NULL && getHost() == NULL) + { + // needs a host + // only select tabs if window they are hosted in is visible + getFloaterHost()->addFloater(this, getFloaterHost()->getVisible()); + } + + if (getHost() != NULL) + { + getHost()->setMinimized(FALSE); + getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); + getHost()->showFloater(this); + } + else + { + LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName); + if (!floater_to_stack) + { + floater_to_stack = LLFloaterReg::getLastFloaterCascading(); + } + applyControlsAndPosition(floater_to_stack); + setMinimized(FALSE); + setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); + } + + mOpenSignal(this, key); + onOpen(key); + + dirtyRect(); } void LLFloater::closeFloater(bool app_quitting) { - LL_INFOS() << "Closing floater " << getName() << LL_ENDL; - LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string - if (app_quitting) - { - LLFloater::sQuitting = true; - } - - // Always unminimize before trying to close. - // Most of the time the user will never see this state. - setMinimized(FALSE); - - if (canClose()) - { - if (getHost()) - { - ((LLMultiFloater*)getHost())->removeFloater(this); - gFloaterView->addChild(this); - } - - if (getSoundFlags() != SILENT - && getVisible() - && !getHost() - && !app_quitting) - { - make_ui_sound("UISndWindowClose"); - } - - gFocusMgr.clearLastFocusForGroup(this); - - if (hasFocus()) - { - // Do this early, so UI controls will commit before the - // window is taken down. - releaseFocus(); - - // give focus to dependee floater if it exists, and we had focus first - if (isDependent()) - { - LLFloater* dependee = mDependeeHandle.get(); - if (dependee && !dependee->isDead()) - { - dependee->setFocus(TRUE); - } - } - } - - - //If floater is a dependent, remove it from parent (dependee) + LL_INFOS() << "Closing floater " << getName() << LL_ENDL; + LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string + if (app_quitting) + { + LLFloater::sQuitting = true; + } + + // Always unminimize before trying to close. + // Most of the time the user will never see this state. + setMinimized(FALSE); + + if (canClose()) + { + if (getHost()) + { + ((LLMultiFloater*)getHost())->removeFloater(this); + gFloaterView->addChild(this); + } + + if (getSoundFlags() != SILENT + && getVisible() + && !getHost() + && !app_quitting) + { + make_ui_sound("UISndWindowClose"); + } + + gFocusMgr.clearLastFocusForGroup(this); + + if (hasFocus()) + { + // Do this early, so UI controls will commit before the + // window is taken down. + releaseFocus(); + + // give focus to dependee floater if it exists, and we had focus first + if (isDependent()) + { + LLFloater* dependee = mDependeeHandle.get(); + if (dependee && !dependee->isDead()) + { + dependee->setFocus(TRUE); + } + } + } + + + //If floater is a dependent, remove it from parent (dependee) LLFloater* dependee = mDependeeHandle.get(); if (dependee) { dependee->removeDependentFloater(this); } - // now close dependent floater - while(mDependents.size() > 0) - { + // now close dependent floater + while(mDependents.size() > 0) + { handle_set_iter_t dependent_it = mDependents.begin(); - LLFloater* floaterp = dependent_it->get(); + LLFloater* floaterp = dependent_it->get(); // normally removeDependentFloater will do this, but in // case floaterp is somehow invalid or orphaned, erase now mDependents.erase(dependent_it); @@ -772,62 +772,62 @@ void LLFloater::closeFloater(bool app_quitting) floaterp->mDependeeHandle = LLHandle<LLFloater>(); floaterp->closeFloater(app_quitting); } - } - - cleanupHandles(); - - dirtyRect(); - - // Close callbacks - onClose(app_quitting); - mCloseSignal(this, LLSD(app_quitting)); - - // Hide or Destroy - if (mSingleInstance) - { - // Hide the instance - if (getHost()) - { - getHost()->setVisible(FALSE); - } - else - { - setVisible(FALSE); - if (!mReuseInstance) - { - destroy(); - } - } - } - else - { - setVisible(FALSE); // hide before destroying (so onVisibilityChange() gets called) - if (!mReuseInstance) - { - destroy(); - } - } - } + } + + cleanupHandles(); + + dirtyRect(); + + // Close callbacks + onClose(app_quitting); + mCloseSignal(this, LLSD(app_quitting)); + + // Hide or Destroy + if (mSingleInstance) + { + // Hide the instance + if (getHost()) + { + getHost()->setVisible(FALSE); + } + else + { + setVisible(FALSE); + if (!mReuseInstance) + { + destroy(); + } + } + } + else + { + setVisible(FALSE); // hide before destroying (so onVisibilityChange() gets called) + if (!mReuseInstance) + { + destroy(); + } + } + } } /*virtual*/ void LLFloater::closeHostedFloater() { - // When toggling *visibility*, close the host instead of the floater when hosted - if (getHost()) - { - getHost()->closeFloater(); - } - else - { - closeFloater(); - } + // When toggling *visibility*, close the host instead of the floater when hosted + if (getHost()) + { + getHost()->closeFloater(); + } + else + { + closeFloater(); + } } /*virtual*/ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLPanel::reshape(width, height, called_from_parent); + LLPanel::reshape(width, height, called_from_parent); } // virtual @@ -850,725 +850,725 @@ void LLFloater::translate(S32 x, S32 y) void LLFloater::releaseFocus() { - LLUI::getInstance()->removePopup(this); + LLUI::getInstance()->removePopup(this); - setFocus(FALSE); + setFocus(FALSE); - if( gFocusMgr.childHasMouseCapture( this ) ) - { - gFocusMgr.setMouseCapture(NULL); - } + if( gFocusMgr.childHasMouseCapture( this ) ) + { + gFocusMgr.setMouseCapture(NULL); + } } void LLFloater::setResizeLimits( S32 min_width, S32 min_height ) { - mMinWidth = min_width; - mMinHeight = min_height; - - for( S32 i = 0; i < 4; i++ ) - { - if( mResizeBar[i] ) - { - if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT) - { - mResizeBar[i]->setResizeLimits( min_width, S32_MAX ); - } - else - { - mResizeBar[i]->setResizeLimits( min_height, S32_MAX ); - } - } - if( mResizeHandle[i] ) - { - mResizeHandle[i]->setResizeLimits( min_width, min_height ); - } - } + mMinWidth = min_width; + mMinHeight = min_height; + + for( S32 i = 0; i < 4; i++ ) + { + if( mResizeBar[i] ) + { + if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT) + { + mResizeBar[i]->setResizeLimits( min_width, S32_MAX ); + } + else + { + mResizeBar[i]->setResizeLimits( min_height, S32_MAX ); + } + } + if( mResizeHandle[i] ) + { + mResizeHandle[i]->setResizeLimits( min_width, min_height ); + } + } } void LLFloater::center() { - if(getHost()) - { - // hosted floaters can't move - return; - } - centerWithin(gFloaterView->getRect()); + if(getHost()) + { + // hosted floaters can't move + return; + } + centerWithin(gFloaterView->getRect()); } LLMultiFloater* LLFloater::getHost() -{ - return (LLMultiFloater*)mHostHandle.get(); +{ + return (LLMultiFloater*)mHostHandle.get(); } void LLFloater::applyControlsAndPosition(LLFloater* other) { - if (!applyDockState()) - { - if (!applyRectControl()) - { - applyPositioning(other, true); - } - } + if (!applyDockState()) + { + if (!applyRectControl()) + { + applyPositioning(other, true); + } + } } bool LLFloater::applyRectControl() { - bool saved_rect = false; - - LLRect screen_rect = calcScreenRect(); - mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); - - LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName); - if (last_in_group && last_in_group != this) - { - // other floaters in our group, position ourselves relative to them and don't save the rect - if (mDefaultRectForGroup) - { - mRectControl.clear(); - } - mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; - } - else - { - bool rect_specified = false; - if (!mRectControl.empty()) - { - // If we have a saved rect, use it - const LLRect& rect = getControlGroup()->getRect(mRectControl); - if (rect.notEmpty()) saved_rect = true; - if (saved_rect) - { - setOrigin(rect.mLeft, rect.mBottom); - - if (mResizable) - { - reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); - } - mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; - LLRect screen_rect = calcScreenRect(); - mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); - rect_specified = true; - } - } - - LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl); - LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl); - if (x_control.notNull() - && y_control.notNull() - && !x_control->isDefault() - && !y_control->isDefault()) - { - mPosition.mX = x_control->getValue().asReal(); - mPosition.mY = y_control->getValue().asReal(); - mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; - applyRelativePosition(); - - saved_rect = true; - } - else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0)) - { - mPosition.mX = mDefaultRelativeX; - mPosition.mY = mDefaultRelativeY; - mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; - applyRelativePosition(); - - saved_rect = true; - } - - // remember updated position - if (rect_specified) - { - storeRectControl(); - } - } - - if (saved_rect) - { - // propagate any derived positioning data back to settings file - storeRectControl(); - } - - - return saved_rect; + bool saved_rect = false; + + LLRect screen_rect = calcScreenRect(); + mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); + + LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName); + if (last_in_group && last_in_group != this) + { + // other floaters in our group, position ourselves relative to them and don't save the rect + if (mDefaultRectForGroup) + { + mRectControl.clear(); + } + mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; + } + else + { + bool rect_specified = false; + if (!mRectControl.empty()) + { + // If we have a saved rect, use it + const LLRect& rect = getControlGroup()->getRect(mRectControl); + if (rect.notEmpty()) saved_rect = true; + if (saved_rect) + { + setOrigin(rect.mLeft, rect.mBottom); + + if (mResizable) + { + reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + } + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + LLRect screen_rect = calcScreenRect(); + mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); + rect_specified = true; + } + } + + LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl); + LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl); + if (x_control.notNull() + && y_control.notNull() + && !x_control->isDefault() + && !y_control->isDefault()) + { + mPosition.mX = x_control->getValue().asReal(); + mPosition.mY = y_control->getValue().asReal(); + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + applyRelativePosition(); + + saved_rect = true; + } + else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0)) + { + mPosition.mX = mDefaultRelativeX; + mPosition.mY = mDefaultRelativeY; + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + applyRelativePosition(); + + saved_rect = true; + } + + // remember updated position + if (rect_specified) + { + storeRectControl(); + } + } + + if (saved_rect) + { + // propagate any derived positioning data back to settings file + storeRectControl(); + } + + + return saved_rect; } bool LLFloater::applyDockState() { - bool docked = false; + bool docked = false; - if (mDocStateControl.size() > 1) - { - docked = getControlGroup()->getBOOL(mDocStateControl); - setDocked(docked); - } + if (mDocStateControl.size() > 1) + { + docked = getControlGroup()->getBOOL(mDocStateControl); + setDocked(docked); + } - return docked; + return docked; } void LLFloater::applyPositioning(LLFloater* other, bool on_open) { - // Otherwise position according to the positioning code - switch (mPositioning) - { - case LLFloaterEnums::POSITIONING_CENTERED: - center(); - break; - - case LLFloaterEnums::POSITIONING_SPECIFIED: - break; - - case LLFloaterEnums::POSITIONING_CASCADING: - if (!on_open) - { - applyRelativePosition(); - } - // fall through - case LLFloaterEnums::POSITIONING_CASCADE_GROUP: - if (on_open) - { - if (other != NULL && other != this) - { - stackWith(*other); - } - else - { - static const U32 CASCADING_FLOATER_HOFFSET = 0; - static const U32 CASCADING_FLOATER_VOFFSET = 0; - - const LLRect& snap_rect = gFloaterView->getSnapRect(); - - const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET; - const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET; - - S32 rect_height = getRect().getHeight(); - setOrigin(horizontal_offset, vertical_offset - rect_height); - - translate(snap_rect.mLeft, snap_rect.mBottom); - } - setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); - } - break; - - case LLFloaterEnums::POSITIONING_RELATIVE: - { - applyRelativePosition(); - - break; - } - default: - // Do nothing - break; - } + // Otherwise position according to the positioning code + switch (mPositioning) + { + case LLFloaterEnums::POSITIONING_CENTERED: + center(); + break; + + case LLFloaterEnums::POSITIONING_SPECIFIED: + break; + + case LLFloaterEnums::POSITIONING_CASCADING: + if (!on_open) + { + applyRelativePosition(); + } + // fall through + case LLFloaterEnums::POSITIONING_CASCADE_GROUP: + if (on_open) + { + if (other != NULL && other != this) + { + stackWith(*other); + } + else + { + static const U32 CASCADING_FLOATER_HOFFSET = 0; + static const U32 CASCADING_FLOATER_VOFFSET = 0; + + const LLRect& snap_rect = gFloaterView->getSnapRect(); + + const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET; + const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET; + + S32 rect_height = getRect().getHeight(); + setOrigin(horizontal_offset, vertical_offset - rect_height); + + translate(snap_rect.mLeft, snap_rect.mBottom); + } + setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); + } + break; + + case LLFloaterEnums::POSITIONING_RELATIVE: + { + applyRelativePosition(); + + break; + } + default: + // Do nothing + break; + } } void LLFloater::applyTitle() { - if (!mDragHandle) - { - return; - } + if (!mDragHandle) + { + return; + } - if (isMinimized() && !mShortTitle.empty()) - { - mDragHandle->setTitle( mShortTitle ); - } - else - { - mDragHandle->setTitle ( mTitle ); - } + if (isMinimized() && !mShortTitle.empty()) + { + mDragHandle->setTitle( mShortTitle ); + } + else + { + mDragHandle->setTitle ( mTitle ); + } - if (getHost()) - { - getHost()->updateFloaterTitle(this); - } + if (getHost()) + { + getHost()->updateFloaterTitle(this); + } } std::string LLFloater::getCurrentTitle() const { - return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; + return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; } void LLFloater::setTitle( const std::string& title ) { - mTitle = title; - applyTitle(); + mTitle = title; + applyTitle(); } std::string LLFloater::getTitle() const { - if (mTitle.empty()) - { - return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; - } - else - { - return mTitle; - } + if (mTitle.empty()) + { + return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; + } + else + { + return mTitle; + } } void LLFloater::setShortTitle( const std::string& short_title ) { - mShortTitle = short_title; - applyTitle(); + mShortTitle = short_title; + applyTitle(); } std::string LLFloater::getShortTitle() const { - if (mShortTitle.empty()) - { - return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; - } - else - { - return mShortTitle; - } + if (mShortTitle.empty()) + { + return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null; + } + else + { + return mShortTitle; + } } BOOL LLFloater::canSnapTo(const LLView* other_view) { - if (NULL == other_view) - { - LL_WARNS() << "other_view is NULL" << LL_ENDL; - return FALSE; - } + if (NULL == other_view) + { + LL_WARNS() << "other_view is NULL" << LL_ENDL; + return FALSE; + } - if (other_view != getParent()) - { - const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view); - if (other_floaterp - && other_floaterp->getSnapTarget() == getHandle() - && mDependents.find(other_floaterp->getHandle()) != mDependents.end()) - { - // this is a dependent that is already snapped to us, so don't snap back to it - return FALSE; - } - } + if (other_view != getParent()) + { + const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view); + if (other_floaterp + && other_floaterp->getSnapTarget() == getHandle() + && mDependents.find(other_floaterp->getHandle()) != mDependents.end()) + { + // this is a dependent that is already snapped to us, so don't snap back to it + return FALSE; + } + } - return LLPanel::canSnapTo(other_view); + return LLPanel::canSnapTo(other_view); } void LLFloater::setSnappedTo(const LLView* snap_view) { - if (!snap_view || snap_view == getParent()) - { - clearSnapTarget(); - } - else - { - //RN: assume it's a floater as it must be a sibling to our parent floater - const LLFloater* floaterp = dynamic_cast<const LLFloater*>(snap_view); - if (floaterp) - { - setSnapTarget(floaterp->getHandle()); - } - } + if (!snap_view || snap_view == getParent()) + { + clearSnapTarget(); + } + else + { + //RN: assume it's a floater as it must be a sibling to our parent floater + const LLFloater* floaterp = dynamic_cast<const LLFloater*>(snap_view); + if (floaterp) + { + setSnapTarget(floaterp->getHandle()); + } + } } void LLFloater::handleReshape(const LLRect& new_rect, bool by_user) { - const LLRect old_rect = getRect(); - LLView::handleReshape(new_rect, by_user); - - if (by_user && !getHost()) - { - LLFloaterView * floaterVp = dynamic_cast<LLFloaterView*>(getParent()); - if (floaterVp) - { - floaterVp->adjustToFitScreen(this, !isMinimized()); - } - } - - // if not minimized, adjust all snapped dependents to new shape - if (!isMinimized()) - { - if (by_user) - { - if (isDocked()) - { - setDocked( false, false); - } - mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; - LLRect screen_rect = calcScreenRect(); - mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); - } - storeRectControl(); - - // gather all snapped dependents - for(handle_set_iter_t dependent_it = mDependents.begin(); - dependent_it != mDependents.end(); ++dependent_it) - { - LLFloater* floaterp = dependent_it->get(); - // is a dependent snapped to us? - if (floaterp && floaterp->getSnapTarget() == getHandle()) - { - S32 delta_x = 0; - S32 delta_y = 0; - // check to see if it snapped to right or top, and move if dependee floater is resizing - LLRect dependent_rect = floaterp->getRect(); - if (dependent_rect.mLeft - getRect().mLeft >= old_rect.getWidth() || // dependent on my right? - dependent_rect.mRight == getRect().mLeft + old_rect.getWidth()) // dependent aligned with my right - { - // was snapped directly onto right side or aligned with it - delta_x += new_rect.getWidth() - old_rect.getWidth(); - } - if (dependent_rect.mBottom - getRect().mBottom >= old_rect.getHeight() || - dependent_rect.mTop == getRect().mBottom + old_rect.getHeight()) - { - // was snapped directly onto top side or aligned with it - delta_y += new_rect.getHeight() - old_rect.getHeight(); - } - - // take translation of dependee floater into account as well - delta_x += new_rect.mLeft - old_rect.mLeft; - delta_y += new_rect.mBottom - old_rect.mBottom; - - dependent_rect.translate(delta_x, delta_y); - floaterp->setShape(dependent_rect, by_user); - } - } - } - else - { - // If minimized, and origin has changed, set - // mHasBeenDraggedWhileMinimized to TRUE - if ((new_rect.mLeft != old_rect.mLeft) || - (new_rect.mBottom != old_rect.mBottom)) - { - mHasBeenDraggedWhileMinimized = TRUE; - } - } + const LLRect old_rect = getRect(); + LLView::handleReshape(new_rect, by_user); + + if (by_user && !getHost()) + { + LLFloaterView * floaterVp = dynamic_cast<LLFloaterView*>(getParent()); + if (floaterVp) + { + floaterVp->adjustToFitScreen(this, !isMinimized()); + } + } + + // if not minimized, adjust all snapped dependents to new shape + if (!isMinimized()) + { + if (by_user) + { + if (isDocked()) + { + setDocked( false, false); + } + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + LLRect screen_rect = calcScreenRect(); + mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); + } + storeRectControl(); + + // gather all snapped dependents + for(handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); ++dependent_it) + { + LLFloater* floaterp = dependent_it->get(); + // is a dependent snapped to us? + if (floaterp && floaterp->getSnapTarget() == getHandle()) + { + S32 delta_x = 0; + S32 delta_y = 0; + // check to see if it snapped to right or top, and move if dependee floater is resizing + LLRect dependent_rect = floaterp->getRect(); + if (dependent_rect.mLeft - getRect().mLeft >= old_rect.getWidth() || // dependent on my right? + dependent_rect.mRight == getRect().mLeft + old_rect.getWidth()) // dependent aligned with my right + { + // was snapped directly onto right side or aligned with it + delta_x += new_rect.getWidth() - old_rect.getWidth(); + } + if (dependent_rect.mBottom - getRect().mBottom >= old_rect.getHeight() || + dependent_rect.mTop == getRect().mBottom + old_rect.getHeight()) + { + // was snapped directly onto top side or aligned with it + delta_y += new_rect.getHeight() - old_rect.getHeight(); + } + + // take translation of dependee floater into account as well + delta_x += new_rect.mLeft - old_rect.mLeft; + delta_y += new_rect.mBottom - old_rect.mBottom; + + dependent_rect.translate(delta_x, delta_y); + floaterp->setShape(dependent_rect, by_user); + } + } + } + else + { + // If minimized, and origin has changed, set + // mHasBeenDraggedWhileMinimized to TRUE + if ((new_rect.mLeft != old_rect.mLeft) || + (new_rect.mBottom != old_rect.mBottom)) + { + mHasBeenDraggedWhileMinimized = TRUE; + } + } } void LLFloater::setMinimized(BOOL minimize) { - const LLFloater::Params& default_params = LLFloater::getDefaultParams(); - S32 floater_header_size = default_params.header_height; - static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0); - - if (minimize == mMinimized) return; - - if (mMinimizeSignal) - { - (*mMinimizeSignal)(this, LLSD(minimize)); - } - - if (minimize) - { - // minimized flag should be turned on before release focus - mMinimized = TRUE; - mExpandedRect = getRect(); - - // If the floater has been dragged while minimized in the - // past, then locate it at its previous minimized location. - // Otherwise, ask the view for a minimize position. - if (mHasBeenDraggedWhileMinimized) - { - setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom); - } - else - { - S32 left, bottom; - gFloaterView->getMinimizePosition(&left, &bottom); - setOrigin( left, bottom ); - } - - if (mButtonsEnabled[BUTTON_MINIMIZE]) - { - mButtonsEnabled[BUTTON_MINIMIZE] = FALSE; - mButtonsEnabled[BUTTON_RESTORE] = TRUE; - } - - setBorderVisible(TRUE); - - for(handle_set_iter_t dependent_it = mDependents.begin(); - dependent_it != mDependents.end(); - ++dependent_it) - { - LLFloater* floaterp = dependent_it->get(); - if (floaterp) - { - if (floaterp->isMinimizeable()) - { - floaterp->setMinimized(TRUE); - } - else if (!floaterp->isMinimized()) - { - floaterp->setVisible(FALSE); - } - } - } - - // Lose keyboard focus when minimized - releaseFocus(); - - for (S32 i = 0; i < 4; i++) - { - if (mResizeBar[i] != NULL) - { - mResizeBar[i]->setEnabled(FALSE); - } - if (mResizeHandle[i] != NULL) - { - mResizeHandle[i]->setEnabled(FALSE); - } - } - - // Reshape *after* setting mMinimized - reshape( minimized_width, floater_header_size, TRUE); - } - else - { - // If this window has been dragged while minimized (at any time), - // remember its position for the next time it's minimized. - if (mHasBeenDraggedWhileMinimized) - { - const LLRect& currentRect = getRect(); - mPreviousMinimizedLeft = currentRect.mLeft; - mPreviousMinimizedBottom = currentRect.mBottom; - } - - setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom ); - if (mButtonsEnabled[BUTTON_RESTORE]) - { - mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; - mButtonsEnabled[BUTTON_RESTORE] = FALSE; - } - - // show dependent floater - for(handle_set_iter_t dependent_it = mDependents.begin(); - dependent_it != mDependents.end(); - ++dependent_it) - { - LLFloater* floaterp = dependent_it->get(); - if (floaterp) - { - floaterp->setMinimized(FALSE); - floaterp->setVisible(TRUE); - } - } - - for (S32 i = 0; i < 4; i++) - { - if (mResizeBar[i] != NULL) - { - mResizeBar[i]->setEnabled(isResizable()); - } - if (mResizeHandle[i] != NULL) - { - mResizeHandle[i]->setEnabled(isResizable()); - } - } - - mMinimized = FALSE; - setFrontmost(); - // Reshape *after* setting mMinimized - reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); - } - - make_ui_sound("UISndWindowClose"); - updateTitleButtons(); - applyTitle (); + const LLFloater::Params& default_params = LLFloater::getDefaultParams(); + S32 floater_header_size = default_params.header_height; + static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0); + + if (minimize == mMinimized) return; + + if (mMinimizeSignal) + { + (*mMinimizeSignal)(this, LLSD(minimize)); + } + + if (minimize) + { + // minimized flag should be turned on before release focus + mMinimized = TRUE; + mExpandedRect = getRect(); + + // If the floater has been dragged while minimized in the + // past, then locate it at its previous minimized location. + // Otherwise, ask the view for a minimize position. + if (mHasBeenDraggedWhileMinimized) + { + setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom); + } + else + { + S32 left, bottom; + gFloaterView->getMinimizePosition(&left, &bottom); + setOrigin( left, bottom ); + } + + if (mButtonsEnabled[BUTTON_MINIMIZE]) + { + mButtonsEnabled[BUTTON_MINIMIZE] = FALSE; + mButtonsEnabled[BUTTON_RESTORE] = TRUE; + } + + setBorderVisible(TRUE); + + for(handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); + ++dependent_it) + { + LLFloater* floaterp = dependent_it->get(); + if (floaterp) + { + if (floaterp->isMinimizeable()) + { + floaterp->setMinimized(TRUE); + } + else if (!floaterp->isMinimized()) + { + floaterp->setVisible(FALSE); + } + } + } + + // Lose keyboard focus when minimized + releaseFocus(); + + for (S32 i = 0; i < 4; i++) + { + if (mResizeBar[i] != NULL) + { + mResizeBar[i]->setEnabled(FALSE); + } + if (mResizeHandle[i] != NULL) + { + mResizeHandle[i]->setEnabled(FALSE); + } + } + + // Reshape *after* setting mMinimized + reshape( minimized_width, floater_header_size, TRUE); + } + else + { + // If this window has been dragged while minimized (at any time), + // remember its position for the next time it's minimized. + if (mHasBeenDraggedWhileMinimized) + { + const LLRect& currentRect = getRect(); + mPreviousMinimizedLeft = currentRect.mLeft; + mPreviousMinimizedBottom = currentRect.mBottom; + } + + setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom ); + if (mButtonsEnabled[BUTTON_RESTORE]) + { + mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; + mButtonsEnabled[BUTTON_RESTORE] = FALSE; + } + + // show dependent floater + for(handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); + ++dependent_it) + { + LLFloater* floaterp = dependent_it->get(); + if (floaterp) + { + floaterp->setMinimized(FALSE); + floaterp->setVisible(TRUE); + } + } + + for (S32 i = 0; i < 4; i++) + { + if (mResizeBar[i] != NULL) + { + mResizeBar[i]->setEnabled(isResizable()); + } + if (mResizeHandle[i] != NULL) + { + mResizeHandle[i]->setEnabled(isResizable()); + } + } + + mMinimized = FALSE; + setFrontmost(); + // Reshape *after* setting mMinimized + reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE ); + } + + make_ui_sound("UISndWindowClose"); + updateTitleButtons(); + applyTitle (); } void LLFloater::setFocus( BOOL b ) { - if (b && getIsChrome()) - { - return; - } - LLView* last_focus = gFocusMgr.getLastFocusForGroup(this); - // a descendent already has focus - BOOL child_had_focus = hasFocus(); - - // give focus to first valid descendent - LLPanel::setFocus(b); - - if (b) - { - // only push focused floaters to front of stack if not in midst of ctrl-tab cycle - LLFloaterView * parent = dynamic_cast<LLFloaterView *>(getParent()); - if (!getHost() && parent && !parent->getCycleMode()) - { - if (!isFrontmost()) - { - setFrontmost(); - } - } - - // when getting focus, delegate to last descendent which had focus - if (last_focus && !child_had_focus && - last_focus->isInEnabledChain() && - last_focus->isInVisibleChain()) - { - // *FIX: should handle case where focus doesn't stick - last_focus->setFocus(TRUE); - } - } - updateTransparency(b ? TT_ACTIVE : TT_INACTIVE); + if (b && getIsChrome()) + { + return; + } + LLView* last_focus = gFocusMgr.getLastFocusForGroup(this); + // a descendent already has focus + BOOL child_had_focus = hasFocus(); + + // give focus to first valid descendent + LLPanel::setFocus(b); + + if (b) + { + // only push focused floaters to front of stack if not in midst of ctrl-tab cycle + LLFloaterView * parent = dynamic_cast<LLFloaterView *>(getParent()); + if (!getHost() && parent && !parent->getCycleMode()) + { + if (!isFrontmost()) + { + setFrontmost(); + } + } + + // when getting focus, delegate to last descendent which had focus + if (last_focus && !child_had_focus && + last_focus->isInEnabledChain() && + last_focus->isInVisibleChain()) + { + // *FIX: should handle case where focus doesn't stick + last_focus->setFocus(TRUE); + } + } + updateTransparency(b ? TT_ACTIVE : TT_INACTIVE); } // virtual void LLFloater::setRect(const LLRect &rect) { - LLPanel::setRect(rect); - layoutDragHandle(); - layoutResizeCtrls(); + LLPanel::setRect(rect); + layoutDragHandle(); + layoutResizeCtrls(); } // virtual void LLFloater::setIsChrome(BOOL is_chrome) { - // chrome floaters don't take focus at all - if (is_chrome) - { - // remove focus if we're changing to chrome - setFocus(FALSE); - // can't Ctrl-Tab to "chrome" floaters - setFocusRoot(FALSE); - mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome))); - } - - LLPanel::setIsChrome(is_chrome); + // chrome floaters don't take focus at all + if (is_chrome) + { + // remove focus if we're changing to chrome + setFocus(FALSE); + // can't Ctrl-Tab to "chrome" floaters + setFocusRoot(FALSE); + mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome))); + } + + LLPanel::setIsChrome(is_chrome); } // Change the draw style to account for the foreground state. void LLFloater::setForeground(BOOL front) { - if (front != mForeground) - { - mForeground = front; - if (mDragHandle) - mDragHandle->setForeground( front ); + if (front != mForeground) + { + mForeground = front; + if (mDragHandle) + mDragHandle->setForeground( front ); - if (!front) - { - releaseFocus(); - } + if (!front) + { + releaseFocus(); + } - setBackgroundOpaque( front ); - } + setBackgroundOpaque( front ); + } } void LLFloater::cleanupHandles() { - // remove handles to non-existent dependents - for(handle_set_iter_t dependent_it = mDependents.begin(); - dependent_it != mDependents.end(); ) - { - LLFloater* floaterp = dependent_it->get(); - if (!floaterp) - { + // remove handles to non-existent dependents + for(handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); ) + { + LLFloater* floaterp = dependent_it->get(); + if (!floaterp) + { dependent_it = mDependents.erase(dependent_it); - } - else - { - ++dependent_it; - } - } + } + else + { + ++dependent_it; + } + } } void LLFloater::setHost(LLMultiFloater* host) { - if (mHostHandle.isDead() && host) - { - // make buttons smaller for hosted windows to differentiate from parent - mButtonScale = 0.9f; - - // add tear off button - if (mCanTearOff) - { - mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE; - } - } - else if (!mHostHandle.isDead() && !host) - { - mButtonScale = 1.f; - //mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE; - } - if (host) - { - mHostHandle = host->getHandle(); - mLastHostHandle = host->getHandle(); - } - else - { - mHostHandle.markDead(); - } - - updateTitleButtons(); + if (mHostHandle.isDead() && host) + { + // make buttons smaller for hosted windows to differentiate from parent + mButtonScale = 0.9f; + + // add tear off button + if (mCanTearOff) + { + mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE; + } + } + else if (!mHostHandle.isDead() && !host) + { + mButtonScale = 1.f; + //mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE; + } + if (host) + { + mHostHandle = host->getHandle(); + mLastHostHandle = host->getHandle(); + } + else + { + mHostHandle.markDead(); + } + + updateTitleButtons(); } void LLFloater::moveResizeHandlesToFront() { - for( S32 i = 0; i < 4; i++ ) - { - if( mResizeBar[i] ) - { - sendChildToFront(mResizeBar[i]); - } - } + for( S32 i = 0; i < 4; i++ ) + { + if( mResizeBar[i] ) + { + sendChildToFront(mResizeBar[i]); + } + } - for( S32 i = 0; i < 4; i++ ) - { - if( mResizeHandle[i] ) - { - sendChildToFront(mResizeHandle[i]); - } - } + for( S32 i = 0; i < 4; i++ ) + { + if( mResizeHandle[i] ) + { + sendChildToFront(mResizeHandle[i]); + } + } } /*virtual*/ BOOL LLFloater::isFrontmost() { - LLFloaterView* floater_view = getParentByType<LLFloaterView>(); - return getVisible() - && (floater_view - && floater_view->getFrontmost() == this); + LLFloaterView* floater_view = getParentByType<LLFloaterView>(); + return getVisible() + && (floater_view + && floater_view->getFrontmost() == this); } void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL resize) { - mDependents.insert(floaterp->getHandle()); - floaterp->mDependeeHandle = getHandle(); - - if (reposition) - { - LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp); - if (resize) - { - const LLRect& base = getRect(); - if (rect.mTop == base.mTop) - rect.mBottom = base.mBottom; - else if (rect.mLeft == base.mLeft) - rect.mRight = base.mRight; - floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE); - } - floaterp->setRect(rect); - floaterp->setSnapTarget(getHandle()); - } - gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE); - if (floaterp->isFrontmost()) - { - // make sure to bring self and sibling floaters to front - gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome()); - } + mDependents.insert(floaterp->getHandle()); + floaterp->mDependeeHandle = getHandle(); + + if (reposition) + { + LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp); + if (resize) + { + const LLRect& base = getRect(); + if (rect.mTop == base.mTop) + rect.mBottom = base.mBottom; + else if (rect.mLeft == base.mLeft) + rect.mRight = base.mRight; + floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE); + } + floaterp->setRect(rect); + floaterp->setSnapTarget(getHandle()); + } + gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE); + if (floaterp->isFrontmost()) + { + // make sure to bring self and sibling floaters to front + gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome()); + } } void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition, BOOL resize) { - LLFloater* dependent_floaterp = dependent.get(); - if(dependent_floaterp) - { - addDependentFloater(dependent_floaterp, reposition, resize); - } + LLFloater* dependent_floaterp = dependent.get(); + if(dependent_floaterp) + { + addDependentFloater(dependent_floaterp, reposition, resize); + } } void LLFloater::removeDependentFloater(LLFloater* floaterp) { - mDependents.erase(floaterp->getHandle()); - floaterp->mDependeeHandle = LLHandle<LLFloater>(); + mDependents.erase(floaterp->getHandle()); + floaterp->mDependeeHandle = LLHandle<LLFloater>(); } void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels) @@ -1584,11 +1584,11 @@ void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bott } } - S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0; - S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0; - S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0; + S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0; + S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0; + S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0; - // move floater with dependings fully onscreen + // move floater with dependings fully onscreen mTranslateWithDependents = true; if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels)) { @@ -1611,111 +1611,111 @@ void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bott BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index) { - if( mButtonsEnabled[index] ) - { - LLButton* my_butt = mButtons[index]; - S32 local_x = x - my_butt->getRect().mLeft; - S32 local_y = y - my_butt->getRect().mBottom; + if( mButtonsEnabled[index] ) + { + LLButton* my_butt = mButtons[index]; + S32 local_x = x - my_butt->getRect().mLeft; + S32 local_y = y - my_butt->getRect().mBottom; - if ( - my_butt->pointInView(local_x, local_y) && - my_butt->handleMouseDown(local_x, local_y, mask)) - { - // the button handled it - return TRUE; - } - } - return FALSE; + if ( + my_butt->pointInView(local_x, local_y) && + my_butt->handleMouseDown(local_x, local_y, mask)) + { + // the button handled it + return TRUE; + } + } + return FALSE; } BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks) { - LLPanel::handleScrollWheel(x,y,clicks); - return TRUE;//always + LLPanel::handleScrollWheel(x,y,clicks); + return TRUE;//always } // virtual BOOL LLFloater::handleMouseUp(S32 x, S32 y, MASK mask) { - LL_DEBUGS() << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; - BOOL handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView - if (handled) { - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); - } - return handled; + LL_DEBUGS() << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; + BOOL handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView + if (handled) { + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + } + return handled; } // virtual BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask) { - if( mMinimized ) - { - // Offer the click to titlebar buttons. - // Note: this block and the offerClickToButton helper method can be removed - // because the parent container will handle it for us but we'll keep it here - // for safety until after reworking the panel code to manage hidden children. - if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return TRUE; - if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return TRUE; - if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE; - if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE; - - setFrontmost(TRUE, FALSE); - // Otherwise pass to drag handle for movement - return mDragHandle->handleMouseDown(x, y, mask); - } - else - { - bringToFront( x, y ); - BOOL handled = LLPanel::handleMouseDown( x, y, mask ); - if (handled) { - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); - } - return handled; - } + if( mMinimized ) + { + // Offer the click to titlebar buttons. + // Note: this block and the offerClickToButton helper method can be removed + // because the parent container will handle it for us but we'll keep it here + // for safety until after reworking the panel code to manage hidden children. + if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return TRUE; + if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return TRUE; + if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE; + if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE; + + setFrontmost(TRUE, FALSE); + // Otherwise pass to drag handle for movement + return mDragHandle->handleMouseDown(x, y, mask); + } + else + { + bringToFront( x, y ); + BOOL handled = LLPanel::handleMouseDown( x, y, mask ); + if (handled) { + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + } + return handled; + } } // virtual BOOL LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL was_minimized = mMinimized; - bringToFront( x, y ); - return was_minimized || LLPanel::handleRightMouseDown( x, y, mask ); + BOOL was_minimized = mMinimized; + bringToFront( x, y ); + return was_minimized || LLPanel::handleRightMouseDown( x, y, mask ); } BOOL LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - bringToFront( x, y ); - return LLPanel::handleMiddleMouseDown( x, y, mask ); + bringToFront( x, y ); + return LLPanel::handleMiddleMouseDown( x, y, mask ); } // virtual BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL was_minimized = mMinimized; - setMinimized(FALSE); - return was_minimized || LLPanel::handleDoubleClick(x, y, mask); + BOOL was_minimized = mMinimized; + setMinimized(FALSE); + return was_minimized || LLPanel::handleDoubleClick(x, y, mask); } // virtual void LLFloater::bringToFront( S32 x, S32 y ) { - if (getVisible() && pointInView(x, y)) - { - LLMultiFloater* hostp = getHost(); - if (hostp) - { - hostp->showFloater(this); - } - else - { - LLFloaterView* parent = dynamic_cast<LLFloaterView*>( getParent() ); - if (parent) - { - parent->bringToFront(this, !getIsChrome()); - } - } - } + if (getVisible() && pointInView(x, y)) + { + LLMultiFloater* hostp = getHost(); + if (hostp) + { + hostp->showFloater(this); + } + else + { + LLFloaterView* parent = dynamic_cast<LLFloaterView*>( getParent() ); + if (parent) + { + parent->bringToFront(this, !getIsChrome()); + } + } + } } // virtual @@ -1730,494 +1730,493 @@ void LLFloater::goneFromFront() // virtual void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key) { - LLUIUsage::instance().logFloater(getInstanceName()); - LLMultiFloater* hostp = getHost(); - if (hostp) - { - hostp->setVisible(TRUE); - hostp->setFrontmost(take_focus); - } - else - { - setVisible(TRUE); - setFrontmost(take_focus); - } + LLUIUsage::instance().logFloater(getInstanceName()); + LLMultiFloater* hostp = getHost(); + if (hostp) + { + hostp->setVisible(TRUE); + hostp->setFrontmost(take_focus); + } + else + { + setVisible(TRUE); + setFrontmost(take_focus); + } } void LLFloater::setFrontmost(BOOL take_focus, BOOL restore) { - LLMultiFloater* hostp = getHost(); - if (hostp) - { - // this will bring the host floater to the front and select - // the appropriate panel - hostp->showFloater(this); - } - else - { - // there are more than one floater view - // so we need to query our parent directly - LLFloaterView * parent = dynamic_cast<LLFloaterView*>( getParent() ); - if (parent) - { - parent->bringToFront(this, take_focus, restore); - } - - // Make sure to set the appropriate transparency type (STORM-732). - updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE); - } + LLMultiFloater* hostp = getHost(); + if (hostp) + { + // this will bring the host floater to the front and select + // the appropriate panel + hostp->showFloater(this); + } + else + { + // there are more than one floater view + // so we need to query our parent directly + LLFloaterView * parent = dynamic_cast<LLFloaterView*>( getParent() ); + if (parent) + { + parent->bringToFront(this, take_focus, restore); + } + + // Make sure to set the appropriate transparency type (STORM-732). + updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE); + } } void LLFloater::setCanDock(bool b) { - if(b != mCanDock) - { - mCanDock = b; - if(mCanDock) - { - mButtonsEnabled[BUTTON_DOCK] = !mDocked; - } - else - { - mButtonsEnabled[BUTTON_DOCK] = FALSE; - } - } - updateTitleButtons(); + if(b != mCanDock) + { + mCanDock = b; + if(mCanDock) + { + mButtonsEnabled[BUTTON_DOCK] = !mDocked; + } + else + { + mButtonsEnabled[BUTTON_DOCK] = FALSE; + } + } + updateTitleButtons(); } void LLFloater::setDocked(bool docked, bool pop_on_undock) { - if(docked != mDocked && mCanDock) - { - mDocked = docked; - mButtonsEnabled[BUTTON_DOCK] = !mDocked; + if(docked != mDocked && mCanDock) + { + mDocked = docked; + mButtonsEnabled[BUTTON_DOCK] = !mDocked; - if (mDocked) - { - setMinimized(FALSE); - mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; - } + if (mDocked) + { + setMinimized(FALSE); + mPositioning = LLFloaterEnums::POSITIONING_RELATIVE; + } - updateTitleButtons(); + updateTitleButtons(); + + storeDockStateControl(); + } - storeDockStateControl(); - } - } // static void LLFloater::onClickMinimize(LLFloater* self) { - if (!self) - return; - self->setMinimized( !self->isMinimized() ); + if (!self) + return; + self->setMinimized( !self->isMinimized() ); } void LLFloater::onClickTearOff(LLFloater* self) { - if (!self) - return; - S32 floater_header_size = self->mHeaderHeight; - LLMultiFloater* host_floater = self->getHost(); - if (host_floater) //Tear off - { - LLRect new_rect; - host_floater->removeFloater(self); - // reparent to floater view - gFloaterView->addChild(self); - - self->openFloater(self->getKey()); - if (self->mSaveRect && !self->mRectControl.empty()) - { - self->applyRectControl(); - } - else - { // only force position for floaters that don't have that data saved - new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight()); - self->setRect(new_rect); - } - gFloaterView->adjustToFitScreen(self, FALSE); - // give focus to new window to keep continuity for the user - self->setFocus(TRUE); - self->setTornOff(true); - } - else //Attach to parent. - { - LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get(); - if (new_host) - { - if (self->mSaveRect) - { + if (!self) + return; + S32 floater_header_size = self->mHeaderHeight; + LLMultiFloater* host_floater = self->getHost(); + if (host_floater) //Tear off + { + LLRect new_rect; + host_floater->removeFloater(self); + // reparent to floater view + gFloaterView->addChild(self); + + self->openFloater(self->getKey()); + if (self->mSaveRect && !self->mRectControl.empty()) + { + self->applyRectControl(); + } + else + { // only force position for floaters that don't have that data saved + new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight()); + self->setRect(new_rect); + } + gFloaterView->adjustToFitScreen(self, FALSE); + // give focus to new window to keep continuity for the user + self->setFocus(TRUE); + self->setTornOff(true); + } + else //Attach to parent. + { + LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get(); + if (new_host) + { + if (self->mSaveRect) + { LLRect screen_rect = self->calcScreenRect(); self->mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); - self->storeRectControl(); - } - self->setMinimized(FALSE); // to reenable minimize button if it was minimized - new_host->showFloater(self); - // make sure host is visible - new_host->openFloater(new_host->getKey()); - } - self->setTornOff(false); - } - self->updateTitleButtons(); + self->storeRectControl(); + } + self->setMinimized(FALSE); // to reenable minimize button if it was minimized + new_host->showFloater(self); + // make sure host is visible + new_host->openFloater(new_host->getKey()); + } + self->setTornOff(false); + } + self->updateTitleButtons(); self->setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE); } // static void LLFloater::onClickDock(LLFloater* self) { - if(self && self->mCanDock) - { - self->setDocked(!self->mDocked, true); - } + if(self && self->mCanDock) + { + self->setDocked(!self->mDocked, true); + } } // static void LLFloater::onClickHelp( LLFloater* self ) { - if (self && LLUI::getInstance()->mHelpImpl) - { - // find the current help context for this floater - std::string help_topic; - if (self->findHelpTopic(help_topic)) - { - LLUI::getInstance()->mHelpImpl->showTopic(help_topic); - } - } + if (self && LLUI::getInstance()->mHelpImpl) + { + // find the current help context for this floater + std::string help_topic; + if (self->findHelpTopic(help_topic)) + { + LLUI::getInstance()->mHelpImpl->showTopic(help_topic); + } + } } void LLFloater::initRectControl() { - // save_rect and save_visibility only apply to registered floaters - if (mSaveRect) - { - std::string ctrl_name = getControlName(mInstanceName, mKey); - mRectControl = LLFloaterReg::declareRectControl(ctrl_name); - mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name); - mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name); - } + // save_rect and save_visibility only apply to registered floaters + if (mSaveRect) + { + std::string ctrl_name = getControlName(mInstanceName, mKey); + mRectControl = LLFloaterReg::declareRectControl(ctrl_name); + mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name); + mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name); + } } // static void LLFloater::closeFrontmostFloater() { - LLFloater* floater_to_close = gFloaterView->getFrontmostClosableFloater(); - if(floater_to_close) - { - floater_to_close->closeFloater(); - } + LLFloater* floater_to_close = gFloaterView->getFrontmostClosableFloater(); + if(floater_to_close) + { + floater_to_close->closeFloater(); + } - // if nothing took focus after closing focused floater - // give it to next floater (to allow closing multiple windows via keyboard in rapid succession) - if (gFocusMgr.getKeyboardFocus() == NULL) - { - // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window - // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view - gFloaterView->focusFrontFloater(); - } + // if nothing took focus after closing focused floater + // give it to next floater (to allow closing multiple windows via keyboard in rapid succession) + if (gFocusMgr.getKeyboardFocus() == NULL) + { + // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window + // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view + gFloaterView->focusFrontFloater(); + } } // static void LLFloater::onClickClose( LLFloater* self ) { - if (!self) - return; - self->onClickCloseBtn(); + if (!self) + return; + self->onClickCloseBtn(); } void LLFloater::onClickCloseBtn(bool app_quitting) { - closeFloater(false); + closeFloater(false); } // virtual void LLFloater::draw() { - const F32 alpha = getCurrentTransparency(); - - // draw background - if( isBackgroundVisible() ) - { - drawShadow(this); - - S32 left = LLPANEL_BORDER_WIDTH; - S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH; - S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH; - S32 bottom = LLPANEL_BORDER_WIDTH; - - LLUIImage* image = NULL; - LLColor4 color; - LLColor4 overlay_color; - if (isBackgroundOpaque()) - { - // NOTE: image may not be set - image = getBackgroundImage(); - color = getBackgroundColor(); - overlay_color = getBackgroundImageOverlay(); - } - else - { - image = getTransparentImage(); - color = getTransparentColor(); - overlay_color = getTransparentImageOverlay(); - } - - if (image) - { - // We're using images for this floater's backgrounds - image->draw(getLocalRect(), overlay_color % alpha); - } - else - { - // We're not using images, use old-school flat colors - gl_rect_2d( left, top, right, bottom, color % alpha ); - - // draw highlight on title bar to indicate focus. RDW - if(hasFocus() - && !getIsChrome() - && !getCurrentTitle().empty()) - { - static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor"); - - const LLFontGL* font = LLFontGL::getFontSansSerif(); - LLRect r = getRect(); - gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1, - titlebar_focus_color % alpha, 0, TRUE); - } - } - } - - LLPanel::updateDefaultBtn(); - - if( getDefaultButton() ) - { - if (hasFocus() && getDefaultButton()->getEnabled()) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - // is this button a direct descendent and not a nested widget (e.g. checkbox)? - BOOL focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this; - // only enable default button when current focus is not a button - getDefaultButton()->setBorderEnabled(!focus_is_child_button); - } - else - { - getDefaultButton()->setBorderEnabled(FALSE); - } - } - if (isMinimized()) - { - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - drawChild(mButtons[i]); - } - drawChild(mDragHandle, 0, 0, TRUE); - } - else - { - // don't call LLPanel::draw() since we've implemented custom background rendering - LLView::draw(); - } - - // update tearoff button for torn off floaters - // when last host goes away - if (mCanTearOff && !getHost()) - { - LLFloater* old_host = mLastHostHandle.get(); - if (!old_host) - { - setCanTearOff(FALSE); - } - } -} - -void LLFloater::drawShadow(LLPanel* panel) -{ - S32 left = LLPANEL_BORDER_WIDTH; - S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH; - S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH; - S32 bottom = LLPANEL_BORDER_WIDTH; - - static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0); - static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow"); - LLColor4 shadow_color = shadow_color_cached; - F32 shadow_offset = (F32)shadow_offset_S32; - - if (!panel->isBackgroundOpaque()) - { - shadow_offset *= 0.2f; - shadow_color.mV[VALPHA] *= 0.5f; - } - gl_drop_shadow(left, top, right, bottom, - shadow_color % getCurrentTransparency(), - ll_round(shadow_offset)); + const F32 alpha = getCurrentTransparency(); + + // draw background + if( isBackgroundVisible() ) + { + drawShadow(this); + + S32 left = LLPANEL_BORDER_WIDTH; + S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH; + S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH; + S32 bottom = LLPANEL_BORDER_WIDTH; + + LLUIImage* image = NULL; + LLColor4 color; + LLColor4 overlay_color; + if (isBackgroundOpaque()) + { + // NOTE: image may not be set + image = getBackgroundImage(); + color = getBackgroundColor(); + overlay_color = getBackgroundImageOverlay(); + } + else + { + image = getTransparentImage(); + color = getTransparentColor(); + overlay_color = getTransparentImageOverlay(); + } + + if (image) + { + // We're using images for this floater's backgrounds + image->draw(getLocalRect(), overlay_color % alpha); + } + else + { + // We're not using images, use old-school flat colors + gl_rect_2d( left, top, right, bottom, color % alpha ); + + // draw highlight on title bar to indicate focus. RDW + if(hasFocus() + && !getIsChrome() + && !getCurrentTitle().empty()) + { + static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor"); + + const LLFontGL* font = LLFontGL::getFontSansSerif(); + LLRect r = getRect(); + gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1, + titlebar_focus_color % alpha, 0, TRUE); + } + } + } + + LLPanel::updateDefaultBtn(); + + if( getDefaultButton() ) + { + if (hasFocus() && getDefaultButton()->getEnabled()) + { + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + // is this button a direct descendent and not a nested widget (e.g. checkbox)? + BOOL focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this; + // only enable default button when current focus is not a button + getDefaultButton()->setBorderEnabled(!focus_is_child_button); + } + else + { + getDefaultButton()->setBorderEnabled(FALSE); + } + } + if (isMinimized()) + { + for (S32 i = 0; i < BUTTON_COUNT; i++) + { + drawChild(mButtons[i]); + } + drawChild(mDragHandle, 0, 0, TRUE); + } + else + { + // don't call LLPanel::draw() since we've implemented custom background rendering + LLView::draw(); + } + + // update tearoff button for torn off floaters + // when last host goes away + if (mCanTearOff && !getHost()) + { + LLFloater* old_host = mLastHostHandle.get(); + if (!old_host) + { + setCanTearOff(FALSE); + } + } +} + +void LLFloater::drawShadow(LLPanel* panel) +{ + S32 left = LLPANEL_BORDER_WIDTH; + S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH; + S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH; + S32 bottom = LLPANEL_BORDER_WIDTH; + + static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow"); + LLColor4 shadow_color = shadow_color_cached; + F32 shadow_offset = (F32)DROP_SHADOW_FLOATER; + + if (!panel->isBackgroundOpaque()) + { + shadow_offset *= 0.2f; + shadow_color.mV[VALPHA] *= 0.5f; + } + gl_drop_shadow(left, top, right, bottom, + shadow_color % getCurrentTransparency(), + ll_round(shadow_offset)); } void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type) { - if (!view) return; - child_list_t children = *view->getChildList(); - child_list_t::iterator it = children.begin(); + if (!view) return; + child_list_t children = *view->getChildList(); + child_list_t::iterator it = children.begin(); - LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view); - if (ctrl) - { - ctrl->setTransparencyType(transparency_type); - } + LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view); + if (ctrl) + { + ctrl->setTransparencyType(transparency_type); + } - for(; it != children.end(); ++it) - { - updateTransparency(*it, transparency_type); - } + for(; it != children.end(); ++it) + { + updateTransparency(*it, transparency_type); + } } void LLFloater::updateTransparency(ETypeTransparency transparency_type) { - updateTransparency(this, transparency_type); + updateTransparency(this, transparency_type); } -void LLFloater::setCanMinimize(BOOL can_minimize) +void LLFloater::setCanMinimize(BOOL can_minimize) { - // if removing minimize/restore button programmatically, - // go ahead and unminimize floater - mCanMinimize = can_minimize; - if (!can_minimize) - { - setMinimized(FALSE); - } + // if removing minimize/restore button programmatically, + // go ahead and unminimize floater + mCanMinimize = can_minimize; + if (!can_minimize) + { + setMinimized(FALSE); + } - mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized(); - mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized(); + mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized(); + mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized(); - updateTitleButtons(); + updateTitleButtons(); } -void LLFloater::setCanClose(BOOL can_close) +void LLFloater::setCanClose(BOOL can_close) { - mCanClose = can_close; - mButtonsEnabled[BUTTON_CLOSE] = can_close; + mCanClose = can_close; + mButtonsEnabled[BUTTON_CLOSE] = can_close; - updateTitleButtons(); + updateTitleButtons(); } -void LLFloater::setCanTearOff(BOOL can_tear_off) +void LLFloater::setCanTearOff(BOOL can_tear_off) { - mCanTearOff = can_tear_off; - mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead(); + mCanTearOff = can_tear_off; + mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead(); - updateTitleButtons(); + updateTitleButtons(); } void LLFloater::setCanResize(BOOL can_resize) { - mResizable = can_resize; - enableResizeCtrls(can_resize); + mResizable = can_resize; + enableResizeCtrls(can_resize); } void LLFloater::setCanDrag(BOOL can_drag) { - // if we delete drag handle, we no longer have access to the floater's title - // so just enable/disable it - if (!can_drag && mDragHandle->getEnabled()) - { - mDragHandle->setEnabled(FALSE); - } - else if (can_drag && !mDragHandle->getEnabled()) - { - mDragHandle->setEnabled(TRUE); - } + // if we delete drag handle, we no longer have access to the floater's title + // so just enable/disable it + if (!can_drag && mDragHandle->getEnabled()) + { + mDragHandle->setEnabled(FALSE); + } + else if (can_drag && !mDragHandle->getEnabled()) + { + mDragHandle->setEnabled(TRUE); + } } bool LLFloater::getCanDrag() { - return mDragHandle->getEnabled(); + return mDragHandle->getEnabled(); } void LLFloater::updateTitleButtons() { - static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); - static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0); - LLRect buttons_rect; - S32 button_count = 0; - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - if (!mButtons[i]) - { - continue; - } - - bool enabled = mButtonsEnabled[i]; - if (i == BUTTON_HELP) - { - // don't show the help button if the floater is minimized - // or if it is a docked tear-off floater - if (isMinimized() || (mButtonsEnabled[BUTTON_TEAR_OFF] && ! mTornOff)) - { - enabled = false; - } - } - if (i == BUTTON_CLOSE && mButtonScale != 1.f) - { - //*HACK: always render close button for hosted floaters so - //that users don't accidentally hit the button when - //closing multiple windows in the chatterbox - enabled = true; - } - - mButtons[i]->setEnabled(enabled); - - if (enabled) - { - button_count++; - - LLRect btn_rect; - if (mDragOnLeft) - { - btn_rect.setLeftTopAndSize( - LLPANEL_BORDER_WIDTH, - getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count, - ll_round((F32)floater_close_box_size * mButtonScale), - ll_round((F32)floater_close_box_size * mButtonScale)); - } - else - { - btn_rect.setLeftTopAndSize( - getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count, - getRect().getHeight() - close_box_from_top, - ll_round((F32)floater_close_box_size * mButtonScale), - ll_round((F32)floater_close_box_size * mButtonScale)); - } - - // first time here, init 'buttons_rect' - if(1 == button_count) - { - buttons_rect = btn_rect; - } - else - { - // if mDragOnLeft=true then buttons are on top-left side vertically aligned - // title is not displayed in this case, calculating 'buttons_rect' for future use - mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom : - buttons_rect.mLeft = btn_rect.mLeft; - } - mButtons[i]->setRect(btn_rect); - mButtons[i]->setVisible(TRUE); - // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater - mButtons[i]->setTabStop(i == BUTTON_RESTORE); - } - else - { - mButtons[i]->setVisible(FALSE); - } - } - if (mDragHandle) - { - localRectToOtherView(buttons_rect, &buttons_rect, mDragHandle); - mDragHandle->setButtonsRect(buttons_rect); - } + static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0); + LLRect buttons_rect; + S32 button_count = 0; + for (S32 i = 0; i < BUTTON_COUNT; i++) + { + if (!mButtons[i]) + { + continue; + } + + bool enabled = mButtonsEnabled[i]; + if (i == BUTTON_HELP) + { + // don't show the help button if the floater is minimized + // or if it is a docked tear-off floater + if (isMinimized() || (mButtonsEnabled[BUTTON_TEAR_OFF] && ! mTornOff)) + { + enabled = false; + } + } + if (i == BUTTON_CLOSE && mButtonScale != 1.f) + { + //*HACK: always render close button for hosted floaters so + //that users don't accidentally hit the button when + //closing multiple windows in the chatterbox + enabled = true; + } + + mButtons[i]->setEnabled(enabled); + + if (enabled) + { + button_count++; + + LLRect btn_rect; + if (mDragOnLeft) + { + btn_rect.setLeftTopAndSize( + LLPANEL_BORDER_WIDTH, + getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count, + ll_round((F32)floater_close_box_size * mButtonScale), + ll_round((F32)floater_close_box_size * mButtonScale)); + } + else + { + btn_rect.setLeftTopAndSize( + getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count, + getRect().getHeight() - close_box_from_top, + ll_round((F32)floater_close_box_size * mButtonScale), + ll_round((F32)floater_close_box_size * mButtonScale)); + } + + // first time here, init 'buttons_rect' + if(1 == button_count) + { + buttons_rect = btn_rect; + } + else + { + // if mDragOnLeft=true then buttons are on top-left side vertically aligned + // title is not displayed in this case, calculating 'buttons_rect' for future use + mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom : + buttons_rect.mLeft = btn_rect.mLeft; + } + mButtons[i]->setRect(btn_rect); + mButtons[i]->setVisible(TRUE); + // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater + mButtons[i]->setTabStop(i == BUTTON_RESTORE); + } + else + { + mButtons[i]->setVisible(FALSE); + } + } + if (mDragHandle) + { + localRectToOtherView(buttons_rect, &buttons_rect, mDragHandle); + mDragHandle->setButtonsRect(buttons_rect); + } } void LLFloater::drawConeToOwner(F32 &context_cone_opacity, @@ -2286,115 +2285,115 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity, void LLFloater::buildButtons(const Params& floater_params) { - static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); - static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0); - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - if (mButtons[i]) - { - removeChild(mButtons[i]); - delete mButtons[i]; - mButtons[i] = NULL; - } - - LLRect btn_rect; - if (mDragOnLeft) - { - btn_rect.setLeftTopAndSize( - LLPANEL_BORDER_WIDTH, - getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1), - ll_round(floater_close_box_size * mButtonScale), - ll_round(floater_close_box_size * mButtonScale)); - } - else - { - btn_rect.setLeftTopAndSize( - getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1), - getRect().getHeight() - close_box_from_top, - ll_round(floater_close_box_size * mButtonScale), - ll_round(floater_close_box_size * mButtonScale)); - } - - LLButton::Params p; - p.name(sButtonNames[i]); - p.rect(btn_rect); - p.image_unselected = getButtonImage(floater_params, (EFloaterButton)i); - // Selected, no matter if hovered or not, is "pressed" - LLUIImage* pressed_image = getButtonPressedImage(floater_params, (EFloaterButton)i); - p.image_selected = pressed_image; - p.image_hover_selected = pressed_image; - // Use a glow effect when the user hovers over the button - // These icons are really small, need glow amount increased - p.hover_glow_amount( 0.33f ); - p.click_callback.function(boost::bind(sButtonCallbacks[i], this)); - p.tab_stop(false); - p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT); - p.tool_tip = getButtonTooltip(floater_params, (EFloaterButton)i, getIsChrome()); - p.scale_image(true); - p.chrome(true); - - LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p); - addChild(buttonp); - mButtons[i] = buttonp; - } - - updateTitleButtons(); + static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0); + for (S32 i = 0; i < BUTTON_COUNT; i++) + { + if (mButtons[i]) + { + removeChild(mButtons[i]); + delete mButtons[i]; + mButtons[i] = NULL; + } + + LLRect btn_rect; + if (mDragOnLeft) + { + btn_rect.setLeftTopAndSize( + LLPANEL_BORDER_WIDTH, + getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1), + ll_round(floater_close_box_size * mButtonScale), + ll_round(floater_close_box_size * mButtonScale)); + } + else + { + btn_rect.setLeftTopAndSize( + getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1), + getRect().getHeight() - close_box_from_top, + ll_round(floater_close_box_size * mButtonScale), + ll_round(floater_close_box_size * mButtonScale)); + } + + LLButton::Params p; + p.name(sButtonNames[i]); + p.rect(btn_rect); + p.image_unselected = getButtonImage(floater_params, (EFloaterButton)i); + // Selected, no matter if hovered or not, is "pressed" + LLUIImage* pressed_image = getButtonPressedImage(floater_params, (EFloaterButton)i); + p.image_selected = pressed_image; + p.image_hover_selected = pressed_image; + // Use a glow effect when the user hovers over the button + // These icons are really small, need glow amount increased + p.hover_glow_amount( 0.33f ); + p.click_callback.function(boost::bind(sButtonCallbacks[i], this)); + p.tab_stop(false); + p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT); + p.tool_tip = getButtonTooltip(floater_params, (EFloaterButton)i, getIsChrome()); + p.scale_image(true); + p.chrome(true); + + LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p); + addChild(buttonp); + mButtons[i] = buttonp; + } + + updateTitleButtons(); } // static LLUIImage* LLFloater::getButtonImage(const Params& p, EFloaterButton e) { - switch(e) - { - default: - case BUTTON_CLOSE: - return p.close_image; - case BUTTON_RESTORE: - return p.restore_image; - case BUTTON_MINIMIZE: - return p.minimize_image; - case BUTTON_TEAR_OFF: - return p.tear_off_image; - case BUTTON_DOCK: - return p.dock_image; - case BUTTON_HELP: - return p.help_image; - } + switch(e) + { + default: + case BUTTON_CLOSE: + return p.close_image; + case BUTTON_RESTORE: + return p.restore_image; + case BUTTON_MINIMIZE: + return p.minimize_image; + case BUTTON_TEAR_OFF: + return p.tear_off_image; + case BUTTON_DOCK: + return p.dock_image; + case BUTTON_HELP: + return p.help_image; + } } // static LLUIImage* LLFloater::getButtonPressedImage(const Params& p, EFloaterButton e) { - switch(e) - { - default: - case BUTTON_CLOSE: - return p.close_pressed_image; - case BUTTON_RESTORE: - return p.restore_pressed_image; - case BUTTON_MINIMIZE: - return p.minimize_pressed_image; - case BUTTON_TEAR_OFF: - return p.tear_off_pressed_image; - case BUTTON_DOCK: - return p.dock_pressed_image; - case BUTTON_HELP: - return p.help_pressed_image; - } + switch(e) + { + default: + case BUTTON_CLOSE: + return p.close_pressed_image; + case BUTTON_RESTORE: + return p.restore_pressed_image; + case BUTTON_MINIMIZE: + return p.minimize_pressed_image; + case BUTTON_TEAR_OFF: + return p.tear_off_pressed_image; + case BUTTON_DOCK: + return p.dock_pressed_image; + case BUTTON_HELP: + return p.help_pressed_image; + } } // static std::string LLFloater::getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome) { - // EXT-4081 (Lag Meter: Ctrl+W does not close floater) - // If floater is chrome set 'Close' text for close button's tooltip - if(is_chrome && BUTTON_CLOSE == e) - { - static std::string close_tooltip_chrome = LLTrans::getString("BUTTON_CLOSE_CHROME"); - return close_tooltip_chrome; - } - // TODO: per-floater localizable tooltips set in XML - return sButtonToolTips[e]; + // EXT-4081 (Lag Meter: Ctrl+W does not close floater) + // If floater is chrome set 'Close' text for close button's tooltip + if(is_chrome && BUTTON_CLOSE == e) + { + static std::string close_tooltip_chrome = LLTrans::getString("BUTTON_CLOSE_CHROME"); + return close_tooltip_chrome; + } + // TODO: per-floater localizable tooltips set in XML + return sButtonToolTips[e]; } ///////////////////////////////////////////////////// @@ -2403,1095 +2402,1096 @@ std::string LLFloater::getButtonTooltip(const Params& p, EFloaterButton e, bool static LLDefaultChildRegistry::Register<LLFloaterView> r("floater_view"); LLFloaterView::LLFloaterView (const Params& p) -: LLUICtrl (p), - mFocusCycleMode(FALSE), - mMinimizePositionVOffset(0), - mSnapOffsetBottom(0), - mSnapOffsetRight(0) +: LLUICtrl (p), + mFocusCycleMode(FALSE), + mMinimizePositionVOffset(0), + mSnapOffsetBottom(0), + mSnapOffsetRight(0) { - mSnapView = getHandle(); + mSnapView = getHandle(); } // By default, adjust vertical. void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLView::reshape(width, height, called_from_parent); - - mLastSnapRect = getSnapRect(); - - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp); - if (floaterp->isDependent()) - { - // dependents are moved with their "dependee" - continue; - } - - if (!floaterp->isMinimized() && floaterp->getCanDrag()) - { - LLRect old_rect = floaterp->getRect(); - floaterp->applyPositioning(NULL, false); - LLRect new_rect = floaterp->getRect(); - - //LLRect r = floaterp->getRect(); - - //// Compute absolute distance from each edge of screen - //S32 left_offset = llabs(r.mLeft - 0); - //S32 right_offset = llabs(old_right - r.mRight); - - //S32 top_offset = llabs(old_top - r.mTop); - //S32 bottom_offset = llabs(r.mBottom - 0); - - S32 translate_x = new_rect.mLeft - old_rect.mLeft; - S32 translate_y = new_rect.mBottom - old_rect.mBottom; - - //if (left_offset > right_offset) - //{ - // translate_x = new_right - old_right; - //} - - //if (top_offset < bottom_offset) - //{ - // translate_y = new_top - old_top; - //} - - // don't reposition immovable floaters - //if (floaterp->getCanDrag()) - //{ - // floaterp->translate(translate_x, translate_y); - //} - for (LLHandle<LLFloater> dependent_floater : floaterp->mDependents) - { - if (dependent_floater.get()) - { - dependent_floater.get()->translate(translate_x, translate_y); - } - } - } - } + LLView::reshape(width, height, called_from_parent); + + mLastSnapRect = getSnapRect(); + + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp); + if (floaterp->isDependent()) + { + // dependents are moved with their "dependee" + continue; + } + + if (!floaterp->isMinimized() && floaterp->getCanDrag()) + { + LLRect old_rect = floaterp->getRect(); + floaterp->applyPositioning(NULL, false); + LLRect new_rect = floaterp->getRect(); + + //LLRect r = floaterp->getRect(); + + //// Compute absolute distance from each edge of screen + //S32 left_offset = llabs(r.mLeft - 0); + //S32 right_offset = llabs(old_right - r.mRight); + + //S32 top_offset = llabs(old_top - r.mTop); + //S32 bottom_offset = llabs(r.mBottom - 0); + + S32 translate_x = new_rect.mLeft - old_rect.mLeft; + S32 translate_y = new_rect.mBottom - old_rect.mBottom; + + //if (left_offset > right_offset) + //{ + // translate_x = new_right - old_right; + //} + + //if (top_offset < bottom_offset) + //{ + // translate_y = new_top - old_top; + //} + + // don't reposition immovable floaters + //if (floaterp->getCanDrag()) + //{ + // floaterp->translate(translate_x, translate_y); + //} + for (LLHandle<LLFloater> dependent_floater : floaterp->mDependents) + { + if (dependent_floater.get()) + { + dependent_floater.get()->translate(translate_x, translate_y); + } + } + } + } } void LLFloaterView::restoreAll() { - // make sure all subwindows aren't minimized - for (auto child : *getChildList()) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(child); - if (floaterp) - { - floaterp->setMinimized(FALSE); - } - } + // make sure all subwindows aren't minimized + child_list_t child_list = *(getChildList()); + for (LLView* child : child_list) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(child); + if (floaterp) + { + floaterp->setMinimized(FALSE); + } + } - // *FIX: make sure dependents are restored + // *FIX: make sure dependents are restored - // children then deleted by default view constructor + // children then deleted by default view constructor } LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ) { - LLRect base_rect = reference_floater->getRect(); - LLRect::tCoordType width = neighbor->getRect().getWidth(); - LLRect::tCoordType height = neighbor->getRect().getHeight(); - LLRect new_rect = neighbor->getRect(); - - LLRect expanded_base_rect = base_rect; - expanded_base_rect.stretch(10); - for(LLFloater::handle_set_iter_t dependent_it = reference_floater->mDependents.begin(); - dependent_it != reference_floater->mDependents.end(); ++dependent_it) - { - LLFloater* sibling = dependent_it->get(); - // check for dependents within 10 pixels of base floater - if (sibling && - sibling != neighbor && - sibling->getVisible() && - expanded_base_rect.overlaps(sibling->getRect())) - { - base_rect.unionWith(sibling->getRect()); - } - } - - LLRect::tCoordType left_margin = llmax(0, base_rect.mLeft); - LLRect::tCoordType right_margin = llmax(0, getRect().getWidth() - base_rect.mRight); - LLRect::tCoordType top_margin = llmax(0, getRect().getHeight() - base_rect.mTop); - LLRect::tCoordType bottom_margin = llmax(0, base_rect.mBottom); - - // find position for floater in following order - // right->left->bottom->top - for (S32 i = 0; i < 5; i++) - { - if (right_margin > width) - { - new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mTop); - return new_rect; - } - else if (left_margin > width) - { - new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight, base_rect.mTop - neighbor->getRect().mTop); - return new_rect; - } - else if (bottom_margin > height) - { - new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mBottom - neighbor->getRect().mTop); - return new_rect; - } - else if (top_margin > height) - { - new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mBottom); - return new_rect; - } - - // keep growing margins to find "best" fit - left_margin += 20; - right_margin += 20; - top_margin += 20; - bottom_margin += 20; - } - - // didn't find anything, return initial rect - return new_rect; + LLRect base_rect = reference_floater->getRect(); + LLRect::tCoordType width = neighbor->getRect().getWidth(); + LLRect::tCoordType height = neighbor->getRect().getHeight(); + LLRect new_rect = neighbor->getRect(); + + LLRect expanded_base_rect = base_rect; + expanded_base_rect.stretch(10); + for(LLFloater::handle_set_iter_t dependent_it = reference_floater->mDependents.begin(); + dependent_it != reference_floater->mDependents.end(); ++dependent_it) + { + LLFloater* sibling = dependent_it->get(); + // check for dependents within 10 pixels of base floater + if (sibling && + sibling != neighbor && + sibling->getVisible() && + expanded_base_rect.overlaps(sibling->getRect())) + { + base_rect.unionWith(sibling->getRect()); + } + } + + LLRect::tCoordType left_margin = llmax(0, base_rect.mLeft); + LLRect::tCoordType right_margin = llmax(0, getRect().getWidth() - base_rect.mRight); + LLRect::tCoordType top_margin = llmax(0, getRect().getHeight() - base_rect.mTop); + LLRect::tCoordType bottom_margin = llmax(0, base_rect.mBottom); + + // find position for floater in following order + // right->left->bottom->top + for (S32 i = 0; i < 5; i++) + { + if (right_margin > width) + { + new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mTop); + return new_rect; + } + else if (left_margin > width) + { + new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight, base_rect.mTop - neighbor->getRect().mTop); + return new_rect; + } + else if (bottom_margin > height) + { + new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mBottom - neighbor->getRect().mTop); + return new_rect; + } + else if (top_margin > height) + { + new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mBottom); + return new_rect; + } + + // keep growing margins to find "best" fit + left_margin += 20; + right_margin += 20; + top_margin += 20; + bottom_margin += 20; + } + + // didn't find anything, return initial rect + return new_rect; } void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore) { - if (!child) - return; + if (!child) + return; LLFloater* front_child = mFrontChildHandle.get(); - if (front_child == child) - { - if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child)) - { - child->setFocus(TRUE); - } - return; - } - - if (front_child && front_child->getVisible()) - { + if (front_child == child) + { + if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child)) + { + child->setFocus(TRUE); + } + return; + } + + if (front_child && front_child->getVisible()) + { front_child->goneFromFront(); - } + } mFrontChildHandle = child->getHandle(); - // *TODO: make this respect floater's mAutoFocus value, instead of - // using parameter - if (child->getHost()) - { - // this floater is hosted elsewhere and hence not one of our children, abort - return; - } - std::vector<LLFloater*> floaters_to_move; - // Look at all floaters...tab - for (child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) - { - LLFloater* floater = dynamic_cast<LLFloater*>(*child_it); - - // ...but if I'm a dependent floater... - if (floater && child->isDependent()) - { - // ...look for floaters that have me as a dependent... - LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle()); - - if (found_dependent != floater->mDependents.end()) - { - // ...and make sure all children of that floater (including me) are brought to front... - for (LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); - dependent_it != floater->mDependents.end(); ++dependent_it) - { - LLFloater* sibling = dependent_it->get(); - if (sibling) - { - floaters_to_move.push_back(sibling); - } - } - //...before bringing my parent to the front... - floaters_to_move.push_back(floater); - } - } - } - - std::vector<LLFloater*>::iterator floater_it; - for(floater_it = floaters_to_move.begin(); floater_it != floaters_to_move.end(); ++floater_it) - { - LLFloater* floaterp = *floater_it; - sendChildToFront(floaterp); - - // always unminimize dependee, but allow dependents to stay minimized - if (!floaterp->isDependent()) - { - floaterp->setMinimized(FALSE); - } - } - floaters_to_move.clear(); - - // ...then bringing my own dependents to the front... - for (LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin(); - dependent_it != child->mDependents.end(); ++dependent_it) - { - LLFloater* dependent = dependent_it->get(); - if (dependent) - { - sendChildToFront(dependent); - } - } - - // ...and finally bringing myself to front - // (do this last, so that I'm left in front at end of this call) - if (*beginChild() != child) - { - sendChildToFront(child); - } - - if(restore) - { - child->setMinimized(FALSE); - } - - if (give_focus && !gFocusMgr.childHasKeyboardFocus(child)) - { - child->setFocus(TRUE); - // floater did not take focus, so relinquish focus to world - if (!child->hasFocus()) - { - gFocusMgr.setKeyboardFocus(NULL); - } - } + // *TODO: make this respect floater's mAutoFocus value, instead of + // using parameter + if (child->getHost()) + { + // this floater is hosted elsewhere and hence not one of our children, abort + return; + } + std::vector<LLFloater*> floaters_to_move; + // Look at all floaters...tab + for (child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) + { + LLFloater* floater = dynamic_cast<LLFloater*>(*child_it); + + // ...but if I'm a dependent floater... + if (floater && child->isDependent()) + { + // ...look for floaters that have me as a dependent... + LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle()); + + if (found_dependent != floater->mDependents.end()) + { + // ...and make sure all children of that floater (including me) are brought to front... + for (LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); + dependent_it != floater->mDependents.end(); ++dependent_it) + { + LLFloater* sibling = dependent_it->get(); + if (sibling) + { + floaters_to_move.push_back(sibling); + } + } + //...before bringing my parent to the front... + floaters_to_move.push_back(floater); + } + } + } + + std::vector<LLFloater*>::iterator floater_it; + for(floater_it = floaters_to_move.begin(); floater_it != floaters_to_move.end(); ++floater_it) + { + LLFloater* floaterp = *floater_it; + sendChildToFront(floaterp); + + // always unminimize dependee, but allow dependents to stay minimized + if (!floaterp->isDependent()) + { + floaterp->setMinimized(FALSE); + } + } + floaters_to_move.clear(); + + // ...then bringing my own dependents to the front... + for (LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin(); + dependent_it != child->mDependents.end(); ++dependent_it) + { + LLFloater* dependent = dependent_it->get(); + if (dependent) + { + sendChildToFront(dependent); + } + } + + // ...and finally bringing myself to front + // (do this last, so that I'm left in front at end of this call) + if (*beginChild() != child) + { + sendChildToFront(child); + } + + if(restore) + { + child->setMinimized(FALSE); + } + + if (give_focus && !gFocusMgr.childHasKeyboardFocus(child)) + { + child->setFocus(TRUE); + // floater did not take focus, so relinquish focus to world + if (!child->hasFocus()) + { + gFocusMgr.setKeyboardFocus(NULL); + } + } } void LLFloaterView::highlightFocusedFloater() { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLFloater *floater = (LLFloater *)(*child_it); - - // skip dependent floaters, as we'll handle them in a batch along with their dependee(?) - if (floater->isDependent()) - { - continue; - } - - BOOL floater_or_dependent_has_focus = gFocusMgr.childHasKeyboardFocus(floater); - for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); - dependent_it != floater->mDependents.end(); - ++dependent_it) - { - LLFloater* dependent_floaterp = dependent_it->get(); - if (dependent_floaterp && gFocusMgr.childHasKeyboardFocus(dependent_floaterp)) - { - floater_or_dependent_has_focus = TRUE; - } - } - - // now set this floater and all its dependents - floater->setForeground(floater_or_dependent_has_focus); - - for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); - dependent_it != floater->mDependents.end(); ) - { - LLFloater* dependent_floaterp = dependent_it->get(); - if (dependent_floaterp) - { - dependent_floaterp->setForeground(floater_or_dependent_has_focus); - } - ++dependent_it; - } - - floater->cleanupHandles(); - } + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLFloater *floater = (LLFloater *)(*child_it); + + // skip dependent floaters, as we'll handle them in a batch along with their dependee(?) + if (floater->isDependent()) + { + continue; + } + + BOOL floater_or_dependent_has_focus = gFocusMgr.childHasKeyboardFocus(floater); + for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); + dependent_it != floater->mDependents.end(); + ++dependent_it) + { + LLFloater* dependent_floaterp = dependent_it->get(); + if (dependent_floaterp && gFocusMgr.childHasKeyboardFocus(dependent_floaterp)) + { + floater_or_dependent_has_focus = TRUE; + } + } + + // now set this floater and all its dependents + floater->setForeground(floater_or_dependent_has_focus); + + for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin(); + dependent_it != floater->mDependents.end(); ) + { + LLFloater* dependent_floaterp = dependent_it->get(); + if (dependent_floaterp) + { + dependent_floaterp->setForeground(floater_or_dependent_has_focus); + } + ++dependent_it; + } + + floater->cleanupHandles(); + } } LLFloater* LLFloaterView::getFrontmostClosableFloater() { - child_list_const_iter_t child_it; - LLFloater* frontmost_floater = NULL; + child_list_const_iter_t child_it; + LLFloater* frontmost_floater = NULL; - for ( child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - frontmost_floater = (LLFloater *)(*child_it); + for ( child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + frontmost_floater = (LLFloater *)(*child_it); - if (frontmost_floater->isInVisibleChain() && frontmost_floater->isCloseable()) - { - return frontmost_floater; - } - } + if (frontmost_floater->isInVisibleChain() && frontmost_floater->isCloseable()) + { + return frontmost_floater; + } + } - return NULL; + return NULL; } void LLFloaterView::unhighlightFocusedFloater() { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLFloater *floater = (LLFloater *)(*child_it); + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLFloater *floater = (LLFloater *)(*child_it); - floater->setForeground(FALSE); - } + floater->setForeground(FALSE); + } } void LLFloaterView::focusFrontFloater() { - LLFloater* floaterp = getFrontmost(); - if (floaterp) - { - floaterp->setFocus(TRUE); - } + LLFloater* floaterp = getFrontmost(); + if (floaterp) + { + floaterp->setFocus(TRUE); + } } void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) { - const LLFloater::Params& default_params = LLFloater::getDefaultParams(); - S32 floater_header_size = default_params.header_height; - static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0); - LLRect snap_rect_local = getLocalSnapRect(); - snap_rect_local.mTop += mMinimizePositionVOffset; - for(S32 col = snap_rect_local.mLeft; - col < snap_rect_local.getWidth() - minimized_width; - col += minimized_width) - { - for(S32 row = snap_rect_local.mTop - floater_header_size; - row > floater_header_size; - row -= floater_header_size ) //loop rows - { - - bool foundGap = TRUE; - for(child_list_const_iter_t child_it = getChildList()->begin(); - child_it != getChildList()->end(); - ++child_it) //loop floaters - { - // Examine minimized children. - LLFloater* floater = dynamic_cast<LLFloater*>(*child_it); - if(floater->isMinimized()) - { - LLRect r = floater->getRect(); - if((r.mBottom < (row + floater_header_size)) - && (r.mBottom > (row - floater_header_size)) - && (r.mLeft < (col + minimized_width)) - && (r.mLeft > (col - minimized_width))) - { - // needs the check for off grid. can't drag, - // but window resize makes them off - foundGap = FALSE; - break; - } - } - } //done floaters - if(foundGap) - { - *left = col; - *bottom = row; - return; //done - } - } //done this col - } - - // crude - stack'em all at 0,0 when screen is full of minimized - // floaters. - *left = snap_rect_local.mLeft; - *bottom = snap_rect_local.mBottom; + const LLFloater::Params& default_params = LLFloater::getDefaultParams(); + S32 floater_header_size = default_params.header_height; + static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0); + LLRect snap_rect_local = getLocalSnapRect(); + snap_rect_local.mTop += mMinimizePositionVOffset; + for(S32 col = snap_rect_local.mLeft; + col < snap_rect_local.getWidth() - minimized_width; + col += minimized_width) + { + for(S32 row = snap_rect_local.mTop - floater_header_size; + row > floater_header_size; + row -= floater_header_size ) //loop rows + { + + bool foundGap = TRUE; + for(child_list_const_iter_t child_it = getChildList()->begin(); + child_it != getChildList()->end(); + ++child_it) //loop floaters + { + // Examine minimized children. + LLFloater* floater = dynamic_cast<LLFloater*>(*child_it); + if(floater->isMinimized()) + { + LLRect r = floater->getRect(); + if((r.mBottom < (row + floater_header_size)) + && (r.mBottom > (row - floater_header_size)) + && (r.mLeft < (col + minimized_width)) + && (r.mLeft > (col - minimized_width))) + { + // needs the check for off grid. can't drag, + // but window resize makes them off + foundGap = FALSE; + break; + } + } + } //done floaters + if(foundGap) + { + *left = col; + *bottom = row; + return; //done + } + } //done this col + } + + // crude - stack'em all at 0,0 when screen is full of minimized + // floaters. + *left = snap_rect_local.mLeft; + *bottom = snap_rect_local.mBottom; } void LLFloaterView::destroyAllChildren() { - LLView::deleteAllChildren(); + LLView::deleteAllChildren(); } void LLFloaterView::closeAllChildren(bool app_quitting) { - // iterate over a copy of the list, because closing windows will destroy - // some windows on the list. - child_list_t child_list = *(getChildList()); - - for (child_list_const_iter_t it = child_list.begin(); it != child_list.end(); ++it) - { - LLView* viewp = *it; - child_list_const_iter_t exists = std::find(getChildList()->begin(), getChildList()->end(), viewp); - if (exists == getChildList()->end()) - { - // this floater has already been removed - continue; - } - - LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp); - - // Attempt to close floater. This will cause the "do you want to save" - // dialogs to appear. - // Skip invisible floaters if we're not quitting (STORM-192). - if (floaterp->canClose() && !floaterp->isDead() && - (app_quitting || floaterp->getVisible())) - { - floaterp->closeFloater(app_quitting); - } - } + // iterate over a copy of the list, because closing windows will destroy + // some windows on the list. + child_list_t child_list = *(getChildList()); + + for (child_list_const_iter_t it = child_list.begin(); it != child_list.end(); ++it) + { + LLView* viewp = *it; + child_list_const_iter_t exists = std::find(getChildList()->begin(), getChildList()->end(), viewp); + if (exists == getChildList()->end()) + { + // this floater has already been removed + continue; + } + + LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp); + + // Attempt to close floater. This will cause the "do you want to save" + // dialogs to appear. + // Skip invisible floaters if we're not quitting (STORM-192). + if (floaterp->canClose() && !floaterp->isDead() && + (app_quitting || floaterp->getVisible())) + { + floaterp->closeFloater(app_quitting); + } + } } void LLFloaterView::hiddenFloaterClosed(LLFloater* floater) { - for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); - it != end_it; - ++it) - { - if (it->first.get() == floater) - { - it->second.disconnect(); - mHiddenFloaters.erase(it); - break; - } - } + for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); + it != end_it; + ++it) + { + if (it->first.get() == floater) + { + it->second.disconnect(); + mHiddenFloaters.erase(it); + break; + } + } } void LLFloaterView::hideAllFloaters() { - child_list_t child_list = *(getChildList()); + child_list_t child_list = *(getChildList()); - for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); - if (floaterp && floaterp->getVisible()) - { - floaterp->setVisible(false); - boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp)); - mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection)); - } - } + for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); + if (floaterp && floaterp->getVisible()) + { + floaterp->setVisible(false); + boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp)); + mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection)); + } + } } void LLFloaterView::showHiddenFloaters() { - for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); - it != end_it; - ++it) - { - LLFloater* floaterp = it->first.get(); - if (floaterp) - { - floaterp->setVisible(true); - } - it->second.disconnect(); - } - mHiddenFloaters.clear(); + for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end(); + it != end_it; + ++it) + { + LLFloater* floaterp = it->first.get(); + if (floaterp) + { + floaterp->setVisible(true); + } + it->second.disconnect(); + } + mHiddenFloaters.clear(); } BOOL LLFloaterView::allChildrenClosed() { - // see if there are any visible floaters (some floaters "close" - // by setting themselves invisible) - for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); + // see if there are any visible floaters (some floaters "close" + // by setting themselves invisible) + for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); - if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable()) - { - return false; - } - } - return true; + if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable()) + { + return false; + } + } + return true; } void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset) { - for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); + for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(*it); - if (floaterp && floaterp->isMinimized()) - { - floaterp->translate(x_offset, y_offset); - } - } + if (floaterp && floaterp->isMinimized()) + { + floaterp->translate(x_offset, y_offset); + } + } } void LLFloaterView::refresh() { - LLRect snap_rect = getSnapRect(); - if (snap_rect != mLastSnapRect) - { - reshape(getRect().getWidth(), getRect().getHeight(), TRUE); - } + LLRect snap_rect = getSnapRect(); + if (snap_rect != mLastSnapRect) + { + reshape(getRect().getWidth(), getRect().getHeight(), TRUE); + } - // Constrain children to be entirely on the screen - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it); - if (floaterp && floaterp->getVisible() ) - { - // minimized floaters are kept fully onscreen - adjustToFitScreen(floaterp, !floaterp->isMinimized()); - } - } + // Constrain children to be entirely on the screen + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it); + if (floaterp && floaterp->getVisible() ) + { + // minimized floaters are kept fully onscreen + adjustToFitScreen(floaterp, !floaterp->isMinimized()); + } + } } void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside, BOOL snap_in_toolbars/* = false*/) { - if (floater->getParent() != this) - { - // floater is hosted elsewhere, so ignore - return; - } - - if (floater->getDependee() && - floater->getDependee() == floater->getSnapTarget().get()) - { - // floater depends on other and snaps to it, so ignore - return; - } - - LLRect::tCoordType screen_width = getSnapRect().getWidth(); - LLRect::tCoordType screen_height = getSnapRect().getHeight(); - - // only automatically resize non-minimized, resizable floaters - if( floater->isResizable() && !floater->isMinimized() ) - { - LLRect view_rect = floater->getRect(); - S32 old_width = view_rect.getWidth(); - S32 old_height = view_rect.getHeight(); - S32 min_width; - S32 min_height; - floater->getResizeLimits( &min_width, &min_height ); - - // Make sure floater isn't already smaller than its min height/width? - S32 new_width = llmax( min_width, old_width ); - S32 new_height = llmax( min_height, old_height); - - if((new_width > screen_width) || (new_height > screen_height)) - { - // We have to make this window able to fit on screen - new_width = llmin(new_width, screen_width); - new_height = llmin(new_height, screen_height); - - // ...while respecting minimum width/height - new_width = llmax(new_width, min_width); - new_height = llmax(new_height, min_height); - - LLRect new_rect; - new_rect.setLeftTopAndSize(view_rect.mLeft,view_rect.mTop,new_width, new_height); - - floater->setShape(new_rect); - - if (floater->followsRight()) - { - floater->translate(old_width - new_width, 0); - } - - if (floater->followsTop()) - { - floater->translate(0, old_height - new_height); - } - } - } + if (floater->getParent() != this) + { + // floater is hosted elsewhere, so ignore + return; + } + + if (floater->getDependee() && + floater->getDependee() == floater->getSnapTarget().get()) + { + // floater depends on other and snaps to it, so ignore + return; + } + + LLRect::tCoordType screen_width = getSnapRect().getWidth(); + LLRect::tCoordType screen_height = getSnapRect().getHeight(); + + // only automatically resize non-minimized, resizable floaters + if( floater->isResizable() && !floater->isMinimized() ) + { + LLRect view_rect = floater->getRect(); + S32 old_width = view_rect.getWidth(); + S32 old_height = view_rect.getHeight(); + S32 min_width; + S32 min_height; + floater->getResizeLimits( &min_width, &min_height ); + + // Make sure floater isn't already smaller than its min height/width? + S32 new_width = llmax( min_width, old_width ); + S32 new_height = llmax( min_height, old_height); + + if((new_width > screen_width) || (new_height > screen_height)) + { + // We have to make this window able to fit on screen + new_width = llmin(new_width, screen_width); + new_height = llmin(new_height, screen_height); + + // ...while respecting minimum width/height + new_width = llmax(new_width, min_width); + new_height = llmax(new_height, min_height); + + LLRect new_rect; + new_rect.setLeftTopAndSize(view_rect.mLeft,view_rect.mTop,new_width, new_height); + + floater->setShape(new_rect); + + if (floater->followsRight()) + { + floater->translate(old_width - new_width, 0); + } + + if (floater->followsTop()) + { + floater->translate(0, old_height - new_height); + } + } + } const LLRect& constraint = snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(); S32 min_overlap_pixels = allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX; - floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels); + floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels); } void LLFloaterView::draw() { - refresh(); + refresh(); - // hide focused floater if in cycle mode, so that it can be drawn on top - LLFloater* focused_floater = getFocusedFloater(); + // hide focused floater if in cycle mode, so that it can be drawn on top + LLFloater* focused_floater = getFocusedFloater(); - if (mFocusCycleMode && focused_floater) - { - child_list_const_iter_t child_it = getChildList()->begin(); - for (;child_it != getChildList()->end(); ++child_it) - { - if ((*child_it) != focused_floater) - { - drawChild(*child_it); - } - } + if (mFocusCycleMode && focused_floater) + { + child_list_const_iter_t child_it = getChildList()->begin(); + for (;child_it != getChildList()->end(); ++child_it) + { + if ((*child_it) != focused_floater) + { + drawChild(*child_it); + } + } - drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET); - } - else - { - LLView::draw(); - } + drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET); + } + else + { + LLView::draw(); + } } LLRect LLFloaterView::getSnapRect() const { - LLRect snap_rect = getLocalRect(); + LLRect snap_rect = getLocalRect(); - LLView* snap_view = mSnapView.get(); - if (snap_view) - { - snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this); - } + LLView* snap_view = mSnapView.get(); + if (snap_view) + { + snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this); + } - return snap_rect; + return snap_rect; } LLFloater *LLFloaterView::getFocusedFloater() const { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - if ((*child_it)->isCtrl()) - { - LLFloater* ctrlp = dynamic_cast<LLFloater*>(*child_it); - if ( ctrlp && ctrlp->hasFocus() ) - { - return ctrlp; - } - } - } - return NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + if ((*child_it)->isCtrl()) + { + LLFloater* ctrlp = dynamic_cast<LLFloater*>(*child_it); + if ( ctrlp && ctrlp->hasFocus() ) + { + return ctrlp; + } + } + } + return NULL; } LLFloater *LLFloaterView::getFrontmost() const { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if ( viewp->getVisible() && !viewp->isDead()) - { - return (LLFloater *)viewp; - } - } - return NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if ( viewp->getVisible() && !viewp->isDead()) + { + return (LLFloater *)viewp; + } + } + return NULL; } LLFloater *LLFloaterView::getBackmost() const { - LLFloater* back_most = NULL; - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if ( viewp->getVisible() ) - { - back_most = (LLFloater *)viewp; - } - } - return back_most; + LLFloater* back_most = NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if ( viewp->getVisible() ) + { + back_most = (LLFloater *)viewp; + } + } + return back_most; } void LLFloaterView::syncFloaterTabOrder() { LLFloater* front_child = mFrontChildHandle.get(); - if (front_child && front_child->getIsChrome()) - return; - - // look for a visible modal dialog, starting from first - LLModalDialog* modal_dialog = NULL; - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLModalDialog* dialog = dynamic_cast<LLModalDialog*>(*child_it); - if (dialog && dialog->isModal() && dialog->getVisible()) - { - modal_dialog = dialog; - break; - } - } - - if (modal_dialog) - { - // If we have a visible modal dialog, make sure that it has focus - LLUI::getInstance()->addPopup(modal_dialog); - - if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) ) - { - modal_dialog->setFocus(TRUE); - } - - if( !gFocusMgr.childHasMouseCapture( modal_dialog ) ) - { - gFocusMgr.setMouseCapture( modal_dialog ); - } - } - else - { - // otherwise, make sure the focused floater is in the front of the child list - for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) - { - LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it); - if (gFocusMgr.childHasKeyboardFocus(floaterp)) - { + if (front_child && front_child->getIsChrome()) + return; + + // look for a visible modal dialog, starting from first + LLModalDialog* modal_dialog = NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLModalDialog* dialog = dynamic_cast<LLModalDialog*>(*child_it); + if (dialog && dialog->isModal() && dialog->getVisible()) + { + modal_dialog = dialog; + break; + } + } + + if (modal_dialog) + { + // If we have a visible modal dialog, make sure that it has focus + LLUI::getInstance()->addPopup(modal_dialog); + + if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) ) + { + modal_dialog->setFocus(TRUE); + } + + if( !gFocusMgr.childHasMouseCapture( modal_dialog ) ) + { + gFocusMgr.setMouseCapture( modal_dialog ); + } + } + else + { + // otherwise, make sure the focused floater is in the front of the child list + for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) + { + LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it); + if (gFocusMgr.childHasKeyboardFocus(floaterp)) + { LLFloater* front_child = mFrontChildHandle.get(); if (front_child != floaterp) { // Grab a list of the top floaters that want to stay on top of the focused floater - std::list<LLFloater*> listTop; - if (front_child && !front_child->canFocusStealFrontmost()) + std::list<LLFloater*> listTop; + if (front_child && !front_child->canFocusStealFrontmost()) { for (LLView* childp : *getChildList()) { - LLFloater* child_floaterp = static_cast<LLFloater*>(childp); + LLFloater* child_floaterp = static_cast<LLFloater*>(childp); if (child_floaterp->canFocusStealFrontmost()) break; - listTop.push_back(child_floaterp); + listTop.push_back(child_floaterp); } } bringToFront(floaterp, FALSE); // Restore top floaters - if (!listTop.empty()) - { - for (LLView* childp : listTop) - { - sendChildToFront(childp); - } + if (!listTop.empty()) + { + for (LLView* childp : listTop) + { + sendChildToFront(childp); + } mFrontChildHandle = listTop.back()->getHandle(); - } + } } - break; - } - } - } + break; + } + } + } } -LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const +LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const { - LLView* parentp = viewp->getParent(); + LLView* parentp = viewp->getParent(); - while(parentp && parentp != this) - { - viewp = parentp; - parentp = parentp->getParent(); - } + while(parentp && parentp != this) + { + viewp = parentp; + parentp = parentp->getParent(); + } - if (parentp == this) - { - return dynamic_cast<LLFloater*>(viewp); - } + if (parentp == this) + { + return dynamic_cast<LLFloater*>(viewp); + } - return NULL; + return NULL; } S32 LLFloaterView::getZOrder(LLFloater* child) { - S32 rv = 0; - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if(viewp == child) - { - break; - } - ++rv; - } - return rv; + S32 rv = 0; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if(viewp == child) + { + break; + } + ++rv; + } + return rv; } void LLFloaterView::pushVisibleAll(BOOL visible, const skip_list_t& skip_list) { - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *view = *child_iter; - if (skip_list.find(view) == skip_list.end()) - { - view->pushVisible(visible); - } - } + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *view = *child_iter; + if (skip_list.find(view) == skip_list.end()) + { + view->pushVisible(visible); + } + } - LLFloaterReg::blockShowFloaters(true); + LLFloaterReg::blockShowFloaters(true); } void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) { - // make a copy of the list since some floaters change their - // order in the childList when changing visibility. - child_list_t child_list_copy = *getChildList(); + // make a copy of the list since some floaters change their + // order in the childList when changing visibility. + child_list_t child_list_copy = *getChildList(); - for (child_list_const_iter_t child_iter = child_list_copy.begin(); - child_iter != child_list_copy.end(); ++child_iter) - { - LLView *view = *child_iter; - if (skip_list.find(view) == skip_list.end()) - { - view->popVisible(); - } - } + for (child_list_const_iter_t child_iter = child_list_copy.begin(); + child_iter != child_list_copy.end(); ++child_iter) + { + LLView *view = *child_iter; + if (skip_list.find(view) == skip_list.end()) + { + view->popVisible(); + } + } - LLFloaterReg::blockShowFloaters(false); + LLFloaterReg::blockShowFloaters(false); } void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect) { - switch (tb) - { - case LLToolBarEnums::TOOLBAR_LEFT: - mToolbarLeftRect = toolbar_rect; - break; - case LLToolBarEnums::TOOLBAR_BOTTOM: - mToolbarBottomRect = toolbar_rect; - break; - case LLToolBarEnums::TOOLBAR_RIGHT: - mToolbarRightRect = toolbar_rect; - break; - default: - LL_WARNS() << "setToolbarRect() passed odd toolbar number " << (S32) tb << LL_ENDL; - break; - } + switch (tb) + { + case LLToolBarEnums::TOOLBAR_LEFT: + mToolbarLeftRect = toolbar_rect; + break; + case LLToolBarEnums::TOOLBAR_BOTTOM: + mToolbarBottomRect = toolbar_rect; + break; + case LLToolBarEnums::TOOLBAR_RIGHT: + mToolbarRightRect = toolbar_rect; + break; + default: + LL_WARNS() << "setToolbarRect() passed odd toolbar number " << (S32) tb << LL_ENDL; + break; + } } void LLFloater::setInstanceName(const std::string& name) { - if (name != mInstanceName) - { - llassert_always(mInstanceName.empty()); - mInstanceName = name; - if (!mInstanceName.empty()) - { - std::string ctrl_name = getControlName(mInstanceName, mKey); - initRectControl(); - if (!mVisibilityControl.empty()) - { - mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name); - } - if(!mDocStateControl.empty()) - { - mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name); - } - } + if (name != mInstanceName) + { + llassert_always(mInstanceName.empty()); + mInstanceName = name; + if (!mInstanceName.empty()) + { + std::string ctrl_name = getControlName(mInstanceName, mKey); + initRectControl(); + if (!mVisibilityControl.empty()) + { + mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name); + } + if(!mDocStateControl.empty()) + { + mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name); + } + } } } void LLFloater::setKey(const LLSD& newkey) { - // Note: We don't have to do anything special with registration when we change keys - mKey = newkey; + // Note: We don't have to do anything special with registration when we change keys + mKey = newkey; } //static void LLFloater::setupParamsForExport(Params& p, LLView* parent) { - // Do rectangle munging to topleft layout first - LLPanel::setupParamsForExport(p, parent); + // Do rectangle munging to topleft layout first + LLPanel::setupParamsForExport(p, parent); - // Copy the rectangle out to apply layout constraints - LLRect rect = p.rect; + // Copy the rectangle out to apply layout constraints + LLRect rect = p.rect; - // Null out other settings - p.rect.left.setProvided(false); - p.rect.top.setProvided(false); - p.rect.right.setProvided(false); - p.rect.bottom.setProvided(false); + // Null out other settings + p.rect.left.setProvided(false); + p.rect.top.setProvided(false); + p.rect.right.setProvided(false); + p.rect.bottom.setProvided(false); - // Explicitly set width/height - p.rect.width.set( rect.getWidth(), true ); - p.rect.height.set( rect.getHeight(), true ); + // Explicitly set width/height + p.rect.width.set( rect.getWidth(), true ); + p.rect.height.set( rect.getHeight(), true ); - // If you can't resize this floater, don't export min_height - // and min_width - bool can_resize = p.can_resize; - if (!can_resize) - { - p.min_height.setProvided(false); - p.min_width.setProvided(false); - } + // If you can't resize this floater, don't export min_height + // and min_width + bool can_resize = p.can_resize; + if (!can_resize) + { + p.min_height.setProvided(false); + p.min_width.setProvided(false); + } } void LLFloater::initFromParams(const LLFloater::Params& p) { - // *NOTE: We have too many classes derived from LLFloater to retrofit them - // all to pass in params via constructors. So we use this method. - - // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible - LLPanel::initFromParams(p); - - // override any follows flags - if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED) - { - setFollows(FOLLOWS_NONE); - } - - mTitle = p.title; - mShortTitle = p.short_title; - applyTitle(); - - setCanTearOff(p.can_tear_off); - setCanMinimize(p.can_minimize); - setCanClose(p.can_close); - setCanDock(p.can_dock); - setCanResize(p.can_resize); - setResizeLimits(p.min_width, p.min_height); - - mDragOnLeft = p.can_drag_on_left; - mHeaderHeight = p.header_height; - mLegacyHeaderHeight = p.legacy_header_height; - mSingleInstance = p.single_instance; - mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; - - mDefaultRelativeX = p.rel_x; - mDefaultRelativeY = p.rel_y; - - mPositioning = p.positioning; - mAutoClose = p.auto_close; - - mSaveRect = p.save_rect; - if (p.save_visibility) - { - mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set - } - if(p.save_dock_state) - { - mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set - } - - // open callback - if (p.open_callback.isProvided()) - { - setOpenCallback(initCommitCallback(p.open_callback)); - } - // close callback - if (p.close_callback.isProvided()) - { - setCloseCallback(initCommitCallback(p.close_callback)); - } - - if (mDragHandle) - { - mDragHandle->setTitleVisible(p.show_title); - } -} - -boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t(); - return mMinimizeSignal->connect(cb); + // *NOTE: We have too many classes derived from LLFloater to retrofit them + // all to pass in params via constructors. So we use this method. + + // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible + LLPanel::initFromParams(p); + + // override any follows flags + if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED) + { + setFollows(FOLLOWS_NONE); + } + + mTitle = p.title; + mShortTitle = p.short_title; + applyTitle(); + + setCanTearOff(p.can_tear_off); + setCanMinimize(p.can_minimize); + setCanClose(p.can_close); + setCanDock(p.can_dock); + setCanResize(p.can_resize); + setResizeLimits(p.min_width, p.min_height); + + mDragOnLeft = p.can_drag_on_left; + mHeaderHeight = p.header_height; + mLegacyHeaderHeight = p.legacy_header_height; + mSingleInstance = p.single_instance; + mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; + + mDefaultRelativeX = p.rel_x; + mDefaultRelativeY = p.rel_y; + + mPositioning = p.positioning; + mAutoClose = p.auto_close; + + mSaveRect = p.save_rect; + if (p.save_visibility) + { + mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set + } + if(p.save_dock_state) + { + mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set + } + + // open callback + if (p.open_callback.isProvided()) + { + setOpenCallback(initCommitCallback(p.open_callback)); + } + // close callback + if (p.close_callback.isProvided()) + { + setCloseCallback(initCommitCallback(p.close_callback)); + } + + if (mDragHandle) + { + mDragHandle->setTitleVisible(p.show_title); + } +} + +boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t(); + return mMinimizeSignal->connect(cb); } boost::signals2::connection LLFloater::setOpenCallback( const commit_signal_t::slot_type& cb ) { - return mOpenSignal.connect(cb); + return mOpenSignal.connect(cb); } boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb ) { - return mCloseSignal.connect(cb); + return mCloseSignal.connect(cb); } bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node) { LL_PROFILE_ZONE_SCOPED; - Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>()); - Params params(default_params); - - LLXUIParser parser; - parser.readXUI(node, params, filename); // *TODO: Error checking - - std::string xml_filename = params.filename; - - if (!xml_filename.empty()) - { - LLXMLNodePtr referenced_xml; - - if (output_node) - { - //if we are exporting, we want to export the current xml - //not the referenced xml - Params output_params; - parser.readXUI(node, output_params, LLUICtrlFactory::getInstance()->getCurFileName()); - setupParamsForExport(output_params, parent); - output_node->setName(node->getName()->mString); - parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); - return TRUE; - } - - LLUICtrlFactory::instance().pushFileName(xml_filename); - - if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) - { - LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; - - return FALSE; - } - - Params referenced_params; - parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName()); - params.fillFrom(referenced_params); - - // add children using dimensions from referenced xml for consistent layout - setShape(params.rect); - LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); - - LLUICtrlFactory::instance().popFileName(); - } - - - if (output_node) - { - Params output_params(params); - setupParamsForExport(output_params, parent); - output_node->setName(node->getName()->mString); - parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); - } - - // Default floater position to top-left corner of screen - // However, some legacy floaters have explicit top or bottom - // coordinates set, so respect their wishes. - if (!params.rect.top.isProvided() && !params.rect.bottom.isProvided()) - { - params.rect.top.set(0); - } - if (!params.rect.left.isProvided() && !params.rect.right.isProvided()) - { - params.rect.left.set(0); - } - params.from_xui = true; - applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect()); - initFromParams(params); - - initFloater(params); - - LLMultiFloater* last_host = LLFloater::getFloaterHost(); - if (node->hasName("multi_floater")) - { - LLFloater::setFloaterHost((LLMultiFloater*) this); - } - - LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); - - if (node->hasName("multi_floater")) - { - LLFloater::setFloaterHost(last_host); - } - - // HACK: When we changed the header height to 25 pixels in Viewer 2, rather - // than re-layout all the floaters we use this value in pixels to make the - // whole floater bigger and change the top-left coordinate for widgets. - // The goal is to eventually set mLegacyHeaderHeight to zero, which would - // make the top-left corner for widget layout the same as the top-left - // corner of the window's content area. James - S32 header_stretch = (mHeaderHeight - mLegacyHeaderHeight); - if (header_stretch > 0) - { - // Stretch the floater vertically, don't move widgets - LLRect rect = getRect(); - rect.mTop += header_stretch; - - // This will also update drag handle, title bar, close box, etc. - setRect(rect); - } - - BOOL result; - result = postBuild(); - - if (!result) - { - LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL; - } - - applyRectControl(); // If we have a saved rect control, apply it - gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen - - moveResizeHandlesToFront(); - - applyDockState(); - - return true; // *TODO: Error checking + Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>()); + Params params(default_params); + + LLXUIParser parser; + parser.readXUI(node, params, filename); // *TODO: Error checking + + std::string xml_filename = params.filename; + + if (!xml_filename.empty()) + { + LLXMLNodePtr referenced_xml; + + if (output_node) + { + //if we are exporting, we want to export the current xml + //not the referenced xml + Params output_params; + parser.readXUI(node, output_params, LLUICtrlFactory::getInstance()->getCurFileName()); + setupParamsForExport(output_params, parent); + output_node->setName(node->getName()->mString); + parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); + return TRUE; + } + + LLUICtrlFactory::instance().pushFileName(xml_filename); + + if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) + { + LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; + + return FALSE; + } + + Params referenced_params; + parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName()); + params.fillFrom(referenced_params); + + // add children using dimensions from referenced xml for consistent layout + setShape(params.rect); + LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); + + LLUICtrlFactory::instance().popFileName(); + } + + + if (output_node) + { + Params output_params(params); + setupParamsForExport(output_params, parent); + output_node->setName(node->getName()->mString); + parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); + } + + // Default floater position to top-left corner of screen + // However, some legacy floaters have explicit top or bottom + // coordinates set, so respect their wishes. + if (!params.rect.top.isProvided() && !params.rect.bottom.isProvided()) + { + params.rect.top.set(0); + } + if (!params.rect.left.isProvided() && !params.rect.right.isProvided()) + { + params.rect.left.set(0); + } + params.from_xui = true; + applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect()); + initFromParams(params); + + initFloater(params); + + LLMultiFloater* last_host = LLFloater::getFloaterHost(); + if (node->hasName("multi_floater")) + { + LLFloater::setFloaterHost((LLMultiFloater*) this); + } + + LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); + + if (node->hasName("multi_floater")) + { + LLFloater::setFloaterHost(last_host); + } + + // HACK: When we changed the header height to 25 pixels in Viewer 2, rather + // than re-layout all the floaters we use this value in pixels to make the + // whole floater bigger and change the top-left coordinate for widgets. + // The goal is to eventually set mLegacyHeaderHeight to zero, which would + // make the top-left corner for widget layout the same as the top-left + // corner of the window's content area. James + S32 header_stretch = (mHeaderHeight - mLegacyHeaderHeight); + if (header_stretch > 0) + { + // Stretch the floater vertically, don't move widgets + LLRect rect = getRect(); + rect.mTop += header_stretch; + + // This will also update drag handle, title bar, close box, etc. + setRect(rect); + } + + BOOL result; + result = postBuild(); + + if (!result) + { + LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL; + } + + applyRectControl(); // If we have a saved rect control, apply it + gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen + + moveResizeHandlesToFront(); + + applyDockState(); + + return true; // *TODO: Error checking } bool LLFloater::isShown() const @@ -3501,7 +3501,7 @@ bool LLFloater::isShown() const bool LLFloater::isDetachedAndNotMinimized() { - return !getHost() && !isMinimized(); + return !getHost() && !isMinimized(); } /* static */ @@ -3525,211 +3525,211 @@ bool LLFloater::isVisible(const LLFloater* floater) bool LLFloater::buildFromFile(const std::string& filename) { LL_PROFILE_ZONE_SCOPED; - LLXMLNodePtr root; - - if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) - { - LL_WARNS() << "Couldn't find (or parse) floater from: " << filename << LL_ENDL; - return false; - } - - // root must be called floater - if( !(root->hasName("floater") || root->hasName("multi_floater")) ) - { - LL_WARNS() << "Root node should be named floater in: " << filename << LL_ENDL; - return false; - } - - bool res = true; - - LL_DEBUGS() << "Building floater " << filename << LL_ENDL; - LLUICtrlFactory::instance().pushFileName(filename); - { - if (!getFactoryMap().empty()) - { - LLPanel::sFactoryStack.push_front(&getFactoryMap()); - } - - // for local registry callbacks; define in constructor, referenced in XUI or postBuild - getCommitCallbackRegistrar().pushScope(); - getEnableCallbackRegistrar().pushScope(); - - res = initFloaterXML(root, getParent(), filename, NULL); - - setXMLFilename(filename); - - getCommitCallbackRegistrar().popScope(); - getEnableCallbackRegistrar().popScope(); - - if (!getFactoryMap().empty()) - { - LLPanel::sFactoryStack.pop_front(); - } - } - LLUICtrlFactory::instance().popFileName(); - - return res; + LLXMLNodePtr root; + + if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) + { + LL_WARNS() << "Couldn't find (or parse) floater from: " << filename << LL_ENDL; + return false; + } + + // root must be called floater + if( !(root->hasName("floater") || root->hasName("multi_floater")) ) + { + LL_WARNS() << "Root node should be named floater in: " << filename << LL_ENDL; + return false; + } + + bool res = true; + + LL_DEBUGS() << "Building floater " << filename << LL_ENDL; + LLUICtrlFactory::instance().pushFileName(filename); + { + if (!getFactoryMap().empty()) + { + LLPanel::sFactoryStack.push_front(&getFactoryMap()); + } + + // for local registry callbacks; define in constructor, referenced in XUI or postBuild + getCommitCallbackRegistrar().pushScope(); + getEnableCallbackRegistrar().pushScope(); + + res = initFloaterXML(root, getParent(), filename, NULL); + + setXMLFilename(filename); + + getCommitCallbackRegistrar().popScope(); + getEnableCallbackRegistrar().popScope(); + + if (!getFactoryMap().empty()) + { + LLPanel::sFactoryStack.pop_front(); + } + } + LLUICtrlFactory::instance().popFileName(); + + return res; } void LLFloater::stackWith(LLFloater& other) { - static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16); - - LLRect next_rect; - if (other.getHost()) - { - next_rect = other.getHost()->getRect(); - } - else - { - next_rect = other.getRect(); - } - next_rect.translate(floater_offset, -floater_offset); - - const LLRect& rect = getControlGroup()->getRect(mRectControl); - if (rect.notEmpty() && !mDefaultRectForGroup && mResizable) - { - next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); - } - else - { - next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); - } - setShape(next_rect); - - if (!other.getHost()) - { - other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; - other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); - } + static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16); + + LLRect next_rect; + if (other.getHost()) + { + next_rect = other.getHost()->getRect(); + } + else + { + next_rect = other.getRect(); + } + next_rect.translate(floater_offset, -floater_offset); + + const LLRect& rect = getControlGroup()->getRect(mRectControl); + if (rect.notEmpty() && !mDefaultRectForGroup && mResizable) + { + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + } + else + { + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); + } + setShape(next_rect); + + if (!other.getHost()) + { + other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; + other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); + } } void LLFloater::applyRelativePosition() { - LLRect snap_rect = gFloaterView->getSnapRect(); - LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); - snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); - LLRect floater_screen_rect = calcScreenRect(); + LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + LLRect floater_screen_rect = calcScreenRect(); - LLCoordGL new_center = mPosition.convert(); - LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY()); - translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); + LLCoordGL new_center = mPosition.convert(); + LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY()); + translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY); } LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater) -: coord_t((S32)x, (S32)y) +: coord_t((S32)x, (S32)y) { - mFloater = floater.getHandle(); + mFloater = floater.getHandle(); } LLCoordFloater::LLCoordFloater(const LLCoordCommon& other, LLFloater& floater) { - mFloater = floater.getHandle(); - convertFromCommon(other); + mFloater = floater.getHandle(); + convertFromCommon(other); } LLCoordFloater& LLCoordFloater::operator=(const LLCoordFloater& other) { - mFloater = other.mFloater; - coord_t::operator =(other); - return *this; + mFloater = other.mFloater; + coord_t::operator =(other); + return *this; } void LLCoordFloater::setFloater(LLFloater& floater) { - mFloater = floater.getHandle(); + mFloater = floater.getHandle(); } -bool LLCoordFloater::operator==(const LLCoordFloater& other) const -{ - return mX == other.mX && mY == other.mY && mFloater == other.mFloater; +bool LLCoordFloater::operator==(const LLCoordFloater& other) const +{ + return mX == other.mX && mY == other.mY && mFloater == other.mFloater; } LLCoordCommon LL_COORD_FLOATER::convertToCommon() const { - const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); - - LLRect snap_rect = gFloaterView->getSnapRect(); - LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); - snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); - - LLFloater* floaterp = mFloater.get(); - S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; - S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; - LLCoordCommon out; - if (self.mX < -0.5f) - { - out.mX = ll_round(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft)); - } - else if (self.mX > 0.5f) - { - out.mX = ll_round(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS)); - } - else - { - out.mX = ll_round(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width)); - } - - if (self.mY < -0.5f) - { - out.mY = ll_round(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom)); - } - else if (self.mY > 0.5f) - { - out.mY = ll_round(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS)); - } - else - { - out.mY = ll_round(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height)); - } - - // return center point instead of lower left - out.mX += floater_width / 2; - out.mY += floater_height / 2; - - return out; + const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); + + LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + + LLFloater* floaterp = mFloater.get(); + S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; + S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; + LLCoordCommon out; + if (self.mX < -0.5f) + { + out.mX = ll_round(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft)); + } + else if (self.mX > 0.5f) + { + out.mX = ll_round(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS)); + } + else + { + out.mX = ll_round(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width)); + } + + if (self.mY < -0.5f) + { + out.mY = ll_round(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom)); + } + else if (self.mY > 0.5f) + { + out.mY = ll_round(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS)); + } + else + { + out.mY = ll_round(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height)); + } + + // return center point instead of lower left + out.mX += floater_width / 2; + out.mY += floater_height / 2; + + return out; } void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from) { - LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); - LLRect snap_rect = gFloaterView->getSnapRect(); - LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); - snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); - - - LLFloater* floaterp = mFloater.get(); - S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; - S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; - - S32 from_x = from.mX - floater_width / 2; - S32 from_y = from.mY - floater_height / 2; - - if (from_x < snap_rect.mLeft) - { - self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f); - } - else if (from_x + floater_width > snap_rect.mRight) - { - self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); - } - else - { - self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f); - } - - if (from_y < snap_rect.mBottom) - { - self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f); - } - else if (from_y + floater_height > snap_rect.mTop) - { - self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); - } - else - { - self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f); - } + LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this)); + LLRect snap_rect = gFloaterView->getSnapRect(); + LLRect floater_view_screen_rect = gFloaterView->calcScreenRect(); + snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom); + + + LLFloater* floaterp = mFloater.get(); + S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0; + S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0; + + S32 from_x = from.mX - floater_width / 2; + S32 from_y = from.mY - floater_height / 2; + + if (from_x < snap_rect.mLeft) + { + self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f); + } + else if (from_x + floater_width > snap_rect.mRight) + { + self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); + } + else + { + self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f); + } + + if (from_y < snap_rect.mBottom) + { + self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f); + } + else if (from_y + floater_height > snap_rect.mTop) + { + self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f); + } + else + { + self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f); + } } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 39957386df..dcc9af4c6e 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloater.h * @brief LLFloater base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -61,484 +61,488 @@ const BOOL CLOSE_NO = FALSE; const BOOL ADJUST_VERTICAL_YES = TRUE; const BOOL ADJUST_VERTICAL_NO = FALSE; +const F32 CONTEXT_CONE_IN_ALPHA = 0.f; +const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; +const F32 CONTEXT_CONE_FADE_TIME = .08f; + namespace LLFloaterEnums { - enum EOpenPositioning - { - POSITIONING_RELATIVE, - POSITIONING_CASCADING, - POSITIONING_CASCADE_GROUP, - POSITIONING_CENTERED, - POSITIONING_SPECIFIED, - POSITIONING_COUNT - }; + enum EOpenPositioning + { + POSITIONING_RELATIVE, + POSITIONING_CASCADING, + POSITIONING_CASCADE_GROUP, + POSITIONING_CENTERED, + POSITIONING_SPECIFIED, + POSITIONING_COUNT + }; } namespace LLInitParam { - template<> - struct TypeValues<LLFloaterEnums::EOpenPositioning> : public TypeValuesHelper<LLFloaterEnums::EOpenPositioning> - { - static void declareValues(); - }; + template<> + struct TypeValues<LLFloaterEnums::EOpenPositioning> : public TypeValuesHelper<LLFloaterEnums::EOpenPositioning> + { + static void declareValues(); + }; } struct LL_COORD_FLOATER { - typedef F32 value_t; + typedef F32 value_t; - LLCoordCommon convertToCommon() const; - void convertFromCommon(const LLCoordCommon& from); + LLCoordCommon convertToCommon() const; + void convertFromCommon(const LLCoordCommon& from); protected: - LLHandle<LLFloater> mFloater; + LLHandle<LLFloater> mFloater; }; struct LLCoordFloater : LLCoord<LL_COORD_FLOATER> { - typedef LLCoord<LL_COORD_FLOATER> coord_t; + typedef LLCoord<LL_COORD_FLOATER> coord_t; - LLCoordFloater() {} - LLCoordFloater(F32 x, F32 y, LLFloater& floater); - LLCoordFloater(const LLCoordCommon& other, LLFloater& floater); + LLCoordFloater() {} + LLCoordFloater(F32 x, F32 y, LLFloater& floater); + LLCoordFloater(const LLCoordCommon& other, LLFloater& floater); - LLCoordFloater& operator=(const LLCoordCommon& other) - { - convertFromCommon(other); - return *this; - } + LLCoordFloater& operator=(const LLCoordCommon& other) + { + convertFromCommon(other); + return *this; + } - LLCoordFloater& operator=(const LLCoordFloater& other); + LLCoordFloater& operator=(const LLCoordFloater& other); - bool operator==(const LLCoordFloater& other) const; - bool operator!=(const LLCoordFloater& other) const { return !(*this == other); } + bool operator==(const LLCoordFloater& other) const; + bool operator!=(const LLCoordFloater& other) const { return !(*this == other); } - void setFloater(LLFloater& floater); + void setFloater(LLFloater& floater); }; class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater> { - friend class LLFloaterView; - friend class LLFloaterReg; - friend class LLMultiFloater; + friend class LLFloaterView; + friend class LLFloaterReg; + friend class LLMultiFloater; public: - struct KeyCompare - { -// static bool compare(const LLSD& a, const LLSD& b); - static bool equate(const LLSD& a, const LLSD& b); + struct KeyCompare + { +// static bool compare(const LLSD& a, const LLSD& b); + static bool equate(const LLSD& a, const LLSD& b); /*==========================================================================*| - bool operator()(const LLSD& a, const LLSD& b) const - { - return compare(a, b); - } + bool operator()(const LLSD& a, const LLSD& b) const + { + return compare(a, b); + } |*==========================================================================*/ - }; - - enum EFloaterButton - { - BUTTON_CLOSE = 0, - BUTTON_RESTORE, - BUTTON_MINIMIZE, - BUTTON_TEAR_OFF, - BUTTON_DOCK, - BUTTON_HELP, - BUTTON_COUNT - }; - - struct Params - : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<std::string> title, - short_title; - - Optional<bool> single_instance, - reuse_instance, - can_resize, - can_minimize, - can_close, - can_drag_on_left, - can_tear_off, - save_rect, - save_visibility, - save_dock_state, - can_dock, - show_title, - auto_close; - - Optional<LLFloaterEnums::EOpenPositioning> positioning; - - Optional<S32> header_height, - legacy_header_height; // HACK see initFromXML() - - Optional<F32> rel_x, - rel_y; - - // Images for top-right controls - Optional<LLUIImage*> close_image, - restore_image, - minimize_image, - tear_off_image, - dock_image, - help_image; - Optional<LLUIImage*> close_pressed_image, - restore_pressed_image, - minimize_pressed_image, - tear_off_pressed_image, - dock_pressed_image, - help_pressed_image; - - Optional<CommitCallbackParam> open_callback, - close_callback; - - Ignored follows; - - Params(); - }; - - // use this to avoid creating your own default LLFloater::Param instance - static const Params& getDefaultParams(); - - // Load translations for tooltips for standard buttons - static void initClass(); - - LLFloater(const LLSD& key, const Params& params = getDefaultParams()); - - virtual ~LLFloater(); - - // Don't export top/left for rect, only height/width - static void setupParamsForExport(Params& p, LLView* parent); - bool buildFromFile(const std::string &filename); - - boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setOpenCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb ); - - void initFromParams(const LLFloater::Params& p); - bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL); - - /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); - /*virtual*/ BOOL canSnapTo(const LLView* other_view); - /*virtual*/ void setSnappedTo(const LLView* snap_view); - /*virtual*/ void setFocus( BOOL b ); - /*virtual*/ void setIsChrome(BOOL is_chrome); - /*virtual*/ void setRect(const LLRect &rect); + }; + + enum EFloaterButton + { + BUTTON_CLOSE = 0, + BUTTON_RESTORE, + BUTTON_MINIMIZE, + BUTTON_TEAR_OFF, + BUTTON_DOCK, + BUTTON_HELP, + BUTTON_COUNT + }; + + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<std::string> title, + short_title; + + Optional<bool> single_instance, + reuse_instance, + can_resize, + can_minimize, + can_close, + can_drag_on_left, + can_tear_off, + save_rect, + save_visibility, + save_dock_state, + can_dock, + show_title, + auto_close; + + Optional<LLFloaterEnums::EOpenPositioning> positioning; + + Optional<S32> header_height, + legacy_header_height; // HACK see initFromXML() + + Optional<F32> rel_x, + rel_y; + + // Images for top-right controls + Optional<LLUIImage*> close_image, + restore_image, + minimize_image, + tear_off_image, + dock_image, + help_image; + Optional<LLUIImage*> close_pressed_image, + restore_pressed_image, + minimize_pressed_image, + tear_off_pressed_image, + dock_pressed_image, + help_pressed_image; + + Optional<CommitCallbackParam> open_callback, + close_callback; + + Ignored follows; + + Params(); + }; + + // use this to avoid creating your own default LLFloater::Param instance + static const Params& getDefaultParams(); + + // Load translations for tooltips for standard buttons + static void initClass(); + + LLFloater(const LLSD& key, const Params& params = getDefaultParams()); + + virtual ~LLFloater(); + + // Don't export top/left for rect, only height/width + static void setupParamsForExport(Params& p, LLView* parent); + bool buildFromFile(const std::string &filename); + + boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setOpenCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb ); + + void initFromParams(const LLFloater::Params& p); + bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL); + + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); + /*virtual*/ BOOL canSnapTo(const LLView* other_view); + /*virtual*/ void setSnappedTo(const LLView* snap_view); + /*virtual*/ void setFocus( BOOL b ); + /*virtual*/ void setIsChrome(BOOL is_chrome); + /*virtual*/ void setRect(const LLRect &rect); void setIsSingleInstance(BOOL is_single_instance); BOOL getIsSingleInstance() { return mSingleInstance; } - void initFloater(const Params& p); - - void openFloater(const LLSD& key = LLSD()); - - // If allowed, close the floater cleanly, releasing focus. - virtual void closeFloater(bool app_quitting = false); - - // Close the floater or its host. Use when hidding or toggling a floater instance. - virtual void closeHostedFloater(); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void translate(S32 x, S32 y); - - // Release keyboard and mouse focus - void releaseFocus(); - - // moves to center of gFloaterView - void center(); - - LLMultiFloater* getHost(); - bool isDetachedAndNotMinimized(); - - void applyTitle(); - std::string getCurrentTitle() const; - void setTitle( const std::string& title); - std::string getTitle() const; - void setShortTitle( const std::string& short_title ); - std::string getShortTitle() const; - virtual void setMinimized(BOOL b); - void moveResizeHandlesToFront(); - void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE); - void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE); - LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); } - void removeDependentFloater(LLFloater* dependent); - void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels); - BOOL isMinimized() const { return mMinimized; } - /// isShown() differs from getVisible() in that isShown() also considers - /// isMinimized(). isShown() is true only if visible and not minimized. - bool isShown() const; - /// The static isShown() can accept a NULL pointer (which of course - /// returns false). When non-NULL, it calls the non-static isShown(). - static bool isShown(const LLFloater* floater); - static bool isVisible(const LLFloater* floater); - static bool isMinimized(const LLFloater* floater); - BOOL isFirstLook() { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts - virtual BOOL isFrontmost(); - BOOL isDependent() { return !mDependeeHandle.isDead(); } - void setCanMinimize(BOOL can_minimize); - void setCanClose(BOOL can_close); - void setCanTearOff(BOOL can_tear_off); - virtual void setCanResize(BOOL can_resize); - void setCanDrag(BOOL can_drag); - bool getCanDrag(); - void setHost(LLMultiFloater* host); - BOOL isResizable() const { return mResizable; } - void setResizeLimits( S32 min_width, S32 min_height ); - void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } - - static std::string getControlName(const std::string& name, const LLSD& key); - static LLControlGroup* getControlGroup(); - - bool isMinimizeable() const{ return mCanMinimize; } - bool isCloseable() const{ return mCanClose; } - bool isDragOnLeft() const{ return mDragOnLeft; } - S32 getMinWidth() const{ return mMinWidth; } - S32 getMinHeight() const{ return mMinHeight; } - S32 getHeaderHeight() const { return mHeaderHeight; } - - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(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 handleScrollWheel(S32 x, S32 y, S32 mask); - - virtual void draw(); - virtual void drawShadow(LLPanel* panel); - - virtual void onOpen(const LLSD& key) {} - virtual void onClose(bool app_quitting) {} - - // This cannot be "const" until all derived floater canClose() - // methods are const as well. JC - virtual BOOL canClose() { return TRUE; } - - /*virtual*/ void setVisible(BOOL visible); // do not override - /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override - - bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; } - void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; } - - void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE); - virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); - - // Defaults to false. - virtual BOOL canSaveAs() const { return FALSE; } - - virtual void saveAs() {} - - void setSnapTarget(LLHandle<LLFloater> handle) { mSnappedTo = handle; } - void clearSnapTarget() { mSnappedTo.markDead(); } - LLHandle<LLFloater> getSnapTarget() const { return mSnappedTo; } - - LLHandle<LLFloater> getHandle() const { return getDerivedHandle<LLFloater>(); } - const LLSD& getKey() { return mKey; } - virtual bool matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); } - - const std::string& getInstanceName() { return mInstanceName; } - - bool isDockable() const { return mCanDock; } - void setCanDock(bool b); - - bool isDocked() const { return mDocked; } - virtual void setDocked(bool docked, bool pop_on_undock = true); - - virtual void setTornOff(bool torn_off) { mTornOff = torn_off; } - bool isTornOff() {return mTornOff;} - void setOpenPositioning(LLFloaterEnums::EOpenPositioning pos) {mPositioning = pos;} - - - // Close the floater returned by getFrontmostClosableFloater() and - // handle refocusing. - static void closeFrontmostFloater(); + void initFloater(const Params& p); + + void openFloater(const LLSD& key = LLSD()); + + // If allowed, close the floater cleanly, releasing focus. + virtual void closeFloater(bool app_quitting = false); + + // Close the floater or its host. Use when hidding or toggling a floater instance. + virtual void closeHostedFloater(); + + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void translate(S32 x, S32 y); + + // Release keyboard and mouse focus + void releaseFocus(); + + // moves to center of gFloaterView + void center(); + + LLMultiFloater* getHost(); + bool isDetachedAndNotMinimized(); + + void applyTitle(); + std::string getCurrentTitle() const; + void setTitle( const std::string& title); + std::string getTitle() const; + void setShortTitle( const std::string& short_title ); + std::string getShortTitle() const; + virtual void setMinimized(BOOL b); + void moveResizeHandlesToFront(); + void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE); + void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE); + LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); } + void removeDependentFloater(LLFloater* dependent); + void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels); + BOOL isMinimized() const { return mMinimized; } + /// isShown() differs from getVisible() in that isShown() also considers + /// isMinimized(). isShown() is true only if visible and not minimized. + bool isShown() const; + /// The static isShown() can accept a NULL pointer (which of course + /// returns false). When non-NULL, it calls the non-static isShown(). + static bool isShown(const LLFloater* floater); + static bool isVisible(const LLFloater* floater); + static bool isMinimized(const LLFloater* floater); + BOOL isFirstLook() { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts + virtual BOOL isFrontmost(); + BOOL isDependent() { return !mDependeeHandle.isDead(); } + void setCanMinimize(BOOL can_minimize); + void setCanClose(BOOL can_close); + void setCanTearOff(BOOL can_tear_off); + virtual void setCanResize(BOOL can_resize); + void setCanDrag(BOOL can_drag); + bool getCanDrag(); + void setHost(LLMultiFloater* host); + BOOL isResizable() const { return mResizable; } + void setResizeLimits( S32 min_width, S32 min_height ); + void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } + + static std::string getControlName(const std::string& name, const LLSD& key); + static LLControlGroup* getControlGroup(); + + bool isMinimizeable() const{ return mCanMinimize; } + bool isCloseable() const{ return mCanClose; } + bool isDragOnLeft() const{ return mDragOnLeft; } + S32 getMinWidth() const{ return mMinWidth; } + S32 getMinHeight() const{ return mMinHeight; } + S32 getHeaderHeight() const { return mHeaderHeight; } + + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(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 handleScrollWheel(S32 x, S32 y, S32 mask); + + virtual void draw(); + virtual void drawShadow(LLPanel* panel); + + virtual void onOpen(const LLSD& key) {} + virtual void onClose(bool app_quitting) {} + + // This cannot be "const" until all derived floater canClose() + // methods are const as well. JC + virtual BOOL canClose() { return TRUE; } + + /*virtual*/ void setVisible(BOOL visible); // do not override + /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override + + bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; } + void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; } + + void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE); + virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); + + // Defaults to false. + virtual BOOL canSaveAs() const { return FALSE; } + + virtual void saveAs() {} + + void setSnapTarget(LLHandle<LLFloater> handle) { mSnappedTo = handle; } + void clearSnapTarget() { mSnappedTo.markDead(); } + LLHandle<LLFloater> getSnapTarget() const { return mSnappedTo; } + + LLHandle<LLFloater> getHandle() const { return getDerivedHandle<LLFloater>(); } + const LLSD& getKey() { return mKey; } + virtual bool matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); } + + const std::string& getInstanceName() { return mInstanceName; } + + bool isDockable() const { return mCanDock; } + void setCanDock(bool b); + + bool isDocked() const { return mDocked; } + virtual void setDocked(bool docked, bool pop_on_undock = true); + + virtual void setTornOff(bool torn_off) { mTornOff = torn_off; } + bool isTornOff() {return mTornOff;} + void setOpenPositioning(LLFloaterEnums::EOpenPositioning pos) {mPositioning = pos;} + + + // Close the floater returned by getFrontmostClosableFloater() and + // handle refocusing. + static void closeFrontmostFloater(); static bool isQuitRequested() { return sQuitting; } -// LLNotification::Params contextualNotification(const std::string& name) -// { -// return LLNotification::Params(name).context(mNotificationContext); -// } +// LLNotification::Params contextualNotification(const std::string& name) +// { +// return LLNotification::Params(name).context(mNotificationContext); +// } + + static void onClickClose(LLFloater* floater); + static void onClickMinimize(LLFloater* floater); + static void onClickTearOff(LLFloater* floater); + static void onClickDock(LLFloater* floater); + static void onClickHelp(LLFloater* floater); - static void onClickClose(LLFloater* floater); - static void onClickMinimize(LLFloater* floater); - static void onClickTearOff(LLFloater* floater); - static void onClickDock(LLFloater* floater); - static void onClickHelp(LLFloater* floater); + static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } + static LLMultiFloater* getFloaterHost() {return sHostp; } - static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } - static LLMultiFloater* getFloaterHost() {return sHostp; } + void updateTransparency(ETypeTransparency transparency_type); - void updateTransparency(ETypeTransparency transparency_type); - - void enableResizeCtrls(bool enable, bool width = true, bool height = true); + void enableResizeCtrls(bool enable, bool width = true, bool height = true); - bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } + bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } protected: - void applyControlsAndPosition(LLFloater* other); + void applyControlsAndPosition(LLFloater* other); - void stackWith(LLFloater& other); + void stackWith(LLFloater& other); - virtual void initRectControl(); - virtual bool applyRectControl(); - bool applyDockState(); - void applyPositioning(LLFloater* other, bool on_open); - void applyRelativePosition(); + virtual void initRectControl(); + virtual bool applyRectControl(); + bool applyDockState(); + void applyPositioning(LLFloater* other, bool on_open); + void applyRelativePosition(); - void storeRectControl(); - void storeVisibilityControl(); - void storeDockStateControl(); + void storeRectControl(); + void storeVisibilityControl(); + void storeDockStateControl(); - void setKey(const LLSD& key); - void setInstanceName(const std::string& name); - - virtual void bringToFront(S32 x, S32 y); - virtual void goneFromFront(); - - void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized - const LLRect& getExpandedRect() const { return mExpandedRect; } + void setKey(const LLSD& key); + void setInstanceName(const std::string& name); - void setAutoFocus(BOOL focus) { mAutoFocus = focus; } // whether to automatically take focus when opened - BOOL getAutoFocus() const { return mAutoFocus; } - LLDragHandle* getDragHandle() const { return mDragHandle; } + virtual void bringToFront(S32 x, S32 y); + virtual void goneFromFront(); - void destroy(); // Don't call this directly. You probably want to call closeFloater() + void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized + const LLRect& getExpandedRect() const { return mExpandedRect; } - virtual void onClickCloseBtn(bool app_quitting = false); + void setAutoFocus(BOOL focus) { mAutoFocus = focus; } // whether to automatically take focus when opened + BOOL getAutoFocus() const { return mAutoFocus; } + LLDragHandle* getDragHandle() const { return mDragHandle; } - virtual void updateTitleButtons(); + void destroy(); // Don't call this directly. You probably want to call closeFloater() - // Draws a cone from this floater to parent floater or view (owner) - // Modifies context_cone_opacity (interpolates according to fade time and returns new value) - void drawConeToOwner(F32 &context_cone_opacity, - F32 max_cone_opacity, - LLView *owner_view, - F32 context_fade_time = CONTEXT_CONE_FADE_TIME, - F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA, - F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA); + virtual void onClickCloseBtn(bool app_quitting = false); + + virtual void updateTitleButtons(); + + // Draws a cone from this floater to parent floater or view (owner) + // Modifies context_cone_opacity (interpolates according to fade time and returns new value) + void drawConeToOwner(F32 &context_cone_opacity, + F32 max_cone_opacity, + LLView *owner_view, + F32 context_fade_time = CONTEXT_CONE_FADE_TIME, + F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA, + F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA); private: - void setForeground(BOOL b); // called only by floaterview - void cleanupHandles(); // remove handles to dead floaters - void createMinimizeButton(); - void buildButtons(const Params& p); - - // Images and tooltips are named in the XML, but we want to look them - // up by index. - static LLUIImage* getButtonImage(const Params& p, EFloaterButton e); - static LLUIImage* getButtonPressedImage(const Params& p, EFloaterButton e); - - /** - * @params is_chrome - if floater is Chrome it means that floater will never get focus. - * Therefore it can't be closed with 'Ctrl+W'. So the tooltip text of close button( X ) - * should be 'Close' not 'Close(Ctrl+W)' as for usual floaters. - */ - static std::string getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome); - - BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index); - void addResizeCtrls(); - void layoutResizeCtrls(); - void addDragHandle(); - void layoutDragHandle(); // repair layout - - static void updateActiveFloaterTransparency(); - static void updateInactiveFloaterTransparency(); - void updateTransparency(LLView* view, ETypeTransparency transparency_type); + void setForeground(BOOL b); // called only by floaterview + void cleanupHandles(); // remove handles to dead floaters + void createMinimizeButton(); + void buildButtons(const Params& p); + + // Images and tooltips are named in the XML, but we want to look them + // up by index. + static LLUIImage* getButtonImage(const Params& p, EFloaterButton e); + static LLUIImage* getButtonPressedImage(const Params& p, EFloaterButton e); + + /** + * @params is_chrome - if floater is Chrome it means that floater will never get focus. + * Therefore it can't be closed with 'Ctrl+W'. So the tooltip text of close button( X ) + * should be 'Close' not 'Close(Ctrl+W)' as for usual floaters. + */ + static std::string getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome); + + BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index); + void addResizeCtrls(); + void layoutResizeCtrls(); + void addDragHandle(); + void layoutDragHandle(); // repair layout + + static void updateActiveFloaterTransparency(); + static void updateInactiveFloaterTransparency(); + void updateTransparency(LLView* view, ETypeTransparency transparency_type); public: - static const F32 CONTEXT_CONE_IN_ALPHA; - static const F32 CONTEXT_CONE_OUT_ALPHA; - static const F32 CONTEXT_CONE_FADE_TIME; + static const F32 CONTEXT_CONE_IN_ALPHA; + static const F32 CONTEXT_CONE_OUT_ALPHA; + static const F32 CONTEXT_CONE_FADE_TIME; - // Called when floater is opened, passes mKey - // Public so external views or floaters can watch for this floater opening - commit_signal_t mOpenSignal; + // Called when floater is opened, passes mKey + // Public so external views or floaters can watch for this floater opening + commit_signal_t mOpenSignal; - // Called when floater is closed, passes app_qitting as LLSD() - // Public so external views or floaters can watch for this floater closing - commit_signal_t mCloseSignal; + // Called when floater is closed, passes app_qitting as LLSD() + // Public so external views or floaters can watch for this floater closing + commit_signal_t mCloseSignal; - commit_signal_t* mMinimizeSignal; + commit_signal_t* mMinimizeSignal; protected: - bool mSaveRect; - bool mDefaultRectForGroup; - std::string mRectControl; - std::string mPosXControl; - std::string mPosYControl; - std::string mVisibilityControl; - std::string mDocStateControl; - LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg - - LLDragHandle* mDragHandle; - LLResizeBar* mResizeBar[4]; - LLResizeHandle* mResizeHandle[4]; - - LLButton* mButtons[BUTTON_COUNT]; + bool mSaveRect; + bool mDefaultRectForGroup; + std::string mRectControl; + std::string mPosXControl; + std::string mPosYControl; + std::string mVisibilityControl; + std::string mDocStateControl; + LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg + + LLDragHandle* mDragHandle; + LLResizeBar* mResizeBar[4]; + LLResizeHandle* mResizeHandle[4]; + + LLButton* mButtons[BUTTON_COUNT]; private: - LLRect mExpandedRect; - - LLUIString mTitle; - LLUIString mShortTitle; - - BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater - bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it + LLRect mExpandedRect; + + LLUIString mTitle; + LLUIString mShortTitle; + + BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater + bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it bool mIsReuseInitialized; // true if mReuseInstance already set from parameters - std::string mInstanceName; // Store the instance name so we can remove ourselves from the list - - BOOL mCanTearOff; - BOOL mCanMinimize; - BOOL mCanClose; - bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction - BOOL mDragOnLeft; - BOOL mResizable; - BOOL mAutoClose; - - LLFloaterEnums::EOpenPositioning mPositioning; - LLCoordFloater mPosition; - - S32 mMinWidth; - S32 mMinHeight; - S32 mHeaderHeight; // height in pixels of header for title, drag bar - S32 mLegacyHeaderHeight;// HACK see initFloaterXML() - - BOOL mMinimized; - BOOL mForeground; - LLHandle<LLFloater> mDependeeHandle; - - - BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. - - typedef std::set<LLHandle<LLFloater> > handle_set_t; - typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t; - handle_set_t mDependents; - bool mTranslateWithDependents { false }; - - bool mButtonsEnabled[BUTTON_COUNT]; - F32 mButtonScale; - BOOL mAutoFocus; - LLHandle<LLFloater> mSnappedTo; - - LLHandle<LLFloater> mHostHandle; - LLHandle<LLFloater> mLastHostHandle; - - bool mCanDock; - bool mDocked; - bool mTornOff; - - static LLMultiFloater* sHostp; - static BOOL sQuitting; - static std::string sButtonNames[BUTTON_COUNT]; - static std::string sButtonToolTips[BUTTON_COUNT]; - static std::string sButtonToolTipsIndex[BUTTON_COUNT]; - - typedef void(*click_callback)(LLFloater*); - static click_callback sButtonCallbacks[BUTTON_COUNT]; - - BOOL mHasBeenDraggedWhileMinimized; - S32 mPreviousMinimizedBottom; - S32 mPreviousMinimizedLeft; - - F32 mDefaultRelativeX; - F32 mDefaultRelativeY; + std::string mInstanceName; // Store the instance name so we can remove ourselves from the list + + BOOL mCanTearOff; + BOOL mCanMinimize; + BOOL mCanClose; + bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction + BOOL mDragOnLeft; + BOOL mResizable; + BOOL mAutoClose; + + LLFloaterEnums::EOpenPositioning mPositioning; + LLCoordFloater mPosition; + + S32 mMinWidth; + S32 mMinHeight; + S32 mHeaderHeight; // height in pixels of header for title, drag bar + S32 mLegacyHeaderHeight;// HACK see initFloaterXML() + + BOOL mMinimized; + BOOL mForeground; + LLHandle<LLFloater> mDependeeHandle; + + + BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. + + typedef std::set<LLHandle<LLFloater> > handle_set_t; + typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t; + handle_set_t mDependents; + bool mTranslateWithDependents { false }; + + bool mButtonsEnabled[BUTTON_COUNT]; + F32 mButtonScale; + BOOL mAutoFocus; + LLHandle<LLFloater> mSnappedTo; + + LLHandle<LLFloater> mHostHandle; + LLHandle<LLFloater> mLastHostHandle; + + bool mCanDock; + bool mDocked; + bool mTornOff; + + static LLMultiFloater* sHostp; + static BOOL sQuitting; + static std::string sButtonNames[BUTTON_COUNT]; + static std::string sButtonToolTips[BUTTON_COUNT]; + static std::string sButtonToolTipsIndex[BUTTON_COUNT]; + + typedef void(*click_callback)(LLFloater*); + static click_callback sButtonCallbacks[BUTTON_COUNT]; + + BOOL mHasBeenDraggedWhileMinimized; + S32 mPreviousMinimizedBottom; + S32 mPreviousMinimizedLeft; + + F32 mDefaultRelativeX; + F32 mDefaultRelativeY; }; @@ -551,78 +555,78 @@ const S32 FLOATER_MIN_VISIBLE_PIXELS = 16; class LLFloaterView : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>{}; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>{}; protected: - LLFloaterView (const Params& p); - friend class LLUICtrlFactory; + LLFloaterView (const Params& p); + friend class LLUICtrlFactory; public: - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void draw(); - /*virtual*/ LLRect getSnapRect() const; - /*virtual*/ void refresh(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void draw(); + /*virtual*/ LLRect getSnapRect() const; + /*virtual*/ void refresh(); - LLRect findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ); + LLRect findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ); - // Given a child of gFloaterView, make sure this view can fit entirely onscreen. - void adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside, BOOL snap_in_toolbars = false); + // Given a child of gFloaterView, make sure this view can fit entirely onscreen. + void adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside, BOOL snap_in_toolbars = false); - void setMinimizePositionVerticalOffset(S32 offset) { mMinimizePositionVOffset = offset; } - void getMinimizePosition( S32 *left, S32 *bottom); - void restoreAll(); // un-minimize all floaters - typedef std::set<LLView*> skip_list_t; - void pushVisibleAll(BOOL visible, const skip_list_t& skip_list = skip_list_t()); - void popVisibleAll(const skip_list_t& skip_list = skip_list_t()); + void setMinimizePositionVerticalOffset(S32 offset) { mMinimizePositionVOffset = offset; } + void getMinimizePosition( S32 *left, S32 *bottom); + void restoreAll(); // un-minimize all floaters + typedef std::set<LLView*> skip_list_t; + void pushVisibleAll(BOOL visible, const skip_list_t& skip_list = skip_list_t()); + void popVisibleAll(const skip_list_t& skip_list = skip_list_t()); - void setCycleMode(BOOL mode) { mFocusCycleMode = mode; } - BOOL getCycleMode() const { return mFocusCycleMode; } - void bringToFront( LLFloater* child, BOOL give_focus = TRUE, BOOL restore = TRUE ); - void highlightFocusedFloater(); - void unhighlightFocusedFloater(); - void focusFrontFloater(); - void destroyAllChildren(); - // attempt to close all floaters - void closeAllChildren(bool app_quitting); - BOOL allChildrenClosed(); - void shiftFloaters(S32 x_offset, S32 y_offset); + void setCycleMode(BOOL mode) { mFocusCycleMode = mode; } + BOOL getCycleMode() const { return mFocusCycleMode; } + void bringToFront( LLFloater* child, BOOL give_focus = TRUE, BOOL restore = TRUE ); + void highlightFocusedFloater(); + void unhighlightFocusedFloater(); + void focusFrontFloater(); + void destroyAllChildren(); + // attempt to close all floaters + void closeAllChildren(bool app_quitting); + BOOL allChildrenClosed(); + void shiftFloaters(S32 x_offset, S32 y_offset); - void hideAllFloaters(); - void showHiddenFloaters(); + void hideAllFloaters(); + void showHiddenFloaters(); - LLFloater* getFrontmost() const; - LLFloater* getBackmost() const; - LLFloater* getParentFloater(LLView* viewp) const; - LLFloater* getFocusedFloater() const; - void syncFloaterTabOrder(); + LLFloater* getFrontmost() const; + LLFloater* getBackmost() const; + LLFloater* getParentFloater(LLView* viewp) const; + LLFloater* getFocusedFloater() const; + void syncFloaterTabOrder(); - // Returns z order of child provided. 0 is closest, larger numbers - // are deeper in the screen. If there is no such child, the return - // value is not defined. - S32 getZOrder(LLFloater* child); + // Returns z order of child provided. 0 is closest, larger numbers + // are deeper in the screen. If there is no such child, the return + // value is not defined. + S32 getZOrder(LLFloater* child); - void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; } - LLFloater* getFrontmostClosableFloater(); + void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; } + LLFloater* getFrontmostClosableFloater(); - void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect); + void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect); private: - void hiddenFloaterClosed(LLFloater* floater); - - LLRect mLastSnapRect; - LLRect mToolbarLeftRect; - LLRect mToolbarBottomRect; - LLRect mToolbarRightRect; - LLHandle<LLView> mSnapView; - BOOL mFocusCycleMode; - S32 mSnapOffsetBottom; - S32 mSnapOffsetRight; - S32 mMinimizePositionVOffset; - typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t; - hidden_floaters_t mHiddenFloaters; - LLHandle<LLFloater> mFrontChildHandle; + void hiddenFloaterClosed(LLFloater* floater); + + LLRect mLastSnapRect; + LLRect mToolbarLeftRect; + LLRect mToolbarBottomRect; + LLRect mToolbarRightRect; + LLHandle<LLView> mSnapView; + BOOL mFocusCycleMode; + S32 mSnapOffsetBottom; + S32 mSnapOffsetRight; + S32 mMinimizePositionVOffset; + typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t; + hidden_floaters_t mHiddenFloaters; + LLHandle<LLFloater> mFrontChildHandle; }; // diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index f888d7ff68..989ce12d09 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterreg.cpp * @brief LLFloaterReg Floater Registration Class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #include "llfloaterreg.h" -//#include "llagent.h" +//#include "llagent.h" #include "llfloater.h" #include "llmultifloater.h" #include "llfloaterreglistener.h" @@ -51,10 +51,10 @@ static LLFloaterRegListener sFloaterRegListener; //static void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname) { - sBuildMap[name].mFunc = func; - sBuildMap[name].mFile = filename; - sGroupMap[name] = groupname.empty() ? name : groupname; - sGroupMap[groupname] = groupname; // for referencing directly by group name + sBuildMap[name].mFunc = func; + sBuildMap[name].mFile = filename; + sGroupMap[name] = groupname.empty() ? name : groupname; + sGroupMap[groupname] = groupname; // for referencing directly by group name } //static @@ -66,468 +66,468 @@ bool LLFloaterReg::isRegistered(const std::string& name) //static LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name) { - const std::string& groupname = sGroupMap[name]; - if (!groupname.empty()) - { - instance_list_t& list = sInstanceMap[groupname]; - if (!list.empty()) - { - for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter) - { - LLFloater* inst = *iter; - - if (inst->getVisible() && !inst->isMinimized()) - { - return inst; - } - } - } - } - return NULL; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + if (!list.empty()) + { + for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter) + { + LLFloater* inst = *iter; + + if (inst->getVisible() && !inst->isMinimized()) + { + return inst; + } + } + } + } + return NULL; } LLFloater* LLFloaterReg::getLastFloaterCascading() { - LLRect candidate_rect; - candidate_rect.mTop = 100000; - LLFloater* candidate_floater = NULL; - - std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); - for( ; it != it_end; ++it) - { - const std::string& group_name = it->second; - - instance_list_t& instances = sInstanceMap[group_name]; - - for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) - { - LLFloater* inst = *iter; - - if (inst->getVisible() - && (inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADING) - || inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADE_GROUP))) - { - if (candidate_rect.mTop > inst->getRect().mTop) - { - candidate_floater = inst; - candidate_rect = inst->getRect(); - } - } - } - } - - return candidate_floater; + LLRect candidate_rect; + candidate_rect.mTop = 100000; + LLFloater* candidate_floater = NULL; + + std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); + for( ; it != it_end; ++it) + { + const std::string& group_name = it->second; + + instance_list_t& instances = sInstanceMap[group_name]; + + for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) + { + LLFloater* inst = *iter; + + if (inst->getVisible() + && (inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADING) + || inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADE_GROUP))) + { + if (candidate_rect.mTop > inst->getRect().mTop) + { + candidate_floater = inst; + candidate_rect = inst->getRect(); + } + } + } + } + + return candidate_floater; } //static LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key) { - LLFloater* res = NULL; - const std::string& groupname = sGroupMap[name]; - if (!groupname.empty()) - { - instance_list_t& list = sInstanceMap[groupname]; - for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) - { - LLFloater* inst = *iter; - if (inst->matchesKey(key)) - { - res = inst; - break; - } - } - } - return res; + LLFloater* res = NULL; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* inst = *iter; + if (inst->matchesKey(key)) + { + res = inst; + break; + } + } + } + return res; } //static -LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key) +LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key) { - LLFloater* res = findInstance(name, key); - if (!res) - { - const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc; - const std::string& xui_file = sBuildMap[name].mFile; - if (build_func) - { - const std::string& groupname = sGroupMap[name]; - if (!groupname.empty()) - { - instance_list_t& list = sInstanceMap[groupname]; - - res = build_func(key); - if (!res) - { - LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL; - return NULL; - } - bool success = res->buildFromFile(xui_file); - if (!success) - { - LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL; - return NULL; - } - - // Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe - if (res->mKey.isUndefined()) - { - res->mKey = key; - } - res->setInstanceName(name); - - LLFloater *last_floater = (list.empty() ? NULL : list.back()); - - res->applyControlsAndPosition(last_floater); - - gFloaterView->adjustToFitScreen(res, false); - - list.push_back(res); - } - } - if (!res) - { - LL_WARNS() << "Floater type: '" << name << "' not registered." << LL_ENDL; - } - } - return res; + LLFloater* res = findInstance(name, key); + if (!res) + { + const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc; + const std::string& xui_file = sBuildMap[name].mFile; + if (build_func) + { + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + + res = build_func(key); + if (!res) + { + LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL; + return NULL; + } + bool success = res->buildFromFile(xui_file); + if (!success) + { + LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL; + return NULL; + } + + // Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe + if (res->mKey.isUndefined()) + { + res->mKey = key; + } + res->setInstanceName(name); + + LLFloater *last_floater = (list.empty() ? NULL : list.back()); + + res->applyControlsAndPosition(last_floater); + + gFloaterView->adjustToFitScreen(res, false); + + list.push_back(res); + } + } + if (!res) + { + LL_WARNS() << "Floater type: '" << name << "' not registered." << LL_ENDL; + } + } + return res; } //static LLFloater* LLFloaterReg::removeInstance(const std::string& name, const LLSD& key) { - LLFloater* res = NULL; - const std::string& groupname = sGroupMap[name]; - if (!groupname.empty()) - { - instance_list_t& list = sInstanceMap[groupname]; - for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) - { - LLFloater* inst = *iter; - if (inst->matchesKey(key)) - { - res = inst; - list.erase(iter); - break; - } - } - } - return res; + LLFloater* res = NULL; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* inst = *iter; + if (inst->matchesKey(key)) + { + res = inst; + list.erase(iter); + break; + } + } + } + return res; } //static // returns true if the instance existed bool LLFloaterReg::destroyInstance(const std::string& name, const LLSD& key) { - LLFloater* inst = removeInstance(name, key); - if (inst) - { - delete inst; - return true; - } - else - { - return false; - } + LLFloater* inst = removeInstance(name, key); + if (inst) + { + delete inst; + return true; + } + else + { + return false; + } } // Iterators //static LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::string& name) { - instance_map_t::iterator iter = sInstanceMap.find(name); - if (iter != sInstanceMap.end()) - { - return iter->second; - } - else - { - return sNullInstanceList; - } + instance_map_t::iterator iter = sInstanceMap.find(name); + if (iter != sInstanceMap.end()) + { + return iter->second; + } + else + { + return sNullInstanceList; + } } // Visibility Management //static -LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) +LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) { - if( sBlockShowFloaters - // see EXT-7090 - && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) - return 0;// - LLFloater* instance = getInstance(name, key); - if (instance) - { - instance->openFloater(key); - if (focus) - instance->setFocus(TRUE); - } - return instance; + if( sBlockShowFloaters + // see EXT-7090 + && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) + return 0;// + LLFloater* instance = getInstance(name, key); + if (instance) + { + instance->openFloater(key); + if (focus) + instance->setFocus(TRUE); + } + return instance; } //static // returns true if the instance exists -bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key) -{ - LLFloater* instance = findInstance(name, key); - if (instance) - { - instance->closeHostedFloater(); - } - return (instance != NULL); +bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key) +{ + LLFloater* instance = findInstance(name, key); + if (instance) + { + instance->closeHostedFloater(); + } + return (instance != NULL); } //static // returns true if the instance is visible when completed bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key) { - LLFloater* instance = findInstance(name, key); - if (LLFloater::isShown(instance)) - { - instance->closeHostedFloater(); - return false; - } - else - { - return showInstance(name, key, TRUE) ? true : false; - } + LLFloater* instance = findInstance(name, key); + if (LLFloater::isShown(instance)) + { + instance->closeHostedFloater(); + return false; + } + else + { + return showInstance(name, key, TRUE) ? true : false; + } } //static // returns true if the instance exists and is visible (doesnt matter minimized or not) bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key) { - LLFloater* instance = findInstance(name, key); - return LLFloater::isVisible(instance); + LLFloater* instance = findInstance(name, key); + return LLFloater::isVisible(instance); } //static -void LLFloaterReg::showInitialVisibleInstances() +void LLFloaterReg::showInitialVisibleInstances() { - // Iterate through alll registered instance names and show any with a save visible state - for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) - { - const std::string& name = iter->first; - std::string controlname = getVisibilityControlName(name); - if (LLFloater::getControlGroup()->controlExists(controlname)) - { - BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname); - if (isvis) - { - showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true - } - } - } + // Iterate through alll registered instance names and show any with a save visible state + for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) + { + const std::string& name = iter->first; + std::string controlname = getVisibilityControlName(name); + if (LLFloater::getControlGroup()->controlExists(controlname)) + { + BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname); + if (isvis) + { + showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true + } + } + } } //static void LLFloaterReg::hideVisibleInstances(const std::set<std::string>& exceptions) { - // Iterate through alll active instances and hide them - for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) - { - const std::string& name = iter->first; - if (exceptions.find(name) != exceptions.end()) - continue; - instance_list_t& list = iter->second; - for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) - { - LLFloater* floater = *iter; - floater->pushVisible(FALSE); - } - } + // Iterate through alll active instances and hide them + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + const std::string& name = iter->first; + if (exceptions.find(name) != exceptions.end()) + continue; + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->pushVisible(FALSE); + } + } } //static void LLFloaterReg::restoreVisibleInstances() { - // Iterate through all active instances and restore visibility - for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) - { - instance_list_t& list = iter->second; - for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) - { - LLFloater* floater = *iter; - floater->popVisible(); - } - } + // Iterate through all active instances and restore visibility + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->popVisible(); + } + } } //static std::string LLFloaterReg::getRectControlName(const std::string& name) { - return std::string("floater_rect_") + getBaseControlName(name); + return std::string("floater_rect_") + getBaseControlName(name); } //static std::string LLFloaterReg::declareRectControl(const std::string& name) { - std::string controlname = getRectControlName(name); - LLFloater::getControlGroup()->declareRect(controlname, LLRect(), - llformat("Window Size for %s", name.c_str()), - LLControlVariable::PERSIST_NONDFT); - return controlname; + std::string controlname = getRectControlName(name); + LLFloater::getControlGroup()->declareRect(controlname, LLRect(), + llformat("Window Size for %s", name.c_str()), + LLControlVariable::PERSIST_NONDFT); + return controlname; } std::string LLFloaterReg::declarePosXControl(const std::string& name) { - std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_x"; - LLFloater::getControlGroup()->declareF32(controlname, - 10.f, - llformat("Window X Position for %s", name.c_str()), - LLControlVariable::PERSIST_NONDFT); - return controlname; + std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_x"; + LLFloater::getControlGroup()->declareF32(controlname, + 10.f, + llformat("Window X Position for %s", name.c_str()), + LLControlVariable::PERSIST_NONDFT); + return controlname; } std::string LLFloaterReg::declarePosYControl(const std::string& name) { - std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_y"; - LLFloater::getControlGroup()->declareF32(controlname, - 10.f, - llformat("Window Y Position for %s", name.c_str()), - LLControlVariable::PERSIST_NONDFT); + std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_y"; + LLFloater::getControlGroup()->declareF32(controlname, + 10.f, + llformat("Window Y Position for %s", name.c_str()), + LLControlVariable::PERSIST_NONDFT); - return controlname; + return controlname; } //static std::string LLFloaterReg::getVisibilityControlName(const std::string& name) { - return std::string("floater_vis_") + getBaseControlName(name); + return std::string("floater_vis_") + getBaseControlName(name); } -//static +//static std::string LLFloaterReg::getBaseControlName(const std::string& name) { - std::string res(name); - LLStringUtil::replaceChar( res, ' ', '_' ); - return res; + std::string res(name); + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; } //static std::string LLFloaterReg::declareVisibilityControl(const std::string& name) { - std::string controlname = getVisibilityControlName(name); - LLFloater::getControlGroup()->declareBOOL(controlname, FALSE, - llformat("Window Visibility for %s", name.c_str()), - LLControlVariable::PERSIST_NONDFT); - return controlname; + std::string controlname = getVisibilityControlName(name); + LLFloater::getControlGroup()->declareBOOL(controlname, FALSE, + llformat("Window Visibility for %s", name.c_str()), + LLControlVariable::PERSIST_NONDFT); + return controlname; } //static std::string LLFloaterReg::declareDockStateControl(const std::string& name) { - std::string controlname = getDockStateControlName(name); - LLFloater::getControlGroup()->declareBOOL(controlname, TRUE, - llformat("Window Docking state for %s", name.c_str()), - LLControlVariable::PERSIST_NONDFT); - return controlname; + std::string controlname = getDockStateControlName(name); + LLFloater::getControlGroup()->declareBOOL(controlname, TRUE, + llformat("Window Docking state for %s", name.c_str()), + LLControlVariable::PERSIST_NONDFT); + return controlname; } //static std::string LLFloaterReg::getDockStateControlName(const std::string& name) { - std::string res = std::string("floater_dock_") + name; - LLStringUtil::replaceChar( res, ' ', '_' ); - return res; + std::string res = std::string("floater_dock_") + name; + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; } //static void LLFloaterReg::registerControlVariables() { - // Iterate through alll registered instance names and register rect and visibility control variables - for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) - { - const std::string& name = iter->first; - if (LLFloater::getControlGroup()->controlExists(getRectControlName(name))) - { - declareRectControl(name); - } - if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name))) - { - declareVisibilityControl(name); - } - } - - const LLSD& exclude_list = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("always_showable_floaters"); - for (LLSD::array_const_iterator iter = exclude_list.beginArray(); - iter != exclude_list.endArray(); - iter++) - { - sAlwaysShowableList.insert(iter->asString()); - } + // Iterate through alll registered instance names and register rect and visibility control variables + for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) + { + const std::string& name = iter->first; + if (LLFloater::getControlGroup()->controlExists(getRectControlName(name))) + { + declareRectControl(name); + } + if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name))) + { + declareVisibilityControl(name); + } + } + + const LLSD& exclude_list = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("always_showable_floaters"); + for (LLSD::array_const_iterator iter = exclude_list.beginArray(); + iter != exclude_list.endArray(); + iter++) + { + sAlwaysShowableList.insert(iter->asString()); + } } //static void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key) { - // - // Floaters controlled by the toolbar behave a bit differently from others. - // Namely they have 3-4 states as defined in the design wiki page here: - // https://wiki.lindenlab.com/wiki/FUI_Button_states - // - // The basic idea is this: - // * If the target floater is minimized, this button press will un-minimize it. - // * Else if the target floater is closed open it. - // * Else if the target floater does not have focus, give it focus. - // * Also, if it is not on top, bring it forward when focus is given. - // * Else the target floater is open, close it. - // - std::string name = sdname.asString(); - LLFloater* instance = getInstance(name, key); - - if (!instance) - { - LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL; - return; - } - - // If hosted, we need to take that into account - LLFloater* host = instance->getHost(); - - if (host) - { - if (host->isMinimized() || !host->isShown() || !host->isFrontmost()) - { - host->setMinimized(FALSE); - instance->openFloater(key); - instance->setVisibleAndFrontmost(true, key); - } - else if (!instance->getVisible()) - { - instance->openFloater(key); - instance->setVisibleAndFrontmost(true, key); - instance->setFocus(TRUE); - } - else - { - instance->closeHostedFloater(); - } - } - else - { - if (instance->isMinimized()) - { - instance->setMinimized(FALSE); - instance->setVisibleAndFrontmost(true, key); - } - else if (!instance->isShown()) - { - instance->openFloater(key); - instance->setVisibleAndFrontmost(true, key); - } - else if (!instance->isFrontmost()) - { - instance->setVisibleAndFrontmost(true, key); - } - else - { - instance->closeHostedFloater(); - } - } + // + // Floaters controlled by the toolbar behave a bit differently from others. + // Namely they have 3-4 states as defined in the design wiki page here: + // https://wiki.lindenlab.com/wiki/FUI_Button_states + // + // The basic idea is this: + // * If the target floater is minimized, this button press will un-minimize it. + // * Else if the target floater is closed open it. + // * Else if the target floater does not have focus, give it focus. + // * Also, if it is not on top, bring it forward when focus is given. + // * Else the target floater is open, close it. + // + std::string name = sdname.asString(); + LLFloater* instance = getInstance(name, key); + + if (!instance) + { + LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL; + return; + } + + // If hosted, we need to take that into account + LLFloater* host = instance->getHost(); + + if (host) + { + if (host->isMinimized() || !host->isShown() || !host->isFrontmost()) + { + host->setMinimized(FALSE); + instance->openFloater(key); + instance->setVisibleAndFrontmost(true, key); + } + else if (!instance->getVisible()) + { + instance->openFloater(key); + instance->setVisibleAndFrontmost(true, key); + instance->setFocus(TRUE); + } + else + { + instance->closeHostedFloater(); + } + } + else + { + if (instance->isMinimized()) + { + instance->setMinimized(FALSE); + instance->setVisibleAndFrontmost(true, key); + } + else if (!instance->isShown()) + { + instance->openFloater(key); + instance->setVisibleAndFrontmost(true, key); + } + else if (!instance->isFrontmost()) + { + instance->setVisibleAndFrontmost(true, key); + } + else + { + instance->closeHostedFloater(); + } + } } // static @@ -585,25 +585,25 @@ void LLFloaterReg::showInstanceOrBringToFront(const LLSD& sdname, const LLSD& ke // static U32 LLFloaterReg::getVisibleFloaterInstanceCount() { - U32 count = 0; + U32 count = 0; - std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); - for( ; it != it_end; ++it) - { - const std::string& group_name = it->second; + std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end(); + for( ; it != it_end; ++it) + { + const std::string& group_name = it->second; - instance_list_t& instances = sInstanceMap[group_name]; + instance_list_t& instances = sInstanceMap[group_name]; - for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) - { - LLFloater* inst = *iter; + for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) + { + LLFloater* inst = *iter; - if (inst->getVisible() && !inst->isMinimized()) - { - count++; - } - } - } + if (inst->getVisible() && !inst->isMinimized()) + { + count++; + } + } + } - return count; + return count; } diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index eaa59b1d6f..43f3f7b170 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -1,25 +1,25 @@ -/** +/** * @file llfloaterreg.h * @brief LLFloaterReg Floater Registration Class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,113 +46,113 @@ typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc; class LLFloaterReg { public: - // We use a list of LLFloater's instead of a set for two reasons: - // 1) With a list we have a predictable ordering, useful for finding the last opened floater of a given type. - // 2) We can change the key of a floater without altering the list. - typedef std::list<LLFloater*> instance_list_t; - typedef const instance_list_t const_instance_list_t; - typedef std::map<std::string, instance_list_t> instance_map_t; - - struct BuildData - { - LLFloaterBuildFunc mFunc; - std::string mFile; - }; - typedef std::map<std::string, BuildData> build_map_t; - + // We use a list of LLFloater's instead of a set for two reasons: + // 1) With a list we have a predictable ordering, useful for finding the last opened floater of a given type. + // 2) We can change the key of a floater without altering the list. + typedef std::list<LLFloater*> instance_list_t; + typedef const instance_list_t const_instance_list_t; + typedef std::map<std::string, instance_list_t> instance_map_t; + + struct BuildData + { + LLFloaterBuildFunc mFunc; + std::string mFile; + }; + typedef std::map<std::string, BuildData> build_map_t; + private: - friend class LLFloaterRegListener; - static instance_list_t sNullInstanceList; - static instance_map_t sInstanceMap; - static build_map_t sBuildMap; - static std::map<std::string,std::string> sGroupMap; - static bool sBlockShowFloaters; - /** - * Defines list of floater names that can be shown despite state of sBlockShowFloaters. - */ - static std::set<std::string> sAlwaysShowableList; - + friend class LLFloaterRegListener; + static instance_list_t sNullInstanceList; + static instance_map_t sInstanceMap; + static build_map_t sBuildMap; + static std::map<std::string,std::string> sGroupMap; + static bool sBlockShowFloaters; + /** + * Defines list of floater names that can be shown despite state of sBlockShowFloaters. + */ + static std::set<std::string> sAlwaysShowableList; + public: - // Registration - - // usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build<LLFloaterFoo>); - template <class T> - static LLFloater* build(const LLSD& key) - { - T* floater = new T(key); - return floater; - } - - static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func, - const std::string& groupname = LLStringUtil::null); - static bool isRegistered(const std::string& name); - - // Helpers - static LLFloater* getLastFloaterInGroup(const std::string& name); - static LLFloater* getLastFloaterCascading(); - - // Find / get (create) / remove / destroy - static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD()); - static LLFloater* getInstance(const std::string& name, const LLSD& key = LLSD()); - static LLFloater* removeInstance(const std::string& name, const LLSD& key = LLSD()); - static bool destroyInstance(const std::string& name, const LLSD& key = LLSD()); - - // Iterators - static const_instance_list_t& getFloaterList(const std::string& name); - - // Visibility Management - // return NULL if instance not found or can't create instance (no builder) - static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE); - // Close a floater (may destroy or set invisible) - // return false if can't find instance - static bool hideInstance(const std::string& name, const LLSD& key = LLSD()); - // return true if instance is visible: - static bool toggleInstance(const std::string& name, const LLSD& key = LLSD()); - static bool instanceVisible(const std::string& name, const LLSD& key = LLSD()); - - static void showInitialVisibleInstances(); - static void hideVisibleInstances(const std::set<std::string>& exceptions = std::set<std::string>()); - static void restoreVisibleInstances(); - - // Control Variables - static std::string getRectControlName(const std::string& name); - static std::string declareRectControl(const std::string& name); - static std::string declarePosXControl(const std::string& name); - static std::string declarePosYControl(const std::string& name); - static std::string getVisibilityControlName(const std::string& name); - static std::string declareVisibilityControl(const std::string& name); - static std::string getBaseControlName(const std::string& name); - static std::string declareDockStateControl(const std::string& name); - static std::string getDockStateControlName(const std::string& name); - - static void registerControlVariables(); - - // Callback wrappers - static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD()); - static void showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD()); - - // Typed find / get / show - template <class T> - static T* findTypedInstance(const std::string& name, const LLSD& key = LLSD()) - { - return dynamic_cast<T*>(findInstance(name, key)); - } - - template <class T> - static T* getTypedInstance(const std::string& name, const LLSD& key = LLSD()) - { - return dynamic_cast<T*>(getInstance(name, key)); - } - - template <class T> - static T* showTypedInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE) - { - return dynamic_cast<T*>(showInstance(name, key, focus)); - } - - static void blockShowFloaters(bool value) { sBlockShowFloaters = value;} - - static U32 getVisibleFloaterInstanceCount(); + // Registration + + // usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build<LLFloaterFoo>); + template <class T> + static LLFloater* build(const LLSD& key) + { + T* floater = new T(key); + return floater; + } + + static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func, + const std::string& groupname = LLStringUtil::null); + static bool isRegistered(const std::string& name); + + // Helpers + static LLFloater* getLastFloaterInGroup(const std::string& name); + static LLFloater* getLastFloaterCascading(); + + // Find / get (create) / remove / destroy + static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD()); + static LLFloater* getInstance(const std::string& name, const LLSD& key = LLSD()); + static LLFloater* removeInstance(const std::string& name, const LLSD& key = LLSD()); + static bool destroyInstance(const std::string& name, const LLSD& key = LLSD()); + + // Iterators + static const_instance_list_t& getFloaterList(const std::string& name); + + // Visibility Management + // return NULL if instance not found or can't create instance (no builder) + static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE); + // Close a floater (may destroy or set invisible) + // return false if can't find instance + static bool hideInstance(const std::string& name, const LLSD& key = LLSD()); + // return true if instance is visible: + static bool toggleInstance(const std::string& name, const LLSD& key = LLSD()); + static bool instanceVisible(const std::string& name, const LLSD& key = LLSD()); + + static void showInitialVisibleInstances(); + static void hideVisibleInstances(const std::set<std::string>& exceptions = std::set<std::string>()); + static void restoreVisibleInstances(); + + // Control Variables + static std::string getRectControlName(const std::string& name); + static std::string declareRectControl(const std::string& name); + static std::string declarePosXControl(const std::string& name); + static std::string declarePosYControl(const std::string& name); + static std::string getVisibilityControlName(const std::string& name); + static std::string declareVisibilityControl(const std::string& name); + static std::string getBaseControlName(const std::string& name); + static std::string declareDockStateControl(const std::string& name); + static std::string getDockStateControlName(const std::string& name); + + static void registerControlVariables(); + + // Callback wrappers + static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD()); + static void showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD()); + + // Typed find / get / show + template <class T> + static T* findTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast<T*>(findInstance(name, key)); + } + + template <class T> + static T* getTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast<T*>(getInstance(name, key)); + } + + template <class T> + static T* showTypedInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE) + { + return dynamic_cast<T*>(showInstance(name, key, focus)); + } + + static void blockShowFloaters(bool value) { sBlockShowFloaters = value;} + + static U32 getVisibleFloaterInstanceCount(); }; #endif diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index 7525b8cab3..aa3d1a1171 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Implementation for llfloaterreglistener. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index 24311a2dfa..a36072892c 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-08-12 * @brief Wrap (subset of) LLFloaterReg API with an event API - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp index 4b3a0a5d21..1d529d09d3 100644 --- a/indra/llui/llflyoutbutton.cpp +++ b/indra/llui/llflyoutbutton.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llflyoutbutton.cpp * @brief LLFlyoutButton base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,44 +34,44 @@ const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24; LLFlyoutButton::LLFlyoutButton(const Params& p) -: LLComboBox(p), - mToggleState(FALSE), - mActionButton(NULL) +: LLComboBox(p), + mToggleState(FALSE), + mActionButton(NULL) { - // Always use text box - // Text label button - LLButton::Params bp(p.action_button); - bp.name(p.label); - bp.label(p.label); - bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight()); - bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2)); - bp.follows.flags(FOLLOWS_ALL); + // Always use text box + // Text label button + LLButton::Params bp(p.action_button); + bp.name(p.label); + bp.label(p.label); + bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight()); + bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2)); + bp.follows.flags(FOLLOWS_ALL); - mActionButton = LLUICtrlFactory::create<LLButton>(bp); - addChild(mActionButton); + mActionButton = LLUICtrlFactory::create<LLButton>(bp); + addChild(mActionButton); } void LLFlyoutButton::onActionButtonClick(const LLSD& data) { - // remember last list selection? - mList->deselect(); - onCommit(); + // remember last list selection? + mList->deselect(); + onCommit(); } void LLFlyoutButton::draw() { - mActionButton->setToggleState(mToggleState); - mButton->setToggleState(mToggleState); + mActionButton->setToggleState(mToggleState); + mButton->setToggleState(mToggleState); - //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or - // the label reflects the last selected item, for now we have to manually remove the label - setLabel(LLStringUtil::null); - LLComboBox::draw(); + //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or + // the label reflects the last selected item, for now we have to manually remove the label + setLabel(LLStringUtil::null); + LLComboBox::draw(); } void LLFlyoutButton::setToggleState(BOOL state) { - mToggleState = state; + mToggleState = state; } diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h index 36998eba2e..c217d14ff1 100644 --- a/indra/llui/llflyoutbutton.h +++ b/indra/llui/llflyoutbutton.h @@ -1,25 +1,25 @@ -/** +/** * @file llflyoutbutton.h * @brief LLFlyoutButton base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,32 +37,32 @@ class LLFlyoutButton : public LLComboBox { public: - struct Params : public LLInitParam::Block<Params, LLComboBox::Params> - { - Optional<LLButton::Params> action_button; - Deprecated allow_text_entry; + struct Params : public LLInitParam::Block<Params, LLComboBox::Params> + { + Optional<LLButton::Params> action_button; + Deprecated allow_text_entry; - Params() - : action_button("action_button"), - allow_text_entry("allow_text_entry") - { - changeDefault(LLComboBox::Params::allow_text_entry, false); - } + Params() + : action_button("action_button"), + allow_text_entry("allow_text_entry") + { + changeDefault(LLComboBox::Params::allow_text_entry, false); + } - }; + }; protected: - LLFlyoutButton(const Params&); - friend class LLUICtrlFactory; + LLFlyoutButton(const Params&); + friend class LLUICtrlFactory; public: - virtual void draw(); + virtual void draw(); - void setToggleState(BOOL state); + void setToggleState(BOOL state); - void onActionButtonClick(const LLSD& data); + void onActionButtonClick(const LLSD& data); protected: - LLButton* mActionButton; - BOOL mToggleState; + LLButton* mActionButton; + BOOL mToggleState; }; #endif // LL_LLFLYOUTBUTTON_H diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 7b0a6cbdae..2331b34c43 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfocusmgr.cpp * @brief LLFocusMgr base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,38 +33,38 @@ const F32 FOCUS_FADE_TIME = 0.3f; LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mTopLostCallback(NULL) +: mFocusLostCallback(NULL), + mFocusReceivedCallback(NULL), + mFocusChangedCallback(NULL), + mTopLostCallback(NULL) { } // virtual BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - return FALSE; + return FALSE; } // virtual BOOL LLFocusableElement::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) { - return FALSE; + return FALSE; } // virtual BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { - return FALSE; + return FALSE; } -// virtual +// virtual bool LLFocusableElement::wantsKeyUpKeyDown() const { return false; } -//virtual +//virtual bool LLFocusableElement::wantsReturnKey() const { return false; @@ -73,60 +73,60 @@ bool LLFocusableElement::wantsReturnKey() const // virtual LLFocusableElement::~LLFocusableElement() { - delete mFocusLostCallback; - delete mFocusReceivedCallback; - delete mFocusChangedCallback; - delete mTopLostCallback; + delete mFocusLostCallback; + delete mFocusReceivedCallback; + delete mFocusChangedCallback; + delete mTopLostCallback; } void LLFocusableElement::onFocusReceived() { - if (mFocusReceivedCallback) (*mFocusReceivedCallback)(this); - if (mFocusChangedCallback) (*mFocusChangedCallback)(this); + if (mFocusReceivedCallback) (*mFocusReceivedCallback)(this); + if (mFocusChangedCallback) (*mFocusChangedCallback)(this); } void LLFocusableElement::onFocusLost() { - if (mFocusLostCallback) (*mFocusLostCallback)(this); - if (mFocusChangedCallback) (*mFocusChangedCallback)(this); + if (mFocusLostCallback) (*mFocusLostCallback)(this); + if (mFocusChangedCallback) (*mFocusChangedCallback)(this); } void LLFocusableElement::onTopLost() { - if (mTopLostCallback) (*mTopLostCallback)(this); + if (mTopLostCallback) (*mTopLostCallback)(this); } BOOL LLFocusableElement::hasFocus() const { - return gFocusMgr.getKeyboardFocus() == this; + return gFocusMgr.getKeyboardFocus() == this; } void LLFocusableElement::setFocus(BOOL b) { } -boost::signals2::connection LLFocusableElement::setFocusLostCallback( const focus_signal_t::slot_type& cb) -{ - if (!mFocusLostCallback) mFocusLostCallback = new focus_signal_t(); - return mFocusLostCallback->connect(cb); +boost::signals2::connection LLFocusableElement::setFocusLostCallback( const focus_signal_t::slot_type& cb) +{ + if (!mFocusLostCallback) mFocusLostCallback = new focus_signal_t(); + return mFocusLostCallback->connect(cb); } -boost::signals2::connection LLFocusableElement::setFocusReceivedCallback(const focus_signal_t::slot_type& cb) -{ - if (!mFocusReceivedCallback) mFocusReceivedCallback = new focus_signal_t(); - return mFocusReceivedCallback->connect(cb); +boost::signals2::connection LLFocusableElement::setFocusReceivedCallback(const focus_signal_t::slot_type& cb) +{ + if (!mFocusReceivedCallback) mFocusReceivedCallback = new focus_signal_t(); + return mFocusReceivedCallback->connect(cb); } -boost::signals2::connection LLFocusableElement::setFocusChangedCallback(const focus_signal_t::slot_type& cb) +boost::signals2::connection LLFocusableElement::setFocusChangedCallback(const focus_signal_t::slot_type& cb) { - if (!mFocusChangedCallback) mFocusChangedCallback = new focus_signal_t(); - return mFocusChangedCallback->connect(cb); + if (!mFocusChangedCallback) mFocusChangedCallback = new focus_signal_t(); + return mFocusChangedCallback->connect(cb); } -boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_signal_t::slot_type& cb) -{ - if (!mTopLostCallback) mTopLostCallback = new focus_signal_t(); - return mTopLostCallback->connect(cb); +boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_signal_t::slot_type& cb) +{ + if (!mTopLostCallback) mTopLostCallback = new focus_signal_t(); + return mTopLostCallback->connect(cb); } @@ -135,283 +135,283 @@ typedef std::list<LLHandle<LLView> > view_handle_list_t; typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t; struct LLFocusMgr::Impl { - // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost - view_handle_list_t mCachedKeyboardFocusList; + // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost + view_handle_list_t mCachedKeyboardFocusList; - focus_history_map_t mFocusHistory; + focus_history_map_t mFocusHistory; }; LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() -: mLockedView( NULL ), - mMouseCaptor( NULL ), - mKeyboardFocus( NULL ), - mLastKeyboardFocus( NULL ), - mDefaultKeyboardFocus( NULL ), - mKeystrokesOnly(FALSE), - mTopCtrl( NULL ), - mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true - mImpl(new LLFocusMgr::Impl) +: mLockedView( NULL ), + mMouseCaptor( NULL ), + mKeyboardFocus( NULL ), + mLastKeyboardFocus( NULL ), + mDefaultKeyboardFocus( NULL ), + mKeystrokesOnly(FALSE), + mTopCtrl( NULL ), + mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true + mImpl(new LLFocusMgr::Impl) { } LLFocusMgr::~LLFocusMgr() { - mImpl->mFocusHistory.clear(); - delete mImpl; - mImpl = NULL; + mImpl->mFocusHistory.clear(); + delete mImpl; + mImpl = NULL; } void LLFocusMgr::releaseFocusIfNeeded( LLView* view ) { - if( childHasMouseCapture( view ) ) - { - setMouseCapture( NULL ); - } + if( childHasMouseCapture( view ) ) + { + setMouseCapture( NULL ); + } - if( childHasKeyboardFocus( view )) - { - if (view == mLockedView) - { - mLockedView = NULL; - setKeyboardFocus( NULL ); - } - else - { - setKeyboardFocus( mLockedView ); - } - } + if( childHasKeyboardFocus( view )) + { + if (view == mLockedView) + { + mLockedView = NULL; + setKeyboardFocus( NULL ); + } + else + { + setKeyboardFocus( mLockedView ); + } + } - LLUI::getInstance()->removePopup(view); + LLUI::getInstance()->removePopup(view); } void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) { - // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived) + // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived) // making the rest of our processing unnecessary since it will already be // handled by the recursive call - static bool focus_dirty; - focus_dirty = false; - - if (mLockedView && - (new_focus == NULL || - (new_focus != mLockedView - && dynamic_cast<LLView*>(new_focus) - && !dynamic_cast<LLView*>(new_focus)->hasAncestor(mLockedView)))) - { - // don't allow focus to go to anything that is not the locked focus - // or one of its descendants - return; - } - - mKeystrokesOnly = keystrokes_only; - - if( new_focus != mKeyboardFocus ) - { - mLastKeyboardFocus = mKeyboardFocus; - mKeyboardFocus = new_focus; - - // list of the focus and it's ancestors - view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList; - view_handle_list_t new_focus_list; - - // walk up the tree to root and add all views to the new_focus_list - for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl; ctrl = ctrl->getParent()) - { - new_focus_list.push_back(ctrl->getHandle()); - } - - // remove all common ancestors since their focus is unchanged - while (!new_focus_list.empty() && - !old_focus_list.empty() && - new_focus_list.back() == old_focus_list.back()) - { - new_focus_list.pop_back(); - old_focus_list.pop_back(); - } - - // walk up the old focus branch calling onFocusLost - // we bubble up the tree to release focus, and back down to add - for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin(); - old_focus_iter != old_focus_list.end() && !focus_dirty; - old_focus_iter++) - { - LLView* old_focus_view = old_focus_iter->get(); - if (old_focus_view) - { - mImpl->mCachedKeyboardFocusList.pop_front(); - old_focus_view->onFocusLost(); - } - } - - // walk down the new focus branch calling onFocusReceived - for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin(); - new_focus_riter != new_focus_list.rend() && !focus_dirty; - new_focus_riter++) - { - LLView* new_focus_view = new_focus_riter->get(); - if (new_focus_view) - { + static bool focus_dirty; + focus_dirty = false; + + if (mLockedView && + (new_focus == NULL || + (new_focus != mLockedView + && dynamic_cast<LLView*>(new_focus) + && !dynamic_cast<LLView*>(new_focus)->hasAncestor(mLockedView)))) + { + // don't allow focus to go to anything that is not the locked focus + // or one of its descendants + return; + } + + mKeystrokesOnly = keystrokes_only; + + if( new_focus != mKeyboardFocus ) + { + mLastKeyboardFocus = mKeyboardFocus; + mKeyboardFocus = new_focus; + + // list of the focus and it's ancestors + view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList; + view_handle_list_t new_focus_list; + + // walk up the tree to root and add all views to the new_focus_list + for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl; ctrl = ctrl->getParent()) + { + new_focus_list.push_back(ctrl->getHandle()); + } + + // remove all common ancestors since their focus is unchanged + while (!new_focus_list.empty() && + !old_focus_list.empty() && + new_focus_list.back() == old_focus_list.back()) + { + new_focus_list.pop_back(); + old_focus_list.pop_back(); + } + + // walk up the old focus branch calling onFocusLost + // we bubble up the tree to release focus, and back down to add + for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin(); + old_focus_iter != old_focus_list.end() && !focus_dirty; + old_focus_iter++) + { + LLView* old_focus_view = old_focus_iter->get(); + if (old_focus_view) + { + mImpl->mCachedKeyboardFocusList.pop_front(); + old_focus_view->onFocusLost(); + } + } + + // walk down the new focus branch calling onFocusReceived + for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin(); + new_focus_riter != new_focus_list.rend() && !focus_dirty; + new_focus_riter++) + { + LLView* new_focus_view = new_focus_riter->get(); + if (new_focus_view) + { mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle()); - new_focus_view->onFocusReceived(); - } - } - - // if focus was changed as part of an onFocusLost or onFocusReceived call - // stop iterating on current list since it is now invalid - if (focus_dirty) - { - return; - } - - // If we've got a default keyboard focus, and the caller is - // releasing keyboard focus, move to the default. - if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL) - { - mDefaultKeyboardFocus->setFocus(TRUE); - } - - LLView* focus_subtree = dynamic_cast<LLView*>(mKeyboardFocus); - LLView* viewp = dynamic_cast<LLView*>(mKeyboardFocus); - // find root-most focus root - while(viewp) - { - if (viewp->isFocusRoot()) - { - focus_subtree = viewp; - } - viewp = viewp->getParent(); - } - - - if (focus_subtree) - { - LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus); - mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>(); - } - } - - if (lock) - { - lockFocus(); - } - - focus_dirty = true; + new_focus_view->onFocusReceived(); + } + } + + // if focus was changed as part of an onFocusLost or onFocusReceived call + // stop iterating on current list since it is now invalid + if (focus_dirty) + { + return; + } + + // If we've got a default keyboard focus, and the caller is + // releasing keyboard focus, move to the default. + if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL) + { + mDefaultKeyboardFocus->setFocus(TRUE); + } + + LLView* focus_subtree = dynamic_cast<LLView*>(mKeyboardFocus); + LLView* viewp = dynamic_cast<LLView*>(mKeyboardFocus); + // find root-most focus root + while(viewp) + { + if (viewp->isFocusRoot()) + { + focus_subtree = viewp; + } + viewp = viewp->getParent(); + } + + + if (focus_subtree) + { + LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus); + mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>(); + } + } + + if (lock) + { + lockFocus(); + } + + focus_dirty = true; } // Returns TRUE is parent or any descedent of parent has keyboard focus. BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const { - LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); - while( focus_view ) - { - if( focus_view == parent ) - { - return TRUE; - } - focus_view = focus_view->getParent(); - } - return FALSE; + LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); + while( focus_view ) + { + if( focus_view == parent ) + { + return TRUE; + } + focus_view = focus_view->getParent(); + } + return FALSE; } // Returns TRUE is parent or any descedent of parent is the mouse captor. BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const { - if( mMouseCaptor && dynamic_cast<LLView*>(mMouseCaptor) != NULL ) - { - LLView* captor_view = (LLView*)mMouseCaptor; - while( captor_view ) - { - if( captor_view == parent ) - { - return TRUE; - } - captor_view = captor_view->getParent(); - } - } - return FALSE; + if( mMouseCaptor && dynamic_cast<LLView*>(mMouseCaptor) != NULL ) + { + LLView* captor_view = (LLView*)mMouseCaptor; + while( captor_view ) + { + if( captor_view == parent ) + { + return TRUE; + } + captor_view = captor_view->getParent(); + } + } + return FALSE; } void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ) { - // should be ok to unlock here, as you have to know the locked view - // in order to unlock it - if (focus == mLockedView) - { - mLockedView = NULL; - } + // should be ok to unlock here, as you have to know the locked view + // in order to unlock it + if (focus == mLockedView) + { + mLockedView = NULL; + } - if( mKeyboardFocus == focus ) - { - mKeyboardFocus = NULL; - } + if( mKeyboardFocus == focus ) + { + mKeyboardFocus = NULL; + } } bool LLFocusMgr::keyboardFocusHasAccelerators() const { - LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); - while( focus_view ) - { - if(focus_view->hasAccelerators()) - { - return true; - } + LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus); + while( focus_view ) + { + if(focus_view->hasAccelerators()) + { + return true; + } - focus_view = focus_view->getParent(); - } - return false; + focus_view = focus_view->getParent(); + } + return false; } void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor ) { - if( new_captor != mMouseCaptor ) - { - LLMouseHandler* old_captor = mMouseCaptor; - mMouseCaptor = new_captor; - - if (LLView::sDebugMouseHandling) - { - if (new_captor) - { - LL_INFOS() << "New mouse captor: " << new_captor->getName() << LL_ENDL; - } - else - { - LL_INFOS() << "New mouse captor: NULL" << LL_ENDL; - } - } - - if( old_captor ) - { - old_captor->onMouseCaptureLost(); - } - - } + if( new_captor != mMouseCaptor ) + { + LLMouseHandler* old_captor = mMouseCaptor; + mMouseCaptor = new_captor; + + if (LLView::sDebugMouseHandling) + { + if (new_captor) + { + LL_INFOS() << "New mouse captor: " << new_captor->getName() << LL_ENDL; + } + else + { + LL_INFOS() << "New mouse captor: NULL" << LL_ENDL; + } + } + + if( old_captor ) + { + old_captor->onMouseCaptureLost(); + } + + } } void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor ) { - if( mMouseCaptor == captor ) - { - mMouseCaptor = NULL; - } + if( mMouseCaptor == captor ) + { + mMouseCaptor = NULL; + } } BOOL LLFocusMgr::childIsTopCtrl( const LLView* parent ) const { - LLView* top_view = (LLView*)mTopCtrl; - while( top_view ) - { - if( top_view == parent ) - { - return TRUE; - } - top_view = top_view->getParent(); - } - return FALSE; + LLView* top_view = (LLView*)mTopCtrl; + while( top_view ) + { + if( top_view == parent ) + { + return TRUE; + } + top_view = top_view->getParent(); + } + return FALSE; } @@ -419,91 +419,91 @@ BOOL LLFocusMgr::childIsTopCtrl( const LLView* parent ) const // set new_top = NULL to release top_view. void LLFocusMgr::setTopCtrl( LLUICtrl* new_top ) { - LLUICtrl* old_top = mTopCtrl; - if( new_top != old_top ) - { - mTopCtrl = new_top; + LLUICtrl* old_top = mTopCtrl; + if( new_top != old_top ) + { + mTopCtrl = new_top; - if (old_top) - { - old_top->onTopLost(); - } - } + if (old_top) + { + old_top->onTopLost(); + } + } } void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view ) { - if( mTopCtrl == top_view ) - { - mTopCtrl = NULL; - } + if( mTopCtrl == top_view ) + { + mTopCtrl = NULL; + } } void LLFocusMgr::lockFocus() { - mLockedView = dynamic_cast<LLUICtrl*>(mKeyboardFocus); + mLockedView = dynamic_cast<LLUICtrl*>(mKeyboardFocus); } void LLFocusMgr::unlockFocus() { - mLockedView = NULL; + mLockedView = NULL; } F32 LLFocusMgr::getFocusFlashAmt() const { - return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f); + return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f); } LLColor4 LLFocusMgr::getFocusColor() const { - static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor"); - LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt()); - // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem) - if (!mAppHasFocus) - { - focus_color.mV[VALPHA] *= 0.4f; - } - return focus_color; + static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor"); + LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt()); + // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem) + if (!mAppHasFocus) + { + focus_color.mV[VALPHA] *= 0.4f; + } + return focus_color; } void LLFocusMgr::triggerFocusFlash() { - mFocusFlashTimer.reset(); + mFocusFlashTimer.reset(); } -void LLFocusMgr::setAppHasFocus(BOOL focus) -{ - if (!mAppHasFocus && focus) - { - triggerFocusFlash(); - } - - // release focus from "top ctrl"s, which generally hides them - if (!focus) - { - LLUI::getInstance()->clearPopups(); - } - mAppHasFocus = focus; +void LLFocusMgr::setAppHasFocus(BOOL focus) +{ + if (!mAppHasFocus && focus) + { + triggerFocusFlash(); + } + + // release focus from "top ctrl"s, which generally hides them + if (!focus) + { + LLUI::getInstance()->clearPopups(); + } + mAppHasFocus = focus; } LLView* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const { - if (subtree_root) - { - focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle()); - if (found_it != mImpl->mFocusHistory.end()) - { - // found last focus for this subtree - return found_it->second.get(); - } - } - return NULL; + if (subtree_root) + { + focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle()); + if (found_it != mImpl->mFocusHistory.end()) + { + // found last focus for this subtree + return found_it->second.get(); + } + } + return NULL; } void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root) { - if (subtree_root) - { - mImpl->mFocusHistory.erase(subtree_root->getHandle()); - } + if (subtree_root) + { + mImpl->mFocusHistory.erase(subtree_root->getHandle()); + } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 0e3d7d8e59..964897500c 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -1,25 +1,25 @@ -/** +/** * @file llfocusmgr.h * @brief LLFocusMgr base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,117 +40,117 @@ class LLView; // NOTE: the LLFocusableElement class declaration has been moved here from lluictrl.h. class LLFocusableElement { - friend class LLFocusMgr; // allow access to focus change handlers + friend class LLFocusMgr; // allow access to focus change handlers public: - LLFocusableElement(); - virtual ~LLFocusableElement(); + LLFocusableElement(); + virtual ~LLFocusableElement(); + + virtual void setFocus( BOOL b ); + virtual BOOL hasFocus() const; - virtual void setFocus( BOOL b ); - virtual BOOL hasFocus() const; + typedef boost::signals2::signal<void(LLFocusableElement*)> focus_signal_t; - typedef boost::signals2::signal<void(LLFocusableElement*)> focus_signal_t; - - boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb); - boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); - boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb); - boost::signals2::connection setTopLostCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setTopLostCallback(const focus_signal_t::slot_type& cb); - // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); /** - * If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages - * even for normal character strokes. + * If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages + * even for normal character strokes. * Default implementation returns false. */ virtual bool wantsKeyUpKeyDown() const; virtual bool wantsReturnKey() const; - virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere -protected: - virtual void onFocusReceived(); - virtual void onFocusLost(); - focus_signal_t* mFocusLostCallback; - focus_signal_t* mFocusReceivedCallback; - focus_signal_t* mFocusChangedCallback; - focus_signal_t* mTopLostCallback; + virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere +protected: + virtual void onFocusReceived(); + virtual void onFocusLost(); + focus_signal_t* mFocusLostCallback; + focus_signal_t* mFocusReceivedCallback; + focus_signal_t* mFocusChangedCallback; + focus_signal_t* mTopLostCallback; }; class LLFocusMgr { public: - LLFocusMgr(); - ~LLFocusMgr(); - - // Mouse Captor - void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse. - LLMouseHandler* getMouseCapture() const { return mMouseCaptor; } - void removeMouseCaptureWithoutCallback( const LLMouseHandler* captor ); - BOOL childHasMouseCapture( const LLView* parent ) const; - - // Keyboard Focus - void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. - LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; } - LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } - BOOL childHasKeyboardFocus( const LLView* parent ) const; - void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ); - BOOL getKeystrokesOnly() { return mKeystrokesOnly; } - void setKeystrokesOnly(BOOL keystrokes_only) { mKeystrokesOnly = keystrokes_only; } - - F32 getFocusFlashAmt() const; - S32 getFocusFlashWidth() const { return ll_round(lerp(1.f, 3.f, getFocusFlashAmt())); } - LLColor4 getFocusColor() const; - void triggerFocusFlash(); - BOOL getAppHasFocus() const { return mAppHasFocus; } - void setAppHasFocus(BOOL focus); - LLView* getLastFocusForGroup(LLView* subtree_root) const; - void clearLastFocusForGroup(LLView* subtree_root); - - // If setKeyboardFocus(NULL) is called, and there is a non-NULL default - // keyboard focus view, focus goes there. JC - void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; } - LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } - - - // Top View - void setTopCtrl(LLUICtrl* new_top); - LLUICtrl* getTopCtrl() const { return mTopCtrl; } - void removeTopCtrlWithoutCallback( const LLUICtrl* top_view ); - BOOL childIsTopCtrl( const LLView* parent ) const; - - // All Three - void releaseFocusIfNeeded( LLView* top_view ); - void lockFocus(); - void unlockFocus(); - BOOL focusLocked() const { return mLockedView != NULL; } - - bool keyboardFocusHasAccelerators() const; - - struct Impl; + LLFocusMgr(); + ~LLFocusMgr(); + + // Mouse Captor + void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse. + LLMouseHandler* getMouseCapture() const { return mMouseCaptor; } + void removeMouseCaptureWithoutCallback( const LLMouseHandler* captor ); + BOOL childHasMouseCapture( const LLView* parent ) const; + + // Keyboard Focus + void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. + LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; } + LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } + BOOL childHasKeyboardFocus( const LLView* parent ) const; + void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ); + BOOL getKeystrokesOnly() { return mKeystrokesOnly; } + void setKeystrokesOnly(BOOL keystrokes_only) { mKeystrokesOnly = keystrokes_only; } + + F32 getFocusFlashAmt() const; + S32 getFocusFlashWidth() const { return ll_round(lerp(1.f, 3.f, getFocusFlashAmt())); } + LLColor4 getFocusColor() const; + void triggerFocusFlash(); + BOOL getAppHasFocus() const { return mAppHasFocus; } + void setAppHasFocus(BOOL focus); + LLView* getLastFocusForGroup(LLView* subtree_root) const; + void clearLastFocusForGroup(LLView* subtree_root); + + // If setKeyboardFocus(NULL) is called, and there is a non-NULL default + // keyboard focus view, focus goes there. JC + void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; } + LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } + + + // Top View + void setTopCtrl(LLUICtrl* new_top); + LLUICtrl* getTopCtrl() const { return mTopCtrl; } + void removeTopCtrlWithoutCallback( const LLUICtrl* top_view ); + BOOL childIsTopCtrl( const LLView* parent ) const; + + // All Three + void releaseFocusIfNeeded( LLView* top_view ); + void lockFocus(); + void unlockFocus(); + BOOL focusLocked() const { return mLockedView != NULL; } + + bool keyboardFocusHasAccelerators() const; + + struct Impl; private: - LLUICtrl* mLockedView; + LLUICtrl* mLockedView; + + // Mouse Captor + LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object - // Mouse Captor - LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object + // Keyboard Focus + LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object + LLFocusableElement* mLastKeyboardFocus; // who last had focus + LLFocusableElement* mDefaultKeyboardFocus; + BOOL mKeystrokesOnly; - // Keyboard Focus - LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object - LLFocusableElement* mLastKeyboardFocus; // who last had focus - LLFocusableElement* mDefaultKeyboardFocus; - BOOL mKeystrokesOnly; - - // Top View - LLUICtrl* mTopCtrl; + // Top View + LLUICtrl* mTopCtrl; - LLFrameTimer mFocusFlashTimer; + LLFrameTimer mFocusFlashTimer; - BOOL mAppHasFocus; + BOOL mAppHasFocus; - Impl * mImpl; + Impl * mImpl; }; extern LLFocusMgr gFocusMgr; diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 650ae9ae75..33921cf4f0 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfolderview.cpp * @brief Implementation of the folder view collection of classes. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,7 +43,7 @@ #include "lldbstrings.h" #include "llfocusmgr.h" #include "llfontgl.h" -#include "llgl.h" +#include "llgl.h" #include "llrender.h" // Third-party library includes @@ -63,8 +63,8 @@ const S32 STATUS_TEXT_HPAD = 6; const S32 STATUS_TEXT_VPAD = 8; enum { - SIGNAL_NO_KEYBOARD_FOCUS = 1, - SIGNAL_KEYBOARD_FOCUS = 2 + SIGNAL_NO_KEYBOARD_FOCUS = 1, + SIGNAL_KEYBOARD_FOCUS = 2 }; F32 LLFolderView::sAutoOpenTime = 1.f; @@ -74,28 +74,28 @@ F32 LLFolderView::sAutoOpenTime = 1.f; // Tells all folders in a folderview to close themselves // For efficiency, calls setOpenArrangeRecursively(). // The calling function must then call: -// LLFolderView* root = getRoot(); -// if( root ) -// { -// root->arrange( NULL, NULL ); -// root->scrollToShowSelection(); -// } +// LLFolderView* root = getRoot(); +// if( root ) +// { +// root->arrange( NULL, NULL ); +// root->scrollToShowSelection(); +// } // to patch things up. class LLCloseAllFoldersFunctor : public LLFolderViewFunctor { public: - LLCloseAllFoldersFunctor(BOOL close) { mOpen = !close; } - virtual ~LLCloseAllFoldersFunctor() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); + LLCloseAllFoldersFunctor(BOOL close) { mOpen = !close; } + virtual ~LLCloseAllFoldersFunctor() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); - BOOL mOpen; + BOOL mOpen; }; void LLCloseAllFoldersFunctor::doFolder(LLFolderViewFolder* folder) { - folder->setOpenArrangeRecursively(mOpen); + folder->setOpenArrangeRecursively(mOpen); } // Do nothing. @@ -106,12 +106,12 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) void LLAllDescendentsPassedFilter::doFolder(LLFolderViewFolder* folder) { - mAllDescendentsPassedFilter &= (folder) && (folder->passedFilter()) && (folder->descendantsPassedFilter()); + mAllDescendentsPassedFilter &= (folder) && (folder->passedFilter()) && (folder->descendantsPassedFilter()); } void LLAllDescendentsPassedFilter::doItem(LLFolderViewItem* item) { - mAllDescendentsPassedFilter &= (item) && (item->passedFilter()); + mAllDescendentsPassedFilter &= (item) && (item->passedFilter()); } ///---------------------------------------------------------------------------- @@ -121,296 +121,302 @@ void LLAllDescendentsPassedFilter::doItem(LLFolderViewItem* item) // virtual const LLRect LLFolderViewScrollContainer::getScrolledViewRect() const { - LLRect rect = LLRect::null; - if (mScrolledView) - { - LLFolderView* folder_view = dynamic_cast<LLFolderView*>(mScrolledView); - if (folder_view) - { - S32 height = folder_view->getRect().getHeight(); + LLRect rect = LLRect::null; + if (mScrolledView) + { + LLFolderView* folder_view = dynamic_cast<LLFolderView*>(mScrolledView); + if (folder_view) + { + S32 height = folder_view->getRect().getHeight(); - rect = mScrolledView->getRect(); - rect.setLeftTopAndSize(rect.mLeft, rect.mTop, rect.getWidth(), height); - } - } + rect = mScrolledView->getRect(); + rect.setLeftTopAndSize(rect.mLeft, rect.mTop, rect.getWidth(), height); + } + } - return rect; + return rect; } LLFolderViewScrollContainer::LLFolderViewScrollContainer(const LLScrollContainer::Params& p) -: LLScrollContainer(p) +: LLScrollContainer(p) {} ///---------------------------------------------------------------------------- /// Class LLFolderView ///---------------------------------------------------------------------------- LLFolderView::Params::Params() -: title("title"), - use_label_suffix("use_label_suffix"), - allow_multiselect("allow_multiselect", true), - allow_drag("allow_drag", true), - show_empty_message("show_empty_message", true), - suppress_folder_menu("suppress_folder_menu", false), - use_ellipses("use_ellipses", false), +: title("title"), + use_label_suffix("use_label_suffix"), + allow_multiselect("allow_multiselect", true), + allow_drag("allow_drag", true), + show_empty_message("show_empty_message", true), + suppress_folder_menu("suppress_folder_menu", false), + use_ellipses("use_ellipses", false), options_menu("options_menu", "") { - folder_indentation = -4; + folder_indentation = -4; } // Default constructor LLFolderView::LLFolderView(const Params& p) -: LLFolderViewFolder(p), - mScrollContainer( NULL ), - mPopupMenuHandle(), - mMenuFileName(p.options_menu), - mAllowMultiSelect(p.allow_multiselect), - mAllowDrag(p.allow_drag), - mShowEmptyMessage(p.show_empty_message), - mShowFolderHierarchy(FALSE), - mRenameItem( NULL ), - mNeedsScroll( FALSE ), - mUseLabelSuffix(p.use_label_suffix), - mSuppressFolderMenu(p.suppress_folder_menu), - mPinningSelectedItem(FALSE), - mNeedsAutoSelect( FALSE ), - mAutoSelectOverride(FALSE), - mNeedsAutoRename(FALSE), - mShowSelectionContext(FALSE), - mShowSingleSelection(FALSE), - mArrangeGeneration(0), - mSignalSelectCallback(0), - mMinWidth(0), - mDragAndDropThisFrame(FALSE), - mCallbackRegistrar(NULL), - mEnableRegistrar(NULL), - mUseEllipses(p.use_ellipses), - mDraggingOverItem(NULL), - mStatusTextBox(NULL), - mShowItemLinkOverlays(p.show_item_link_overlays), - mViewModel(p.view_model), +: LLFolderViewFolder(p), + mScrollContainer( NULL ), + mPopupMenuHandle(), + mMenuFileName(p.options_menu), + mAllowMultiSelect(p.allow_multiselect), + mAllowDrag(p.allow_drag), + mShowEmptyMessage(p.show_empty_message), + mShowFolderHierarchy(FALSE), + mRenameItem( NULL ), + mNeedsScroll( FALSE ), + mUseLabelSuffix(p.use_label_suffix), + mSuppressFolderMenu(p.suppress_folder_menu), + mPinningSelectedItem(FALSE), + mNeedsAutoSelect( FALSE ), + mAutoSelectOverride(FALSE), + mNeedsAutoRename(FALSE), + mShowSelectionContext(FALSE), + mShowSingleSelection(FALSE), + mArrangeGeneration(0), + mSignalSelectCallback(0), + mMinWidth(0), + mDragAndDropThisFrame(FALSE), + mCallbackRegistrar(NULL), + mEnableRegistrar(NULL), + mUseEllipses(p.use_ellipses), + mDraggingOverItem(NULL), + mStatusTextBox(NULL), + mShowItemLinkOverlays(p.show_item_link_overlays), + mViewModel(p.view_model), mGroupedItemModel(p.grouped_item_model), mForceArrange(false), mSingleFolderMode(false) { LLPanel* panel = p.parent_panel; mParentPanel = panel->getHandle(); - mViewModel->setFolderView(this); - mRoot = this; - - LLRect rect = p.rect; - LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); - setRect( rect ); - reshape(rect.getWidth(), rect.getHeight()); - mAutoOpenItems.setDepth(AUTO_OPEN_STACK_DEPTH); - mAutoOpenCandidate = NULL; - mAutoOpenTimer.stop(); - mKeyboardSelection = FALSE; - mIndentation = getParentFolder() ? getParentFolder()->getIndentation() + mLocalIndentation : 0; - - //clear label - // go ahead and render root folder as usual - // just make sure the label ("Inventory Folder") never shows up - mLabel = LLStringUtil::null; - - // Escape is handled by reverting the rename, not commiting it (default behavior) - LLLineEditor::Params params; - params.name("ren"); - params.rect(rect); - params.font(getLabelFontForStyle(LLFontGL::NORMAL)); - params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN); - params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); - params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe); - params.commit_on_focus_lost(true); - params.visible(false); - mRenamer = LLUICtrlFactory::create<LLLineEditor> (params); - addChild(mRenamer); - - // Textbox - LLTextBox::Params text_p; - LLFontGL* font = getLabelFontForStyle(mLabelStyle); + mViewModel->setFolderView(this); + mRoot = this; + + LLRect rect = p.rect; + LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); + setRect( rect ); + reshape(rect.getWidth(), rect.getHeight()); + mAutoOpenItems.setDepth(AUTO_OPEN_STACK_DEPTH); + mAutoOpenCandidate = NULL; + mAutoOpenTimer.stop(); + mKeyboardSelection = FALSE; + mIndentation = getParentFolder() ? getParentFolder()->getIndentation() + mLocalIndentation : 0; + + //clear label + // go ahead and render root folder as usual + // just make sure the label ("Inventory Folder") never shows up + mLabel = LLStringUtil::null; + + // Escape is handled by reverting the rename, not commiting it (default behavior) + LLLineEditor::Params params; + params.name("ren"); + params.rect(rect); + params.font(getLabelFontForStyle(LLFontGL::NORMAL)); + params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN); + params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); + params.prevalidator(&LLTextValidate::validateASCIIPrintableNoPipe); + params.commit_on_focus_lost(true); + params.visible(false); + mRenamer = LLUICtrlFactory::create<LLLineEditor> (params); + addChild(mRenamer); + + // Textbox + LLTextBox::Params text_p; + LLFontGL* font = getLabelFontForStyle(mLabelStyle); //mIconPad, mTextPad are set in folder_view_item.xml - LLRect new_r = LLRect(rect.mLeft + mIconPad, - rect.mTop - mTextPad, - rect.mRight, - rect.mTop - mTextPad - font->getLineHeight()); - text_p.rect(new_r); - text_p.name(std::string(p.name)); - text_p.font(font); - text_p.visible(false); - text_p.parse_urls(true); - text_p.wrap(true); // allow multiline text. See EXT-7564, EXT-7047 - // set text padding the same as in People panel. EXT-7047, EXT-4837 - text_p.h_pad(STATUS_TEXT_HPAD); - text_p.v_pad(STATUS_TEXT_VPAD); - mStatusTextBox = LLUICtrlFactory::create<LLTextBox> (text_p); - mStatusTextBox->setFollowsLeft(); - mStatusTextBox->setFollowsTop(); - addChild(mStatusTextBox); - - mViewModelItem->openItem(); - - mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited. + LLRect new_r = LLRect(rect.mLeft + mIconPad, + rect.mTop - mTextPad, + rect.mRight, + rect.mTop - mTextPad - font->getLineHeight()); + text_p.rect(new_r); + text_p.name(std::string(p.name)); + text_p.font(font); + text_p.visible(false); + text_p.parse_urls(true); + text_p.wrap(true); // allow multiline text. See EXT-7564, EXT-7047 + // set text padding the same as in People panel. EXT-7047, EXT-4837 + text_p.h_pad(STATUS_TEXT_HPAD); + text_p.v_pad(STATUS_TEXT_VPAD); + mStatusTextBox = LLUICtrlFactory::create<LLTextBox> (text_p); + mStatusTextBox->setFollowsLeft(); + mStatusTextBox->setFollowsTop(); + addChild(mStatusTextBox); + + mViewModelItem->openItem(); + + mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited. } // Destroys the object LLFolderView::~LLFolderView( void ) { - closeRenamer(); + mRenamerTopLostSignalConnection.disconnect(); + if (mRenamer) + { + // instead of using closeRenamer remove it directly, + // since it might already be hidden + LLUI::getInstance()->removePopup(mRenamer); + } - // The release focus call can potentially call the - // scrollcontainer, which can potentially be called with a partly - // destroyed scollcontainer. Just null it out here, and no worries - // about calling into the invalid scroll container. - // Same with the renamer. - mScrollContainer = NULL; - mRenameItem = NULL; - mRenamer = NULL; - mStatusTextBox = NULL; + // The release focus call can potentially call the + // scrollcontainer, which can potentially be called with a partly + // destroyed scollcontainer. Just null it out here, and no worries + // about calling into the invalid scroll container. + // Same with the renamer. + mScrollContainer = NULL; + mRenameItem = NULL; + mRenamer = NULL; + mStatusTextBox = NULL; - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); - mPopupMenuHandle.markDead(); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + mPopupMenuHandle.markDead(); - mAutoOpenItems.removeAllNodes(); - clearSelection(); - mItems.clear(); - mFolders.clear(); + mAutoOpenItems.removeAllNodes(); + clearSelection(); + mItems.clear(); + mFolders.clear(); - //mViewModel->setFolderView(NULL); - mViewModel = NULL; + //mViewModel->setFolderView(NULL); + mViewModel = NULL; } BOOL LLFolderView::canFocusChildren() const { - return FALSE; + return FALSE; } void LLFolderView::addFolder( LLFolderViewFolder* folder) { - LLFolderViewFolder::addFolder(folder); + LLFolderViewFolder::addFolder(folder); } void LLFolderView::closeAllFolders() { - // Close all the folders - setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); - arrangeAll(); + // Close all the folders + setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + arrangeAll(); } void LLFolderView::openTopLevelFolders() { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->setOpen(TRUE); - } + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setOpen(TRUE); + } } // This view grows and shrinks to enclose all of its children items and folders. // *width should be 0 // conform show folder state works S32 LLFolderView::arrange( S32* unused_width, S32* unused_height ) - { - mMinWidth = 0; - S32 target_height; + { + mMinWidth = 0; + S32 target_height; - LLFolderViewFolder::arrange(&mMinWidth, &target_height); + LLFolderViewFolder::arrange(&mMinWidth, &target_height); - LLRect scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); - reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) ); + LLRect scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); + reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) ); - LLRect new_scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); - if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) - { - reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) ); - } + LLRect new_scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); + if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) + { + reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) ); + } - // move item renamer text field to item's new position - updateRenamerPosition(); + // move item renamer text field to item's new position + updateRenamerPosition(); - return ll_round(mTargetHeight); + return ll_round(mTargetHeight); } void LLFolderView::filter( LLFolderViewFilter& filter ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); - filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100)); + const S32 TIME_VISIBLE = 10; // in milliseconds + const S32 TIME_INVISIBLE = 1; + filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? TIME_VISIBLE : TIME_INVISIBLE), 1, 100)); // Note: we filter the model, not the view - getViewModelItem()->filter(filter); + getViewModelItem()->filter(filter); } void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLRect scroll_rect; - if (mScrollContainer) - { - LLView::reshape(width, height, called_from_parent); - scroll_rect = mScrollContainer->getContentWindowRect(); - } - width = llmax(mMinWidth, scroll_rect.getWidth()); - height = llmax(ll_round(mCurHeight), scroll_rect.getHeight()); + LLRect scroll_rect; + if (mScrollContainer) + { + LLView::reshape(width, height, called_from_parent); + scroll_rect = mScrollContainer->getContentWindowRect(); + } + width = llmax(mMinWidth, scroll_rect.getWidth()); + height = llmax(ll_round(mCurHeight), scroll_rect.getHeight()); - // Restrict width within scroll container's width - if (mUseEllipses && mScrollContainer) - { - width = scroll_rect.getWidth(); - } - LLView::reshape(width, height, called_from_parent); - mReshapeSignal(mSelectedItems, FALSE); + // Restrict width within scroll container's width + if (mUseEllipses && mScrollContainer) + { + width = scroll_rect.getWidth(); + } + LLView::reshape(width, height, called_from_parent); + mReshapeSignal(mSelectedItems, FALSE); } void LLFolderView::addToSelectionList(LLFolderViewItem* item) { - if (item->isSelected()) - { - removeFromSelectionList(item); - } - if (mSelectedItems.size()) - { - mSelectedItems.back()->setIsCurSelection(FALSE); - } - item->setIsCurSelection(TRUE); - mSelectedItems.push_back(item); + if (item->isSelected()) + { + removeFromSelectionList(item); + } + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(FALSE); + } + item->setIsCurSelection(TRUE); + mSelectedItems.push_back(item); } void LLFolderView::removeFromSelectionList(LLFolderViewItem* item) { - if (mSelectedItems.size()) - { - mSelectedItems.back()->setIsCurSelection(FALSE); - } - - selected_items_t::iterator item_iter; - for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end();) - { - if (*item_iter == item) - { - item_iter = mSelectedItems.erase(item_iter); - } - else - { - ++item_iter; - } - } - if (mSelectedItems.size()) - { - mSelectedItems.back()->setIsCurSelection(TRUE); - } + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(FALSE); + } + + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end();) + { + if (*item_iter == item) + { + item_iter = mSelectedItems.erase(item_iter); + } + else + { + ++item_iter; + } + } + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(TRUE); + } } LLFolderViewItem* LLFolderView::getCurSelectedItem( void ) { - if(mSelectedItems.size()) - { - LLFolderViewItem* itemp = mSelectedItems.back(); - llassert(itemp->getIsCurSelection()); - return itemp; - } - return NULL; + if(mSelectedItems.size()) + { + LLFolderViewItem* itemp = mSelectedItems.back(); + llassert(itemp->getIsCurSelection()); + return itemp; + } + return NULL; } LLFolderView::selected_items_t& LLFolderView::getSelectedItems( void ) @@ -420,281 +426,281 @@ LLFolderView::selected_items_t& LLFolderView::getSelectedItems( void ) // Record the selected item and pass it down the hierachy. BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus) + BOOL take_keyboard_focus) { - mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS; + mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS; - if( selection == this ) - { - return FALSE; - } + if( selection == this ) + { + return FALSE; + } - if( selection && take_keyboard_focus) - { - mParentPanel.get()->setFocus(TRUE); - } + if( selection && take_keyboard_focus) + { + mParentPanel.get()->setFocus(TRUE); + } - // clear selection down here because change of keyboard focus can potentially - // affect selection - clearSelection(); + // clear selection down here because change of keyboard focus can potentially + // affect selection + clearSelection(); - if(selection) - { - addToSelectionList(selection); - } + if(selection) + { + addToSelectionList(selection); + } - BOOL rv = LLFolderViewFolder::setSelection(selection, openitem, take_keyboard_focus); - if(openitem && selection) - { - selection->getParentFolder()->requestArrange(); - } + BOOL rv = LLFolderViewFolder::setSelection(selection, openitem, take_keyboard_focus); + if(openitem && selection) + { + selection->getParentFolder()->requestArrange(); + } - llassert(mSelectedItems.size() <= 1); + llassert(mSelectedItems.size() <= 1); - return rv; + return rv; } BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) { - BOOL rv = FALSE; + BOOL rv = FALSE; - // can't select root folder - if(!selection || selection == this) - { - return FALSE; - } + // can't select root folder + if(!selection || selection == this) + { + return FALSE; + } - if (!mAllowMultiSelect) - { - clearSelection(); - } + if (!mAllowMultiSelect) + { + clearSelection(); + } - selected_items_t::iterator item_iter; - for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) - { - if (*item_iter == selection) - { - break; - } - } + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + if (*item_iter == selection) + { + break; + } + } - BOOL on_list = (item_iter != mSelectedItems.end()); + BOOL on_list = (item_iter != mSelectedItems.end()); + + if(selected && !on_list) + { + addToSelectionList(selection); + } + if(!selected && on_list) + { + removeFromSelectionList(selection); + } - if(selected && !on_list) - { - addToSelectionList(selection); - } - if(!selected && on_list) - { - removeFromSelectionList(selection); - } + rv = LLFolderViewFolder::changeSelection(selection, selected); - rv = LLFolderViewFolder::changeSelection(selection, selected); + mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; - mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; - - return rv; + return rv; } void LLFolderView::sanitizeSelection() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - // store off current item in case it is automatically deselected - // and we want to preserve context - LLFolderViewItem* original_selected_item = getCurSelectedItem(); - - std::vector<LLFolderViewItem*> items_to_remove; - selected_items_t::iterator item_iter; - for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) - { - LLFolderViewItem* item = *item_iter; - - // ensure that each ancestor is open and potentially passes filtering - BOOL visible = false; - if(item->getViewModelItem() != NULL) - { - visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item - } - // modify with parent open and filters states - LLFolderViewFolder* parent_folder = item->getParentFolder(); - // Move up through parent folders and see what's visible - while(parent_folder) - { - visible = visible && parent_folder->isOpen() && parent_folder->getViewModelItem()->potentiallyVisible(); - parent_folder = parent_folder->getParentFolder(); - } - - // deselect item if any ancestor is closed or didn't pass filter requirements. - if (!visible) - { - items_to_remove.push_back(item); - } - - // disallow nested selections (i.e. folder items plus one or more ancestors) - // could check cached mum selections count and only iterate if there are any - // but that may be a premature optimization. - selected_items_t::iterator other_item_iter; - for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter) - { - LLFolderViewItem* other_item = *other_item_iter; - for( parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder()) - { - if (parent_folder == item) - { - // this is a descendent of the current folder, remove from list - items_to_remove.push_back(other_item); - break; - } - } - } - - // Don't allow invisible items (such as root folders) to be selected. - if (item == getRoot()) - { - items_to_remove.push_back(item); - } - } - - std::vector<LLFolderViewItem*>::iterator item_it; - for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it ) - { - changeSelection(*item_it, FALSE); // toggle selection (also removes from list) - } - - // if nothing selected after prior constraints... - if (mSelectedItems.empty()) - { - // ...select first available parent of original selection - LLFolderViewItem* new_selection = NULL; - if (original_selected_item) - { - for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder(); - parent_folder; - parent_folder = parent_folder->getParentFolder()) - { - if (parent_folder->getViewModelItem() && parent_folder->getViewModelItem()->potentiallyVisible()) - { - // give initial selection to first ancestor folder that potentially passes the filter - if (!new_selection) - { - new_selection = parent_folder; - } - - // if any ancestor folder of original item is closed, move the selection up - // to the highest closed - if (!parent_folder->isOpen()) - { - new_selection = parent_folder; - } - } - } - } - else - { - new_selection = NULL; - } - - if (new_selection) - { - setSelection(new_selection, FALSE, FALSE); - } - } + // store off current item in case it is automatically deselected + // and we want to preserve context + LLFolderViewItem* original_selected_item = getCurSelectedItem(); + + std::vector<LLFolderViewItem*> items_to_remove; + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + LLFolderViewItem* item = *item_iter; + + // ensure that each ancestor is open and potentially passes filtering + BOOL visible = false; + if(item->getViewModelItem() != NULL) + { + visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item + } + // modify with parent open and filters states + LLFolderViewFolder* parent_folder = item->getParentFolder(); + // Move up through parent folders and see what's visible + while(parent_folder) + { + visible = visible && parent_folder->isOpen() && parent_folder->getViewModelItem()->potentiallyVisible(); + parent_folder = parent_folder->getParentFolder(); + } + + // deselect item if any ancestor is closed or didn't pass filter requirements. + if (!visible) + { + items_to_remove.push_back(item); + } + + // disallow nested selections (i.e. folder items plus one or more ancestors) + // could check cached mum selections count and only iterate if there are any + // but that may be a premature optimization. + selected_items_t::iterator other_item_iter; + for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter) + { + LLFolderViewItem* other_item = *other_item_iter; + for( parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder()) + { + if (parent_folder == item) + { + // this is a descendent of the current folder, remove from list + items_to_remove.push_back(other_item); + break; + } + } + } + + // Don't allow invisible items (such as root folders) to be selected. + if (item == getRoot()) + { + items_to_remove.push_back(item); + } + } + + std::vector<LLFolderViewItem*>::iterator item_it; + for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it ) + { + changeSelection(*item_it, FALSE); // toggle selection (also removes from list) + } + + // if nothing selected after prior constraints... + if (mSelectedItems.empty()) + { + // ...select first available parent of original selection + LLFolderViewItem* new_selection = NULL; + if (original_selected_item) + { + for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder(); + parent_folder; + parent_folder = parent_folder->getParentFolder()) + { + if (parent_folder->getViewModelItem() && parent_folder->getViewModelItem()->potentiallyVisible()) + { + // give initial selection to first ancestor folder that potentially passes the filter + if (!new_selection) + { + new_selection = parent_folder; + } + + // if any ancestor folder of original item is closed, move the selection up + // to the highest closed + if (!parent_folder->isOpen()) + { + new_selection = parent_folder; + } + } + } + } + else + { + new_selection = NULL; + } + + if (new_selection) + { + setSelection(new_selection, FALSE, FALSE); + } + } } void LLFolderView::clearSelection() { - for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); - item_it != mSelectedItems.end(); - ++item_it) - { - (*item_it)->setUnselected(); - } + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); + item_it != mSelectedItems.end(); + ++item_it) + { + (*item_it)->setUnselected(); + } - mSelectedItems.clear(); + mSelectedItems.clear(); mNeedsScroll = false; } std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const { - std::set<LLFolderViewItem*> selection; - std::copy(mSelectedItems.begin(), mSelectedItems.end(), std::inserter(selection, selection.begin())); - return selection; + std::set<LLFolderViewItem*> selection; + std::copy(mSelectedItems.begin(), mSelectedItems.end(), std::inserter(selection, selection.begin())); + return selection; } bool LLFolderView::startDrag() { - std::vector<LLFolderViewModelItem*> selected_items; - selected_items_t::iterator item_it; + std::vector<LLFolderViewModelItem*> selected_items; + selected_items_t::iterator item_it; - if (!mSelectedItems.empty()) - { - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - { - selected_items.push_back((*item_it)->getViewModelItem()); - } + if (!mSelectedItems.empty()) + { + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + selected_items.push_back((*item_it)->getViewModelItem()); + } - return getFolderViewModel()->startDrag(selected_items); - } - return false; + return getFolderViewModel()->startDrag(selected_items); + } + return false; } void LLFolderView::commitRename( const LLSD& data ) { - finishRenamingItem(); - arrange( NULL, NULL ); + finishRenamingItem(); + arrange( NULL, NULL ); } void LLFolderView::draw() { - //LLFontGL* font = getLabelFontForStyle(mLabelStyle); - - // if cursor has moved off of me during drag and drop - // close all auto opened folders - if (!mDragAndDropThisFrame) - { - closeAutoOpenedFolders(); - } - - static LLCachedControl<F32> type_ahead_timeout(*LLUI::getInstance()->mSettingGroups["config"], "TypeAheadTimeout", 1.5f); - if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size()) - { - mSearchString.clear(); - } - - if (hasVisibleChildren()) - { - mStatusTextBox->setVisible( FALSE ); - } - else if (mShowEmptyMessage) - { - mStatusTextBox->setValue(getFolderViewModel()->getStatusText(mItems.empty() && mFolders.empty())); - mStatusTextBox->setVisible( TRUE ); - - // firstly reshape message textbox with current size. This is necessary to - // LLTextBox::getTextPixelHeight works properly - const LLRect local_rect = getLocalRect(); - mStatusTextBox->setShape(local_rect); - - // get preferable text height... - S32 pixel_height = mStatusTextBox->getTextPixelHeight(); - bool height_changed = (local_rect.getHeight() < pixel_height); - if (height_changed) - { - // ... if it does not match current height, lets rearrange current view. - // This will indirectly call ::arrange and reshape of the status textbox. - // We should call this method to also notify parent about required rect. - // See EXT-7564, EXT-7047. - S32 height = 0; - S32 width = 0; - S32 total_height = arrange( &width, &height ); - notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); - - LLUI::popMatrix(); - LLUI::pushMatrix(); - LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); - } - } + //LLFontGL* font = getLabelFontForStyle(mLabelStyle); + + // if cursor has moved off of me during drag and drop + // close all auto opened folders + if (!mDragAndDropThisFrame) + { + closeAutoOpenedFolders(); + } + + static LLCachedControl<F32> type_ahead_timeout(*LLUI::getInstance()->mSettingGroups["config"], "TypeAheadTimeout", 1.5f); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size()) + { + mSearchString.clear(); + } + + if (hasVisibleChildren()) + { + mStatusTextBox->setVisible( FALSE ); + } + else if (mShowEmptyMessage) + { + mStatusTextBox->setValue(getFolderViewModel()->getStatusText(mItems.empty() && mFolders.empty())); + mStatusTextBox->setVisible( TRUE ); + + // firstly reshape message textbox with current size. This is necessary to + // LLTextBox::getTextPixelHeight works properly + const LLRect local_rect = getLocalRect(); + mStatusTextBox->setShape(local_rect); + + // get preferable text height... + S32 pixel_height = mStatusTextBox->getTextPixelHeight(); + bool height_changed = (local_rect.getHeight() < pixel_height); + if (height_changed) + { + // ... if it does not match current height, lets rearrange current view. + // This will indirectly call ::arrange and reshape of the status textbox. + // We should call this method to also notify parent about required rect. + // See EXT-7564, EXT-7047. + S32 height = 0; + S32 width = 0; + S32 total_height = arrange( &width, &height ); + notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); + + LLUI::popMatrix(); + LLUI::pushMatrix(); + LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); + } + } if (mRenameItem && mRenamer @@ -707,342 +713,342 @@ void LLFolderView::draw() finishRenamingItem(); } - // skip over LLFolderViewFolder::draw since we don't want the folder icon, label, - // and arrow for the root folder - LLView::draw(); + // skip over LLFolderViewFolder::draw since we don't want the folder icon, label, + // and arrow for the root folder + LLView::draw(); - mDragAndDropThisFrame = FALSE; + mDragAndDropThisFrame = FALSE; } void LLFolderView::finishRenamingItem( void ) { - if(!mRenamer) - { - return; - } - if( mRenameItem ) - { - mRenameItem->rename( mRenamer->getText() ); - } + if(!mRenamer) + { + return; + } + if( mRenameItem ) + { + mRenameItem->rename( mRenamer->getText() ); + } - closeRenamer(); + closeRenamer(); - // This is moved to an inventory observer in llinventorybridge.cpp, to handle updating after operation completed in AISv3 (SH-4611). - // List is re-sorted alphabetically, so scroll to make sure the selected item is visible. - //scrollToShowSelection(); + // This is moved to an inventory observer in llinventorybridge.cpp, to handle updating after operation completed in AISv3 (SH-4611). + // List is re-sorted alphabetically, so scroll to make sure the selected item is visible. + //scrollToShowSelection(); } void LLFolderView::closeRenamer( void ) { - if (mRenamer && mRenamer->getVisible()) - { - // Triggers onRenamerLost() that actually closes the renamer. - LLUI::getInstance()->removePopup(mRenamer); - } + if (mRenamer && mRenamer->getVisible()) + { + // Triggers onRenamerLost() that actually closes the renamer. + LLUI::getInstance()->removePopup(mRenamer); + } } void LLFolderView::removeSelectedItems() { - if(getVisible() && getEnabled()) - { - // just in case we're removing the renaming item. - mRenameItem = NULL; - - // create a temporary structure which we will use to remove - // items, since the removal will futz with internal data - // structures. - std::vector<LLFolderViewItem*> items; - S32 count = mSelectedItems.size(); - if(count <= 0) return; - LLFolderViewItem* item = NULL; - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - { - item = *item_it; - if (item && item->isRemovable()) - { - items.push_back(item); - } - else - { - LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL; - return; - } - } - - // iterate through the new container. - count = items.size(); - LLUUID new_selection_id; - LLFolderViewItem* item_to_select = getNextUnselectedItem(); - - if(count == 1) - { - LLFolderViewItem* item_to_delete = items[0]; - LLFolderViewFolder* parent = item_to_delete->getParentFolder(); - if(parent) - { - if (item_to_delete->remove()) - { - // change selection on successful delete - setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); - } - } - arrangeAll(); - } - else if (count > 1) - { - std::vector<LLFolderViewModelItem*> listeners; - LLFolderViewModelItem* listener; - - setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); - - listeners.reserve(count); - for(S32 i = 0; i < count; ++i) - { - listener = items[i]->getViewModelItem(); - if(listener && (std::find(listeners.begin(), listeners.end(), listener) == listeners.end())) - { - listeners.push_back(listener); - } - } - listener = static_cast<LLFolderViewModelItem*>(listeners.at(0)); - if(listener) - { - listener->removeBatch(listeners); - } - } - arrangeAll(); - scrollToShowSelection(); - } + if(getVisible() && getEnabled()) + { + // just in case we're removing the renaming item. + mRenameItem = NULL; + + // create a temporary structure which we will use to remove + // items, since the removal will futz with internal data + // structures. + std::vector<LLFolderViewItem*> items; + S32 count = mSelectedItems.size(); + if(count <= 0) return; + LLFolderViewItem* item = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + item = *item_it; + if (item && item->isRemovable()) + { + items.push_back(item); + } + else + { + LL_DEBUGS() << "Cannot delete " << item->getName() << LL_ENDL; + return; + } + } + + // iterate through the new container. + count = items.size(); + LLUUID new_selection_id; + LLFolderViewItem* item_to_select = getNextUnselectedItem(); + + if(count == 1) + { + LLFolderViewItem* item_to_delete = items[0]; + LLFolderViewFolder* parent = item_to_delete->getParentFolder(); + if(parent) + { + if (item_to_delete->remove()) + { + // change selection on successful delete + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); + } + } + arrangeAll(); + } + else if (count > 1) + { + std::vector<LLFolderViewModelItem*> listeners; + LLFolderViewModelItem* listener; + + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); + + listeners.reserve(count); + for(S32 i = 0; i < count; ++i) + { + listener = items[i]->getViewModelItem(); + if(listener && (std::find(listeners.begin(), listeners.end(), listener) == listeners.end())) + { + listeners.push_back(listener); + } + } + listener = static_cast<LLFolderViewModelItem*>(listeners.at(0)); + if(listener) + { + listener->removeBatch(listeners); + } + } + arrangeAll(); + scrollToShowSelection(); + } } void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { - if ((mAutoOpenItems.check() == item) || - (mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) || - item->isOpen()) - { - return; - } - - // close auto-opened folders - LLFolderViewFolder* close_item = mAutoOpenItems.check(); - while (close_item && close_item != item->getParentFolder()) - { - mAutoOpenItems.pop(); - close_item->setOpenArrangeRecursively(FALSE); - close_item = mAutoOpenItems.check(); - } - - item->requestArrange(); - - mAutoOpenItems.push(item); - - item->setOpen(TRUE); + if ((mAutoOpenItems.check() == item) || + (mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) || + item->isOpen()) + { + return; + } + + // close auto-opened folders + LLFolderViewFolder* close_item = mAutoOpenItems.check(); + while (close_item && close_item != item->getParentFolder()) + { + mAutoOpenItems.pop(); + close_item->setOpenArrangeRecursively(FALSE); + close_item = mAutoOpenItems.check(); + } + + item->requestArrange(); + + mAutoOpenItems.push(item); + + item->setOpen(TRUE); if(!item->isSingleFolderMode()) { - LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); - LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); - scrollToShowItem(item, constraint_rect); + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); + LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); + scrollToShowItem(item, constraint_rect); } } void LLFolderView::closeAutoOpenedFolders() { - while (mAutoOpenItems.check()) - { - LLFolderViewFolder* close_item = mAutoOpenItems.pop(); - close_item->setOpen(FALSE); - } + while (mAutoOpenItems.check()) + { + LLFolderViewFolder* close_item = mAutoOpenItems.pop(); + close_item->setOpen(FALSE); + } - if (mAutoOpenCandidate) - { - mAutoOpenCandidate->setAutoOpenCountdown(0.f); - } - mAutoOpenCandidate = NULL; - mAutoOpenTimer.stop(); + if (mAutoOpenCandidate) + { + mAutoOpenCandidate->setAutoOpenCountdown(0.f); + } + mAutoOpenCandidate = NULL; + mAutoOpenTimer.stop(); } BOOL LLFolderView::autoOpenTest(LLFolderViewFolder* folder) { - if (folder && mAutoOpenCandidate == folder) - { - if (mAutoOpenTimer.getStarted()) - { - if (!mAutoOpenCandidate->isOpen()) - { - mAutoOpenCandidate->setAutoOpenCountdown(clamp_rescale(mAutoOpenTimer.getElapsedTimeF32(), 0.f, sAutoOpenTime, 0.f, 1.f)); - } - if (mAutoOpenTimer.getElapsedTimeF32() > sAutoOpenTime) - { - autoOpenItem(folder); - mAutoOpenTimer.stop(); - return TRUE; - } - } - return FALSE; - } - - // otherwise new candidate, restart timer - if (mAutoOpenCandidate) - { - mAutoOpenCandidate->setAutoOpenCountdown(0.f); - } - mAutoOpenCandidate = folder; - mAutoOpenTimer.start(); - return FALSE; + if (folder && mAutoOpenCandidate == folder) + { + if (mAutoOpenTimer.getStarted()) + { + if (!mAutoOpenCandidate->isOpen()) + { + mAutoOpenCandidate->setAutoOpenCountdown(clamp_rescale(mAutoOpenTimer.getElapsedTimeF32(), 0.f, sAutoOpenTime, 0.f, 1.f)); + } + if (mAutoOpenTimer.getElapsedTimeF32() > sAutoOpenTime) + { + autoOpenItem(folder); + mAutoOpenTimer.stop(); + return TRUE; + } + } + return FALSE; + } + + // otherwise new candidate, restart timer + if (mAutoOpenCandidate) + { + mAutoOpenCandidate->setAutoOpenCountdown(0.f); + } + mAutoOpenCandidate = folder; + mAutoOpenTimer.start(); + return FALSE; } BOOL LLFolderView::canCopy() const { - if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) - { - return FALSE; - } - - for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) - { - const LLFolderViewItem* item = *selected_it; - if (!item->getViewModelItem()->isItemCopyable()) - { - return FALSE; - } - } - return TRUE; + if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) + { + return FALSE; + } + + for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + const LLFolderViewItem* item = *selected_it; + if (!item->getViewModelItem()->isItemCopyable()) + { + return FALSE; + } + } + return TRUE; } // copy selected item void LLFolderView::copy() { - // *NOTE: total hack to clear the inventory clipboard - LLClipboard::instance().reset(); - S32 count = mSelectedItems.size(); - if(getVisible() && getEnabled() && (count > 0)) - { - LLFolderViewModelItem* listener = NULL; - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - { - listener = (*item_it)->getViewModelItem(); - if(listener) - { - listener->copyToClipboard(); - } - } - } - mSearchString.clear(); + // *NOTE: total hack to clear the inventory clipboard + LLClipboard::instance().reset(); + S32 count = mSelectedItems.size(); + if(getVisible() && getEnabled() && (count > 0)) + { + LLFolderViewModelItem* listener = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + listener = (*item_it)->getViewModelItem(); + if(listener) + { + listener->copyToClipboard(); + } + } + } + mSearchString.clear(); } BOOL LLFolderView::canCut() const { - if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) - { - return FALSE; - } - - for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) - { - const LLFolderViewItem* item = *selected_it; - const LLFolderViewModelItem* listener = item->getViewModelItem(); + if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) + { + return FALSE; + } - if (!listener || !listener->isItemRemovable()) - { - return FALSE; - } - } - return TRUE; + for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + const LLFolderViewItem* item = *selected_it; + const LLFolderViewModelItem* listener = item->getViewModelItem(); + + if (!listener || !listener->isItemRemovable()) + { + return FALSE; + } + } + return TRUE; } void LLFolderView::cut() { - // clear the inventory clipboard - LLClipboard::instance().reset(); - if(getVisible() && getEnabled() && (mSelectedItems.size() > 0)) - { - // Find out which item will be selected once the selection will be cut - LLFolderViewItem* item_to_select = getNextUnselectedItem(); - - // Get the selection: removeItem() modified mSelectedItems and makes iterating on it unwise - std::set<LLFolderViewItem*> inventory_selected = getSelectionList(); - - // Move each item to the clipboard and out of their folder - for (std::set<LLFolderViewItem*>::iterator item_it = inventory_selected.begin(); item_it != inventory_selected.end(); ++item_it) - { - LLFolderViewItem* item_to_cut = *item_it; - LLFolderViewModelItem* listener = item_to_cut->getViewModelItem(); - if (listener) - { - listener->cutToClipboard(); - } - } - - // Update the selection - setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); - } - mSearchString.clear(); + // clear the inventory clipboard + LLClipboard::instance().reset(); + if(getVisible() && getEnabled() && (mSelectedItems.size() > 0)) + { + // Find out which item will be selected once the selection will be cut + LLFolderViewItem* item_to_select = getNextUnselectedItem(); + + // Get the selection: removeItem() modified mSelectedItems and makes iterating on it unwise + std::set<LLFolderViewItem*> inventory_selected = getSelectionList(); + + // Move each item to the clipboard and out of their folder + for (std::set<LLFolderViewItem*>::iterator item_it = inventory_selected.begin(); item_it != inventory_selected.end(); ++item_it) + { + LLFolderViewItem* item_to_cut = *item_it; + LLFolderViewModelItem* listener = item_to_cut->getViewModelItem(); + if (listener) + { + listener->cutToClipboard(); + } + } + + // Update the selection + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus()); + } + mSearchString.clear(); } BOOL LLFolderView::canPaste() const { - if (mSelectedItems.empty()) - { - return FALSE; - } - - if(getVisible() && getEnabled()) - { - for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); - item_it != mSelectedItems.end(); ++item_it) - { - // *TODO: only check folders and parent folders of items - const LLFolderViewItem* item = (*item_it); - const LLFolderViewModelItem* listener = item->getViewModelItem(); - if(!listener || !listener->isClipboardPasteable()) - { - const LLFolderViewFolder* folderp = item->getParentFolder(); - listener = folderp->getViewModelItem(); - if (!listener || !listener->isClipboardPasteable()) - { - return FALSE; - } - } - } - return TRUE; - } - return FALSE; + if (mSelectedItems.empty()) + { + return FALSE; + } + + if(getVisible() && getEnabled()) + { + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); + item_it != mSelectedItems.end(); ++item_it) + { + // *TODO: only check folders and parent folders of items + const LLFolderViewItem* item = (*item_it); + const LLFolderViewModelItem* listener = item->getViewModelItem(); + if(!listener || !listener->isClipboardPasteable()) + { + const LLFolderViewFolder* folderp = item->getParentFolder(); + listener = folderp->getViewModelItem(); + if (!listener || !listener->isClipboardPasteable()) + { + return FALSE; + } + } + } + return TRUE; + } + return FALSE; } // paste selected item void LLFolderView::paste() { - if(getVisible() && getEnabled()) - { - // find set of unique folders to paste into - std::set<LLFolderViewFolder*> folder_set; - - selected_items_t::iterator selected_it; - for (selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) - { - LLFolderViewItem* item = *selected_it; - LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(item); - if (folder == NULL) - { - folder = item->getParentFolder(); - } - folder_set.insert(folder); - } - - std::set<LLFolderViewFolder*>::iterator set_iter; - for(set_iter = folder_set.begin(); set_iter != folder_set.end(); ++set_iter) - { - LLFolderViewModelItem* listener = (*set_iter)->getViewModelItem(); - if(listener && listener->isClipboardPasteable()) - { - listener->pasteFromClipboard(); - } - } - } - mSearchString.clear(); + if(getVisible() && getEnabled()) + { + // find set of unique folders to paste into + std::set<LLFolderViewFolder*> folder_set; + + selected_items_t::iterator selected_it; + for (selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + LLFolderViewItem* item = *selected_it; + LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(item); + if (folder == NULL) + { + folder = item->getParentFolder(); + } + folder_set.insert(folder); + } + + std::set<LLFolderViewFolder*>::iterator set_iter; + for(set_iter = folder_set.begin(); set_iter != folder_set.end(); ++set_iter) + { + LLFolderViewModelItem* listener = (*set_iter)->getViewModelItem(); + if(listener && listener->isClipboardPasteable()) + { + listener->pasteFromClipboard(); + } + } + } + mSearchString.clear(); } // public rename functionality - can only start the process @@ -1050,431 +1056,434 @@ void LLFolderView::startRenamingSelectedItem( void ) { LL_DEBUGS("Inventory") << "Starting inventory renamer" << LL_ENDL; - // make sure selection is visible - scrollToShowSelection(); + // make sure selection is visible + scrollToShowSelection(); - S32 count = mSelectedItems.size(); - LLFolderViewItem* item = NULL; - if(count > 0) - { - item = mSelectedItems.front(); - } - if(getVisible() && getEnabled() && (count == 1) && item && item->getViewModelItem() && - item->getViewModelItem()->isItemRenameable()) - { - mRenameItem = item; + S32 count = mSelectedItems.size(); + LLFolderViewItem* item = NULL; + if(count > 0) + { + item = mSelectedItems.front(); + } + if(getVisible() && getEnabled() && (count == 1) && item && item->getViewModelItem() && + item->getViewModelItem()->isItemRenameable()) + { + mRenameItem = item; - updateRenamerPosition(); + updateRenamerPosition(); - mRenamer->setText(item->getName()); - mRenamer->selectAll(); - mRenamer->setVisible( TRUE ); - // set focus will fail unless item is visible - mRenamer->setFocus( TRUE ); - mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); - LLUI::getInstance()->addPopup(mRenamer); - } + mRenamer->setText(item->getName()); + mRenamer->selectAll(); + mRenamer->setVisible( TRUE ); + // set focus will fail unless item is visible + mRenamer->setFocus( TRUE ); + if (!mRenamerTopLostSignalConnection.connected()) + { + mRenamerTopLostSignalConnection = mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); + } + LLUI::getInstance()->addPopup(mRenamer); + } } BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) { - BOOL handled = FALSE; - - // SL-51858: Key presses are not being passed to the Popup menu. - // A proper fix is non-trivial so instead just close the menu. - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu && menu->isOpen()) - { - LLMenuGL::sMenuContainer->hideMenus(); - } - - switch( key ) - { - case KEY_F2: - mSearchString.clear(); - startRenamingSelectedItem(); - handled = TRUE; - break; - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( mRenameItem && mRenamer->getVisible() ) - { - finishRenamingItem(); - mSearchString.clear(); - handled = TRUE; - } - } - break; - - case KEY_ESCAPE: - if( mRenameItem && mRenamer->getVisible() ) - { - closeRenamer(); - handled = TRUE; - } - mSearchString.clear(); - break; - - case KEY_PAGE_UP: - mSearchString.clear(); - if (mScrollContainer) - { - mScrollContainer->pageUp(30); - } - handled = TRUE; - break; - - case KEY_PAGE_DOWN: - mSearchString.clear(); - if (mScrollContainer) - { - mScrollContainer->pageDown(30); - } - handled = TRUE; - break; - - case KEY_HOME: - mSearchString.clear(); - if (mScrollContainer) - { - mScrollContainer->goToTop(); - } - handled = TRUE; - break; - - case KEY_END: - mSearchString.clear(); - if (mScrollContainer) - { - mScrollContainer->goToBottom(); - } - break; - - case KEY_DOWN: - if((mSelectedItems.size() > 0) && mScrollContainer) - { - LLFolderViewItem* last_selected = getCurSelectedItem(); - BOOL shift_select = mask & MASK_SHIFT; - // don't shift select down to children of folders (they are implicitly selected through parent) - LLFolderViewItem* next = last_selected->getNextOpenNode(!shift_select); - - if (!mKeyboardSelection || (!shift_select && (!next || next == last_selected))) - { - setSelection(last_selected, FALSE, TRUE); - mKeyboardSelection = TRUE; - } - - if (shift_select) - { - if (next) - { - if (next->isSelected()) - { - // shrink selection - changeSelection(last_selected, FALSE); - } - else if (last_selected->getParentFolder() == next->getParentFolder()) - { - // grow selection - changeSelection(next, TRUE); - } - } - } - else - { - if( next ) - { - if (next == last_selected) - { - //special case for LLAccordionCtrl - if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed - { - clearSelection(); - return TRUE; - } - return FALSE; - } - setSelection( next, FALSE, TRUE ); - } - else - { - //special case for LLAccordionCtrl - if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed - { - clearSelection(); - return TRUE; - } - return FALSE; - } - } - scrollToShowSelection(); - mSearchString.clear(); - handled = TRUE; - } - break; - - case KEY_UP: - if((mSelectedItems.size() > 0) && mScrollContainer) - { - LLFolderViewItem* last_selected = mSelectedItems.back(); - BOOL shift_select = mask & MASK_SHIFT; - // don't shift select down to children of folders (they are implicitly selected through parent) - LLFolderViewItem* prev = last_selected->getPreviousOpenNode(!shift_select); - - if (!mKeyboardSelection || (!shift_select && prev == this)) - { - setSelection(last_selected, FALSE, TRUE); - mKeyboardSelection = TRUE; - } - - if (shift_select) - { - if (prev) - { - if (prev->isSelected()) - { - // shrink selection - changeSelection(last_selected, FALSE); - } - else if (last_selected->getParentFolder() == prev->getParentFolder()) - { - // grow selection - changeSelection(prev, TRUE); - } - } - } - else - { - if( prev ) - { - if (prev == this) - { - // If case we are in accordion tab notify parent to go to the previous accordion - if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed - { - clearSelection(); - return TRUE; - } - - return FALSE; - } - setSelection( prev, FALSE, TRUE ); - } - } - scrollToShowSelection(); - mSearchString.clear(); - - handled = TRUE; - } - break; - - case KEY_RIGHT: - if(mSelectedItems.size()) - { - LLFolderViewItem* last_selected = getCurSelectedItem(); - last_selected->setOpen( TRUE ); - mSearchString.clear(); - handled = TRUE; - } - break; - - case KEY_LEFT: - if(mSelectedItems.size()) - { - LLFolderViewItem* last_selected = getCurSelectedItem(); + BOOL handled = FALSE; + + // SL-51858: Key presses are not being passed to the Popup menu. + // A proper fix is non-trivial so instead just close the menu. + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + + switch( key ) + { + case KEY_F2: + mSearchString.clear(); + startRenamingSelectedItem(); + handled = TRUE; + break; + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( mRenameItem && mRenamer->getVisible() ) + { + finishRenamingItem(); + mSearchString.clear(); + handled = TRUE; + } + } + break; + + case KEY_ESCAPE: + if( mRenameItem && mRenamer->getVisible() ) + { + closeRenamer(); + handled = TRUE; + } + mSearchString.clear(); + break; + + case KEY_PAGE_UP: + mSearchString.clear(); + if (mScrollContainer) + { + mScrollContainer->pageUp(30); + } + handled = TRUE; + break; + + case KEY_PAGE_DOWN: + mSearchString.clear(); + if (mScrollContainer) + { + mScrollContainer->pageDown(30); + } + handled = TRUE; + break; + + case KEY_HOME: + mSearchString.clear(); + if (mScrollContainer) + { + mScrollContainer->goToTop(); + } + handled = TRUE; + break; + + case KEY_END: + mSearchString.clear(); + if (mScrollContainer) + { + mScrollContainer->goToBottom(); + } + break; + + case KEY_DOWN: + if((mSelectedItems.size() > 0) && mScrollContainer) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); + BOOL shift_select = mask & MASK_SHIFT; + // don't shift select down to children of folders (they are implicitly selected through parent) + LLFolderViewItem* next = last_selected->getNextOpenNode(!shift_select); + + if (!mKeyboardSelection || (!shift_select && (!next || next == last_selected))) + { + setSelection(last_selected, FALSE, TRUE); + mKeyboardSelection = TRUE; + } + + if (shift_select) + { + if (next) + { + if (next->isSelected()) + { + // shrink selection + changeSelection(last_selected, FALSE); + } + else if (last_selected->getParentFolder() == next->getParentFolder()) + { + // grow selection + changeSelection(next, TRUE); + } + } + } + else + { + if( next ) + { + if (next == last_selected) + { + //special case for LLAccordionCtrl + if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + return FALSE; + } + setSelection( next, FALSE, TRUE ); + } + else + { + //special case for LLAccordionCtrl + if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + return FALSE; + } + } + scrollToShowSelection(); + mSearchString.clear(); + handled = TRUE; + } + break; + + case KEY_UP: + if((mSelectedItems.size() > 0) && mScrollContainer) + { + LLFolderViewItem* last_selected = mSelectedItems.back(); + BOOL shift_select = mask & MASK_SHIFT; + // don't shift select down to children of folders (they are implicitly selected through parent) + LLFolderViewItem* prev = last_selected->getPreviousOpenNode(!shift_select); + + if (!mKeyboardSelection || (!shift_select && prev == this)) + { + setSelection(last_selected, FALSE, TRUE); + mKeyboardSelection = TRUE; + } + + if (shift_select) + { + if (prev) + { + if (prev->isSelected()) + { + // shrink selection + changeSelection(last_selected, FALSE); + } + else if (last_selected->getParentFolder() == prev->getParentFolder()) + { + // grow selection + changeSelection(prev, TRUE); + } + } + } + else + { + if( prev ) + { + if (prev == this) + { + // If case we are in accordion tab notify parent to go to the previous accordion + if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + + return FALSE; + } + setSelection( prev, FALSE, TRUE ); + } + } + scrollToShowSelection(); + mSearchString.clear(); + + handled = TRUE; + } + break; + + case KEY_RIGHT: + if(mSelectedItems.size()) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); + last_selected->setOpen( TRUE ); + mSearchString.clear(); + handled = TRUE; + } + break; + + case KEY_LEFT: + if(mSelectedItems.size()) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); if(last_selected && last_selected->isSingleFolderMode()) { handled = FALSE; break; } - LLFolderViewItem* parent_folder = last_selected->getParentFolder(); - if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder()) - { - setSelection(parent_folder, FALSE, TRUE); - } - else - { - last_selected->setOpen( FALSE ); - } - mSearchString.clear(); - scrollToShowSelection(); - handled = TRUE; - } - break; - } - - return handled; + LLFolderViewItem* parent_folder = last_selected->getParentFolder(); + if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder()) + { + setSelection(parent_folder, FALSE, TRUE); + } + else + { + last_selected->setOpen( FALSE ); + } + mSearchString.clear(); + scrollToShowSelection(); + handled = TRUE; + } + break; + } + + return handled; } BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } - - if (uni_char > 0x7f) - { - LL_WARNS() << "LLFolderView::handleUnicodeCharHere - Don't handle non-ascii yet, aborting" << LL_ENDL; - return FALSE; - } - - BOOL handled = FALSE; - if (mParentPanel.get()->hasFocus()) - { - // SL-51858: Key presses are not being passed to the Popup menu. - // A proper fix is non-trivial so instead just close the menu. - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu && menu->isOpen()) - { - LLMenuGL::sMenuContainer->hideMenus(); - } - - //do text search - if (mSearchTimer.getElapsedTimeF32() > LLUI::getInstance()->mSettingGroups["config"]->getF32("TypeAheadTimeout")) - { - mSearchString.clear(); - } - mSearchTimer.reset(); - if (mSearchString.size() < 128) - { - mSearchString += uni_char; - } - search(getCurSelectedItem(), mSearchString, FALSE); - - handled = TRUE; - } - - return handled; + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } + + if (uni_char > 0x7f) + { + LL_WARNS() << "LLFolderView::handleUnicodeCharHere - Don't handle non-ascii yet, aborting" << LL_ENDL; + return FALSE; + } + + BOOL handled = FALSE; + if (mParentPanel.get()->hasFocus()) + { + // SL-51858: Key presses are not being passed to the Popup menu. + // A proper fix is non-trivial so instead just close the menu. + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + + //do text search + if (mSearchTimer.getElapsedTimeF32() > LLUI::getInstance()->mSettingGroups["config"]->getF32("TypeAheadTimeout")) + { + mSearchString.clear(); + } + mSearchTimer.reset(); + if (mSearchString.size() < 128) + { + mSearchString += uni_char; + } + search(getCurSelectedItem(), mSearchString, FALSE); + + handled = TRUE; + } + + return handled; } BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) { - mKeyboardSelection = FALSE; - mSearchString.clear(); + mKeyboardSelection = FALSE; + mSearchString.clear(); - mParentPanel.get()->setFocus(TRUE); + mParentPanel.get()->setFocus(TRUE); - LLEditMenuHandler::gEditMenuHandler = this; + LLEditMenuHandler::gEditMenuHandler = this; - return LLView::handleMouseDown( x, y, mask ); + return LLView::handleMouseDown( x, y, mask ); } BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward) { - // get first selected item - LLFolderViewItem* search_item = first_item; - - // make sure search string is upper case - std::string upper_case_string = search_string; - LLStringUtil::toUpper(upper_case_string); - - // if nothing selected, select first item in folder - if (!search_item) - { - // start from first item - search_item = getNextFromChild(NULL); - } - - // search over all open nodes for first substring match (with wrapping) - BOOL found = FALSE; - LLFolderViewItem* original_search_item = search_item; - do - { - // wrap at end - if (!search_item) - { - if (backward) - { - search_item = getPreviousFromChild(NULL); - } - else - { - search_item = getNextFromChild(NULL); - } - if (!search_item || search_item == original_search_item) - { - break; - } - } - - std::string current_item_label(search_item->getViewModelItem()->getSearchableName()); - LLStringUtil::toUpper(current_item_label); - S32 search_string_length = llmin(upper_case_string.size(), current_item_label.size()); - if (!current_item_label.compare(0, search_string_length, upper_case_string)) - { - found = TRUE; - break; - } - if (backward) - { - search_item = search_item->getPreviousOpenNode(); - } - else - { - search_item = search_item->getNextOpenNode(); - } - - } while(search_item != original_search_item); - - - if (found) - { - setSelection(search_item, FALSE, TRUE); - scrollToShowSelection(); - } - - return found; + // get first selected item + LLFolderViewItem* search_item = first_item; + + // make sure search string is upper case + std::string upper_case_string = search_string; + LLStringUtil::toUpper(upper_case_string); + + // if nothing selected, select first item in folder + if (!search_item) + { + // start from first item + search_item = getNextFromChild(NULL); + } + + // search over all open nodes for first substring match (with wrapping) + BOOL found = FALSE; + LLFolderViewItem* original_search_item = search_item; + do + { + // wrap at end + if (!search_item) + { + if (backward) + { + search_item = getPreviousFromChild(NULL); + } + else + { + search_item = getNextFromChild(NULL); + } + if (!search_item || search_item == original_search_item) + { + break; + } + } + + std::string current_item_label(search_item->getViewModelItem()->getSearchableName()); + LLStringUtil::toUpper(current_item_label); + S32 search_string_length = llmin(upper_case_string.size(), current_item_label.size()); + if (!current_item_label.compare(0, search_string_length, upper_case_string)) + { + found = TRUE; + break; + } + if (backward) + { + search_item = search_item->getPreviousOpenNode(); + } + else + { + search_item = search_item->getNextOpenNode(); + } + + } while(search_item != original_search_item); + + + if (found) + { + setSelection(search_item, FALSE, TRUE); + scrollToShowSelection(); + } + + return found; } BOOL LLFolderView::handleDoubleClick( S32 x, S32 y, MASK mask ) { - // skip LLFolderViewFolder::handleDoubleClick() - return LLView::handleDoubleClick( x, y, mask ); + // skip LLFolderViewFolder::handleDoubleClick() + return LLView::handleDoubleClick( x, y, mask ); } BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { - // all user operations move keyboard focus to inventory - // this way, we know when to stop auto-updating a search - mParentPanel.get()->setFocus(TRUE); - - BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; - S32 count = mSelectedItems.size(); - - LLMenuGL* menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); - if (!menu) - { - if (mCallbackRegistrar) - { - mCallbackRegistrar->pushScope(); - } - if (mEnableRegistrar) - { - mEnableRegistrar->pushScope(); - } - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(mMenuFileName, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); - if (!menu) - { - menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu"); - } - menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); - mPopupMenuHandle = menu->getHandle(); - if (mEnableRegistrar) - { - mEnableRegistrar->popScope(); - } - if (mCallbackRegistrar) - { - mCallbackRegistrar->popScope(); - } - } + // all user operations move keyboard focus to inventory + // this way, we know when to stop auto-updating a search + mParentPanel.get()->setFocus(TRUE); + + BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; + S32 count = mSelectedItems.size(); + + LLMenuGL* menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); + if (!menu) + { + if (mCallbackRegistrar) + { + mCallbackRegistrar->pushScope(); + } + if (mEnableRegistrar) + { + mEnableRegistrar->pushScope(); + } + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(mMenuFileName, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + if (!menu) + { + menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu"); + } + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); + mPopupMenuHandle = menu->getHandle(); + if (mEnableRegistrar) + { + mEnableRegistrar->popScope(); + } + if (mCallbackRegistrar) + { + mCallbackRegistrar->popScope(); + } + } BOOL item_clicked = FALSE; for (selected_items_t::iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) @@ -1485,207 +1494,211 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { clearSelection(); } - bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected(); - if (menu && (mSingleFolderMode || (handled - && ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible - !hide_folder_menu) - { - if (mCallbackRegistrar) - { - mCallbackRegistrar->pushScope(); - } - if (mEnableRegistrar) - { - mEnableRegistrar->pushScope(); - } - - updateMenuOptions(menu); - - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); - if (mEnableRegistrar) - { - mEnableRegistrar->popScope(); - } - if (mCallbackRegistrar) - { - mCallbackRegistrar->popScope(); - } - } - else - { - if (menu && menu->getVisible()) - { - menu->setVisible(FALSE); - } - setSelection(NULL, FALSE, TRUE); - } - return handled; + bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected(); + if (menu && (mSingleFolderMode || (handled + && ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible + !hide_folder_menu) + { + if (mCallbackRegistrar) + { + mCallbackRegistrar->pushScope(); + } + if (mEnableRegistrar) + { + mEnableRegistrar->pushScope(); + } + + updateMenuOptions(menu); + + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + if (mEnableRegistrar) + { + mEnableRegistrar->popScope(); + } + if (mCallbackRegistrar) + { + mCallbackRegistrar->popScope(); + } + } + else + { + if (menu && menu->getVisible()) + { + menu->setVisible(FALSE); + } + setSelection(NULL, FALSE, TRUE); + } + return handled; } // Add "--no options--" if the menu is completely blank. BOOL LLFolderView::addNoOptions(LLMenuGL* menu) const { - const std::string nooptions_str = "--no options--"; - LLView *nooptions_item = NULL; - - const LLView::child_list_t *list = menu->getChildList(); - for (LLView::child_list_t::const_iterator itor = list->begin(); - itor != list->end(); - ++itor) - { - LLView *menu_item = (*itor); - if (menu_item->getVisible()) - { - return FALSE; - } - std::string name = menu_item->getName(); - if (menu_item->getName() == nooptions_str) - { - nooptions_item = menu_item; - } - } - if (nooptions_item) - { - nooptions_item->setVisible(TRUE); - nooptions_item->setEnabled(FALSE); - return TRUE; - } - return FALSE; + const std::string nooptions_str = "--no options--"; + LLView *nooptions_item = NULL; + + const LLView::child_list_t *list = menu->getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + if (menu_item->getVisible()) + { + return FALSE; + } + std::string name = menu_item->getName(); + if (menu_item->getName() == nooptions_str) + { + nooptions_item = menu_item; + } + } + if (nooptions_item) + { + nooptions_item->setVisible(TRUE); + nooptions_item->setEnabled(FALSE); + return TRUE; + } + return FALSE; } BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask ) { - return LLView::handleHover( x, y, mask ); + return LLView::handleHover( x, y, mask ); } LLFolderViewItem* LLFolderView::getHoveredItem() const { - return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get()); + return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get()); } void LLFolderView::setHoveredItem(LLFolderViewItem* itemp) { - if (mHoveredItem.get() != itemp) - { - if (itemp) - mHoveredItem = itemp->getHandle(); - else - mHoveredItem.markDead(); - } + if (mHoveredItem.get() != itemp) + { + if (itemp) + mHoveredItem = itemp->getHandle(); + else + mHoveredItem.markDead(); + } } BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - mDragAndDropThisFrame = TRUE; - // have children handle it first - BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, - accept, tooltip_msg); - - // when drop is not handled by child, it should be handled - // by the folder which is the hierarchy root. - if (!handled) - { - handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + mDragAndDropThisFrame = TRUE; + // have children handle it first + BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, + accept, tooltip_msg); + + // when drop is not handled by child, it should be handled + // by the folder which is the hierarchy root. + if (!handled) + { + handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } - return handled; + return handled; } void LLFolderView::deleteAllChildren() { - closeRenamer(); - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); - mPopupMenuHandle.markDead(); - mScrollContainer = NULL; - mRenameItem = NULL; - mRenamer = NULL; - mStatusTextBox = NULL; - - clearSelection(); - LLView::deleteAllChildren(); + mRenamerTopLostSignalConnection.disconnect(); + if (mRenamer) + { + LLUI::getInstance()->removePopup(mRenamer); + } + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + mPopupMenuHandle.markDead(); + mScrollContainer = NULL; + mRenameItem = NULL; + mRenamer = NULL; + mStatusTextBox = NULL; + + clearSelection(); + LLView::deleteAllChildren(); } void LLFolderView::scrollToShowSelection() { - if ( mSelectedItems.size() ) - { - mNeedsScroll = TRUE; - } + if ( mSelectedItems.size() ) + { + mNeedsScroll = TRUE; + } } // If the parent is scroll container, scroll it to make the selection // is maximally visible. void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) { - if (!mScrollContainer) return; - - // don't scroll to items when mouse is being used to scroll/drag and drop - if (gFocusMgr.childHasMouseCapture(mScrollContainer)) - { - mNeedsScroll = FALSE; - return; - } - - // if item exists and is in visible portion of parent folder... - if(item) - { - LLRect local_rect = item->getLocalRect(); - S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); - // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder - S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight(); - - // get portion of item that we want to see... - LLRect item_local_rect = LLRect(item->getIndentation(), - local_rect.getHeight(), + if (!mScrollContainer) return; + + // don't scroll to items when mouse is being used to scroll/drag and drop + if (gFocusMgr.childHasMouseCapture(mScrollContainer)) + { + mNeedsScroll = FALSE; + return; + } + + // if item exists and is in visible portion of parent folder... + if(item) + { + LLRect local_rect = item->getLocalRect(); + S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); + S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); + // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder + S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight(); + + // get portion of item that we want to see... + LLRect item_local_rect = LLRect(item->getIndentation(), + local_rect.getHeight(), //+40 is supposed to include few first characters - llmin(item->getLabelXPos() - item->getIndentation() + 40, local_rect.getWidth()), - llmax(0, local_rect.getHeight() - max_height_to_show)); + llmin(item->getLabelXPos() - item->getIndentation() + 40, local_rect.getWidth()), + llmax(0, local_rect.getHeight() - max_height_to_show)); - LLRect item_doc_rect; + LLRect item_doc_rect; - item->localRectToOtherView(item_local_rect, &item_doc_rect, this); + item->localRectToOtherView(item_local_rect, &item_doc_rect, this); - mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect ); + mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect ); - } + } } LLRect LLFolderView::getVisibleRect() { - S32 visible_height = (mScrollContainer ? mScrollContainer->getRect().getHeight() : 0); - S32 visible_width = (mScrollContainer ? mScrollContainer->getRect().getWidth() : 0); - LLRect visible_rect; - visible_rect.setLeftTopAndSize(-getRect().mLeft, visible_height - getRect().mBottom, visible_width, visible_height); - return visible_rect; + S32 visible_height = (mScrollContainer ? mScrollContainer->getRect().getHeight() : 0); + S32 visible_width = (mScrollContainer ? mScrollContainer->getRect().getWidth() : 0); + LLRect visible_rect; + visible_rect.setLeftTopAndSize(-getRect().mLeft, visible_height - getRect().mBottom, visible_width, visible_height); + return visible_rect; } BOOL LLFolderView::getShowSelectionContext() { - if (mShowSelectionContext) - { - return TRUE; - } - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu && menu->getVisible()) - { - return TRUE; - } - return FALSE; + if (mShowSelectionContext) + { + return TRUE; + } + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + return TRUE; + } + return FALSE; } void LLFolderView::setShowSingleSelection(bool show) { - if (show != mShowSingleSelection) - { - mMultiSelectionFadeTimer.reset(); - mShowSingleSelection = show; - } + if (show != mShowSingleSelection) + { + mMultiSelectionFadeTimer.reset(); + mShowSingleSelection = show; + } } static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory"); @@ -1693,71 +1706,71 @@ static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory"); // Main idle routine void LLFolderView::update() { - // If this is associated with the user's inventory, don't do anything - // until that inventory is loaded up. - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY); - + // If this is associated with the user's inventory, don't do anything + // until that inventory is loaded up. + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY); + // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated if (getFolderViewModel() == NULL) { return; } - LLFolderViewFilter& filter_object = getFolderViewModel()->getFilter(); + LLFolderViewFilter& filter_object = getFolderViewModel()->getFilter(); - if (filter_object.isModified() && filter_object.isNotDefault() && mParentPanel.get()->getVisible()) - { - mNeedsAutoSelect = TRUE; - } - - // Filter to determine visibility before arranging - filter(filter_object); - - // Clear the modified setting on the filter only if the filter finished after running the filter process - // Note: if the filter count has timed out, that means the filter halted before completing the entire set of items + if (filter_object.isModified() && filter_object.isNotDefault() && mParentPanel.get()->getVisible()) + { + mNeedsAutoSelect = TRUE; + } + + // Filter to determine visibility before arranging + filter(filter_object); + + // Clear the modified setting on the filter only if the filter finished after running the filter process + // Note: if the filter count has timed out, that means the filter halted before completing the entire set of items bool filter_modified = filter_object.isModified(); if (filter_modified && (!filter_object.isTimedOut())) - { - filter_object.clearModified(); - } - - // automatically show matching items, and select first one if we had a selection - if (mNeedsAutoSelect) - { - // select new item only if a filtered item not currently selected and there was a selection - LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); - if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible()) - { - // these are named variables to get around gcc not binding non-const references to rvalues - // and functor application is inherently non-const to allow for stateful functors - LLSelectFirstFilteredItem functor; - applyFunctorRecursively(functor); - } - - // Open filtered folders for folder views with mAutoSelectOverride=TRUE. - // Used by LLPlacesFolderView. - if (filter_object.showAllResults()) - { - // these are named variables to get around gcc not binding non-const references to rvalues - // and functor application is inherently non-const to allow for stateful functors - LLOpenFilteredFolders functor; - applyFunctorRecursively(functor); - } - - scrollToShowSelection(); - } - - BOOL filter_finished = mViewModel->contentsReady() - && (getViewModelItem()->passedFilter() - || ( getViewModelItem()->getLastFilterGeneration() >= filter_object.getFirstSuccessGeneration() - && !filter_modified)); - if (filter_finished - || gFocusMgr.childHasKeyboardFocus(mParentPanel.get()) - || gFocusMgr.childHasMouseCapture(mParentPanel.get())) - { - // finishing the filter process, giving focus to the folder view, or dragging the scrollbar all stop the auto select process - mNeedsAutoSelect = FALSE; - } + { + filter_object.clearModified(); + } + + // automatically show matching items, and select first one if we had a selection + if (mNeedsAutoSelect) + { + // select new item only if a filtered item not currently selected and there was a selection + LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); + if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible()) + { + // these are named variables to get around gcc not binding non-const references to rvalues + // and functor application is inherently non-const to allow for stateful functors + LLSelectFirstFilteredItem functor; + applyFunctorRecursively(functor); + } + + // Open filtered folders for folder views with mAutoSelectOverride=TRUE. + // Used by LLPlacesFolderView. + if (filter_object.showAllResults()) + { + // these are named variables to get around gcc not binding non-const references to rvalues + // and functor application is inherently non-const to allow for stateful functors + LLOpenFilteredFolders functor; + applyFunctorRecursively(functor); + } + + scrollToShowSelection(); + } + + BOOL filter_finished = mViewModel->contentsReady() + && (getViewModelItem()->passedFilter() + || ( getViewModelItem()->getLastFilterGeneration() >= filter_object.getFirstSuccessGeneration() + && !filter_modified)); + if (filter_finished + || gFocusMgr.childHasKeyboardFocus(mParentPanel.get()) + || gFocusMgr.childHasMouseCapture(mParentPanel.get())) + { + // finishing the filter process, giving focus to the folder view, or dragging the scrollbar all stop the auto select process + mNeedsAutoSelect = FALSE; + } BOOL is_visible = isInVisibleChain() || mForceArrange; @@ -1776,71 +1789,71 @@ void LLFolderView::update() } } - // during filtering process, try to pin selected item's location on screen - // this will happen when searching your inventory and when new items arrive - if (!filter_finished) - { - // calculate rectangle to pin item to at start of animated rearrange - if (!mPinningSelectedItem && !mSelectedItems.empty()) - { - // lets pin it! - mPinningSelectedItem = TRUE; + // during filtering process, try to pin selected item's location on screen + // this will happen when searching your inventory and when new items arrive + if (!filter_finished) + { + // calculate rectangle to pin item to at start of animated rearrange + if (!mPinningSelectedItem && !mSelectedItems.empty()) + { + // lets pin it! + mPinningSelectedItem = TRUE; - //Computes visible area - const LLRect visible_content_rect = (mScrollContainer ? mScrollContainer->getVisibleContentRect() : LLRect()); - LLFolderViewItem* selected_item = mSelectedItems.back(); + //Computes visible area + const LLRect visible_content_rect = (mScrollContainer ? mScrollContainer->getVisibleContentRect() : LLRect()); + LLFolderViewItem* selected_item = mSelectedItems.back(); //Computes location of selected content, content outside visible area will be scrolled to using below code - LLRect item_rect; - selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); - + LLRect item_rect; + selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); + //Computes intersected region of the selected content and visible area LLRect overlap_rect(item_rect); overlap_rect.intersectWith(visible_content_rect); //Don't scroll when the selected content exists within the visible area - if (overlap_rect.getHeight() >= selected_item->getItemHeight()) - { - // then attempt to keep it in same place on screen - mScrollConstraintRect = item_rect; - mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); - } + if (overlap_rect.getHeight() >= selected_item->getItemHeight()) + { + // then attempt to keep it in same place on screen + mScrollConstraintRect = item_rect; + mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); + } //Scroll because the selected content is outside the visible area - else - { - // otherwise we just want it onscreen somewhere - LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); - mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); - } - } - } - else - { - // stop pinning selected item after folders stop rearranging - if (!needsArrange()) - { - mPinningSelectedItem = FALSE; - } - } - - LLRect constraint_rect; - if (mPinningSelectedItem) - { - // use last known constraint rect for pinned item - constraint_rect = mScrollConstraintRect; - } - else - { - // during normal use (page up/page down, etc), just try to fit item on screen - LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); - constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); - } - - if (mSelectedItems.size() && mNeedsScroll) - { + else + { + // otherwise we just want it onscreen somewhere + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); + mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + } + } + else + { + // stop pinning selected item after folders stop rearranging + if (!needsArrange()) + { + mPinningSelectedItem = FALSE; + } + } + + LLRect constraint_rect; + if (mPinningSelectedItem) + { + // use last known constraint rect for pinned item + constraint_rect = mScrollConstraintRect; + } + else + { + // during normal use (page up/page down, etc), just try to fit item on screen + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); + constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + + if (mSelectedItems.size() && mNeedsScroll) + { LLFolderViewItem* scroll_to_item = mSelectedItems.back(); - scrollToShowItem(scroll_to_item, constraint_rect); - // continue scrolling until animated layout change is done + scrollToShowItem(scroll_to_item, constraint_rect); + // continue scrolling until animated layout change is done bool selected_filter_finished = getRoot()->getViewModelItem()->getLastFilterGeneration() >= filter_object.getFirstSuccessGeneration(); if (selected_filter_finished && scroll_to_item && scroll_to_item->getViewModelItem()) { @@ -1858,7 +1871,7 @@ void LLFolderView::update() mNeedsScroll = FALSE; } } - } + } if (mSelectedItems.size()) { @@ -1886,182 +1899,182 @@ void LLFolderView::update() void LLFolderView::dumpSelectionInformation() { - LL_INFOS() << "LLFolderView::dumpSelectionInformation()" << LL_NEWLINE - << "****************************************" << LL_ENDL; - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - { - LL_INFOS() << " " << (*item_it)->getName() << LL_ENDL; - } - LL_INFOS() << "****************************************" << LL_ENDL; + LL_INFOS() << "LLFolderView::dumpSelectionInformation()" << LL_NEWLINE + << "****************************************" << LL_ENDL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + LL_INFOS() << " " << (*item_it)->getName() << LL_ENDL; + } + LL_INFOS() << "****************************************" << LL_ENDL; } void LLFolderView::updateRenamerPosition() { - if(mRenameItem) - { - // See also LLFolderViewItem::draw() - S32 x = mRenameItem->getLabelXPos(); - S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; - mRenameItem->localPointToScreen( x, y, &x, &y ); - screenPointToLocal( x, y, &x, &y ); - mRenamer->setOrigin( x, y ); - - LLRect scroller_rect(0, 0, (S32)LLUI::getInstance()->getWindowSize().mV[VX], 0); - if (mScrollContainer) - { - scroller_rect = mScrollContainer->getContentWindowRect(); - } + if(mRenameItem) + { + // See also LLFolderViewItem::draw() + S32 x = mRenameItem->getLabelXPos(); + S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenameItem->localPointToScreen( x, y, &x, &y ); + screenPointToLocal( x, y, &x, &y ); + mRenamer->setOrigin( x, y ); + + LLRect scroller_rect(0, 0, (S32)LLUI::getInstance()->getWindowSize().mV[VX], 0); + if (mScrollContainer) + { + scroller_rect = mScrollContainer->getContentWindowRect(); + } - S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); - S32 height = mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; - mRenamer->reshape( width, height, TRUE ); - } + S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); + S32 height = mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenamer->reshape( width, height, TRUE ); + } } // Update visibility and availability (i.e. enabled/disabled) of context menu items. void LLFolderView::updateMenuOptions(LLMenuGL* menu) { - const LLView::child_list_t *list = menu->getChildList(); - - LLView::child_list_t::const_iterator menu_itor; - for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) - { - (*menu_itor)->setVisible(FALSE); - (*menu_itor)->pushVisible(TRUE); - (*menu_itor)->setEnabled(TRUE); - } - - // Successively filter out invalid options - U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0); - U32 flags = multi_select_flag | FIRST_SELECTED_ITEM; - for (selected_items_t::iterator item_itor = mSelectedItems.begin(); - item_itor != mSelectedItems.end(); - ++item_itor) - { - LLFolderViewItem* selected_item = (*item_itor); - selected_item->buildContextMenu(*menu, flags); - flags = multi_select_flag; - } + const LLView::child_list_t *list = menu->getChildList(); + + LLView::child_list_t::const_iterator menu_itor; + for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) + { + (*menu_itor)->setVisible(FALSE); + (*menu_itor)->pushVisible(TRUE); + (*menu_itor)->setEnabled(TRUE); + } + + // Successively filter out invalid options + U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0); + U32 flags = multi_select_flag | FIRST_SELECTED_ITEM; + for (selected_items_t::iterator item_itor = mSelectedItems.begin(); + item_itor != mSelectedItems.end(); + ++item_itor) + { + LLFolderViewItem* selected_item = (*item_itor); + selected_item->buildContextMenu(*menu, flags); + flags = multi_select_flag; + } if(mSingleFolderMode && (mSelectedItems.size() == 0)) { buildContextMenu(*menu, flags); } - // This adds a check for restrictions based on the entire - // selection set - for example, any one wearable may not push you - // over the limit, but all wearables together still might. + // This adds a check for restrictions based on the entire + // selection set - for example, any one wearable may not push you + // over the limit, but all wearables together still might. if (getFolderViewGroupedItemModel()) { getFolderViewGroupedItemModel()->groupFilterContextMenu(mSelectedItems,*menu); } - addNoOptions(menu); + addNoOptions(menu); } // Refresh the context menu (that is already shown). void LLFolderView::updateMenu() { - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu && menu->getVisible()) - { - updateMenuOptions(menu); - menu->needsArrange(); // update menu height if needed - } + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + updateMenuOptions(menu); + menu->needsArrange(); // update menu height if needed + } } bool LLFolderView::isFolderSelected() { - selected_items_t::iterator item_iter; - for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) - { - LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*item_iter); - if (folder != NULL) - { - return true; - } - } - return false; + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + LLFolderViewFolder* folder = dynamic_cast<LLFolderViewFolder*>(*item_iter); + if (folder != NULL) + { + return true; + } + } + return false; } bool LLFolderView::selectFirstItem() { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();++iter) - { - LLFolderViewFolder* folder = (*iter ); - if (folder->getVisible()) - { - LLFolderViewItem* itemp = folder->getNextFromChild(0,true); - if(itemp) - setSelection(itemp,FALSE,TRUE); - return true; - } - - } - for(items_t::iterator iit = mItems.begin(); - iit != mItems.end(); ++iit) - { - LLFolderViewItem* itemp = (*iit); - if (itemp->getVisible()) - { - setSelection(itemp,FALSE,TRUE); - return true; - } - } - return false; + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();++iter) + { + LLFolderViewFolder* folder = (*iter ); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getNextFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + + } + for(items_t::iterator iit = mItems.begin(); + iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; } bool LLFolderView::selectLastItem() { - for(items_t::reverse_iterator iit = mItems.rbegin(); - iit != mItems.rend(); ++iit) - { - LLFolderViewItem* itemp = (*iit); - if (itemp->getVisible()) - { - setSelection(itemp,FALSE,TRUE); - return true; - } - } - for (folders_t::reverse_iterator iter = mFolders.rbegin(); - iter != mFolders.rend();++iter) - { - LLFolderViewFolder* folder = (*iter); - if (folder->getVisible()) - { - LLFolderViewItem* itemp = folder->getPreviousFromChild(0,true); - if(itemp) - setSelection(itemp,FALSE,TRUE); - return true; - } - } - return false; -} - - -S32 LLFolderView::notify(const LLSD& info) -{ - if(info.has("action")) - { - std::string str_action = info["action"]; - if(str_action == "select_first") - { - setFocus(true); - selectFirstItem(); - scrollToShowSelection(); - return 1; - - } - else if(str_action == "select_last") - { - setFocus(true); - selectLastItem(); - scrollToShowSelection(); - return 1; - } - } - return 0; + for(items_t::reverse_iterator iit = mItems.rbegin(); + iit != mItems.rend(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + for (folders_t::reverse_iterator iter = mFolders.rbegin(); + iter != mFolders.rend();++iter) + { + LLFolderViewFolder* folder = (*iter); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getPreviousFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; +} + + +S32 LLFolderView::notify(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + scrollToShowSelection(); + return 1; + + } + else if(str_action == "select_last") + { + setFocus(true); + selectLastItem(); + scrollToShowSelection(); + return 1; + } + } + return 0; } @@ -2071,46 +2084,46 @@ S32 LLFolderView::notify(const LLSD& info) void LLFolderView::onRenamerLost() { - if (mRenamer && mRenamer->getVisible()) - { - mRenamer->setVisible(FALSE); + if (mRenamer && mRenamer->getVisible()) + { + mRenamer->setVisible(FALSE); - // will commit current name (which could be same as original name) - mRenamer->setFocus(FALSE); - } + // will commit current name (which could be same as original name) + mRenamer->setFocus(FALSE); + } - if( mRenameItem ) - { - setSelection( mRenameItem, TRUE ); - mRenameItem = NULL; - } + if( mRenameItem ) + { + setSelection( mRenameItem, TRUE ); + mRenameItem = NULL; + } } LLFolderViewItem* LLFolderView::getNextUnselectedItem() { - LLFolderViewItem* last_item = *mSelectedItems.rbegin(); - LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); - while(new_selection && new_selection->isSelected()) - { - new_selection = new_selection->getNextOpenNode(FALSE); - } - if (!new_selection) - { - new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && (new_selection->isInSelection())) - { - new_selection = new_selection->getPreviousOpenNode(FALSE); - } - } - return new_selection; + LLFolderViewItem* last_item = *mSelectedItems.rbegin(); + LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); + while(new_selection && new_selection->isSelected()) + { + new_selection = new_selection->getNextOpenNode(FALSE); + } + if (!new_selection) + { + new_selection = last_item->getPreviousOpenNode(FALSE); + while (new_selection && (new_selection->isInSelection())) + { + new_selection = new_selection->getPreviousOpenNode(FALSE); + } + } + return new_selection; } S32 LLFolderView::getItemHeight() const { - if(!hasVisibleChildren()) + if(!hasVisibleChildren()) { - //We need to display status textbox, let's reserve some place for it - return llmax(0, mStatusTextBox->getTextPixelHeight()); + //We need to display status textbox, let's reserve some place for it + return llmax(0, mStatusTextBox->getTextPixelHeight()); } - return 0; + return 0; } diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 5f8a173889..ca78bd3072 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -1,25 +1,25 @@ -/** +/** * @file llfolderview.h * @brief Definition of the folder view collection of classes. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #ifndef LL_LLFOLDERVIEW_H #define LL_LLFOLDERVIEW_H -#include "llfolderviewitem.h" // because LLFolderView is-a LLFolderViewFolder +#include "llfolderviewitem.h" // because LLFolderView is-a LLFolderViewFolder #include "lluictrl.h" #include "v4color.h" @@ -66,290 +66,292 @@ class LLTextBox; class LLFolderViewScrollContainer : public LLScrollContainer { public: - /*virtual*/ ~LLFolderViewScrollContainer() {}; - /*virtual*/ const LLRect getScrolledViewRect() const; + /*virtual*/ ~LLFolderViewScrollContainer() {}; + /*virtual*/ const LLRect getScrolledViewRect() const; protected: - LLFolderViewScrollContainer(const LLScrollContainer::Params& p); - friend class LLUICtrlFactory; + LLFolderViewScrollContainer(const LLScrollContainer::Params& p); + friend class LLUICtrlFactory; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFolderView // -// The LLFolderView represents the root level folder view object. +// The LLFolderView represents the root level folder view object. // It manages the screen region of the folder view. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler { public: - struct Params : public LLInitParam::Block<Params, LLFolderViewFolder::Params> - { - Mandatory<LLPanel*> parent_panel; - Optional<std::string> title; - Optional<bool> use_label_suffix, - allow_multiselect, - allow_drag, - show_empty_message, - use_ellipses, - show_item_link_overlays, - suppress_folder_menu; - Mandatory<LLFolderViewModelInterface*> view_model; - Optional<LLFolderViewGroupedItemModel*> grouped_item_model; + struct Params : public LLInitParam::Block<Params, LLFolderViewFolder::Params> + { + Mandatory<LLPanel*> parent_panel; + Optional<std::string> title; + Optional<bool> use_label_suffix, + allow_multiselect, + allow_drag, + show_empty_message, + use_ellipses, + show_item_link_overlays, + suppress_folder_menu; + Mandatory<LLFolderViewModelInterface*> view_model; + Optional<LLFolderViewGroupedItemModel*> grouped_item_model; Mandatory<std::string> options_menu; - Params(); - }; + Params(); + }; - friend class LLFolderViewScrollContainer; + friend class LLFolderViewScrollContainer; typedef folder_view_item_deque selected_items_t; - LLFolderView(const Params&); - virtual ~LLFolderView( void ); + LLFolderView(const Params&); + virtual ~LLFolderView( void ); - virtual BOOL canFocusChildren() const; + virtual BOOL canFocusChildren() const; - virtual const LLFolderView* getRoot() const { return this; } - virtual LLFolderView* getRoot() { return this; } + virtual const LLFolderView* getRoot() const { return this; } + virtual LLFolderView* getRoot() { return this; } - LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; } - const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; } + LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; } + const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; } LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() { return mGroupedItemModel; } const LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() const { return mGroupedItemModel; } - - typedef boost::signals2::signal<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)> signal_t; - void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } - void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } - - bool getAllowMultiSelect() { return mAllowMultiSelect; } - bool getAllowDrag() { return mAllowDrag; } + + typedef boost::signals2::signal<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)> signal_t; + void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } + void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } + + bool getAllowMultiSelect() { return mAllowMultiSelect; } + bool getAllowDrag() { return mAllowDrag; } void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; } bool isSingleFolderMode() { return mSingleFolderMode; } - // Close all folders in the view - void closeAllFolders(); - void openTopLevelFolders(); + // Close all folders in the view + void closeAllFolders(); + void openTopLevelFolders(); - virtual void addFolder( LLFolderViewFolder* folder); + virtual void addFolder( LLFolderViewFolder* folder); - // Find width and height of this object and its children. Also - // makes sure that this view and its children are the right size. - virtual S32 arrange( S32* width, S32* height ); - virtual S32 getItemHeight() const; + // Find width and height of this object and its children. Also + // makes sure that this view and its children are the right size. + virtual S32 arrange( S32* width, S32* height ); + virtual S32 getItemHeight() const; - void arrangeAll() { mArrangeGeneration++; } - S32 getArrangeGeneration() { return mArrangeGeneration; } + void arrangeAll() { mArrangeGeneration++; } + S32 getArrangeGeneration() { return mArrangeGeneration; } - // applies filters to control visibility of items - virtual void filter( LLFolderViewFilter& filter); + // applies filters to control visibility of items + virtual void filter( LLFolderViewFilter& filter); - void clearHoveredItem() { setHoveredItem(nullptr); } - LLFolderViewItem* getHoveredItem() const; - void setHoveredItem(LLFolderViewItem* itemp); + void clearHoveredItem() { setHoveredItem(nullptr); } + LLFolderViewItem* getHoveredItem() const; + void setHoveredItem(LLFolderViewItem* itemp); - // Get the last selected item - virtual LLFolderViewItem* getCurSelectedItem( void ); + // Get the last selected item + virtual LLFolderViewItem* getCurSelectedItem( void ); selected_items_t& getSelectedItems( void ); - // Record the selected item and pass it down the hierarchy. - virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus = TRUE); - - // This method is used to toggle the selection of an item. Walks - // children, and keeps track of selected objects. - virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - - virtual std::set<LLFolderViewItem*> getSelectionList() const; - - // Make sure if ancestor is selected, descendants are not - void sanitizeSelection(); - virtual void clearSelection(); - void addToSelectionList(LLFolderViewItem* item); - void removeFromSelectionList(LLFolderViewItem* item); - - bool startDrag(); - void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; } - void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; } - LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; } - - // Deletion functionality - void removeSelectedItems(); - - void autoOpenItem(LLFolderViewFolder* item); - void closeAutoOpenedFolders(); - BOOL autoOpenTest(LLFolderViewFolder* item); - BOOL isOpen() const { return TRUE; } // root folder always open - - // Copy & paste - virtual BOOL canCopy() const; - virtual void copy(); - - virtual BOOL canCut() const; - virtual void cut(); - - virtual BOOL canPaste() const; - virtual void paste(); - - LLFolderViewItem* getNextUnselectedItem(); - - // Public rename functionality - can only start the process - void startRenamingSelectedItem( void ); - - // LLView functionality - ///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent ); - /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); - /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); - /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) { setShowSelectionContext(FALSE); } - virtual void draw(); - virtual void deleteAllChildren(); + // Record the selected item and pass it down the hierarchy. + virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus = TRUE); + + // This method is used to toggle the selection of an item. Walks + // children, and keeps track of selected objects. + virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); + + virtual std::set<LLFolderViewItem*> getSelectionList() const; + + // Make sure if ancestor is selected, descendants are not + void sanitizeSelection(); + virtual void clearSelection(); + void addToSelectionList(LLFolderViewItem* item); + void removeFromSelectionList(LLFolderViewItem* item); + + bool startDrag(); + void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; } + void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; } + LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; } + + // Deletion functionality + void removeSelectedItems(); + + void autoOpenItem(LLFolderViewFolder* item); + void closeAutoOpenedFolders(); + BOOL autoOpenTest(LLFolderViewFolder* item); + BOOL isOpen() const { return TRUE; } // root folder always open + + // Copy & paste + virtual BOOL canCopy() const; + virtual void copy(); + + virtual BOOL canCut() const; + virtual void cut(); + + virtual BOOL canPaste() const; + virtual void paste(); + + LLFolderViewItem* getNextUnselectedItem(); + + // Public rename functionality - can only start the process + void startRenamingSelectedItem( void ); + + // LLView functionality + ///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent ); + /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); + /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); + /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) { setShowSelectionContext(FALSE); } + virtual void draw(); + virtual void deleteAllChildren(); void stopAutoScollining() {mNeedsScroll = false;} - void scrollToShowSelection(); - void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); - void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; } - LLRect getVisibleRect(); + void scrollToShowSelection(); + void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); + void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; } + LLRect getVisibleRect(); - BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward); - void setShowSelectionContext(bool show) { mShowSelectionContext = show; } - BOOL getShowSelectionContext(); - void setShowSingleSelection(bool show); - BOOL getShowSingleSelection() { return mShowSingleSelection; } - F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } - bool getUseEllipses() { return mUseEllipses; } - S32 getSelectedCount() { return (S32)mSelectedItems.size(); } + BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward); + void setShowSelectionContext(bool show) { mShowSelectionContext = show; } + BOOL getShowSelectionContext(); + void setShowSingleSelection(bool show); + BOOL getShowSingleSelection() { return mShowSingleSelection; } + F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } + bool getUseEllipses() { return mUseEllipses; } + S32 getSelectedCount() { return (S32)mSelectedItems.size(); } - void update(); // needs to be called periodically (e.g. once per frame) + void update(); // needs to be called periodically (e.g. once per frame) - BOOL needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; } - BOOL needsAutoRename() { return mNeedsAutoRename; } - void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } - void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; } - void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; } + BOOL needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; } + BOOL needsAutoRename() { return mNeedsAutoRename; } + void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } + void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; } + void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; } - bool showItemLinkOverlays() { return mShowItemLinkOverlays; } + bool showItemLinkOverlays() { return mShowItemLinkOverlays; } - void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } - void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; } + void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } + void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; } void setForceArrange(bool force) { mForceArrange = force; } - LLPanel* getParentPanel() { return mParentPanel.get(); } - // DEBUG only - void dumpSelectionInformation(); + LLPanel* getParentPanel() { return mParentPanel.get(); } + // DEBUG only + void dumpSelectionInformation(); - virtual S32 notify(const LLSD& info) ; + virtual S32 notify(const LLSD& info) ; - void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; } - - bool useLabelSuffix() { return mUseLabelSuffix; } - virtual void updateMenu(); + void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; } - void finishRenamingItem( void ); + bool useLabelSuffix() { return mUseLabelSuffix; } + virtual void updateMenu(); + + void finishRenamingItem( void ); // Note: We may eventually have to move that method up the hierarchy to LLFolderViewItem. - LLHandle<LLFolderView> getHandle() const { return getDerivedHandle<LLFolderView>(); } - + LLHandle<LLFolderView> getHandle() const { return getDerivedHandle<LLFolderView>(); } + private: - void updateMenuOptions(LLMenuGL* menu); - void updateRenamerPosition(); + void updateMenuOptions(LLMenuGL* menu); + void updateRenamerPosition(); protected: - LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. + LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. - void commitRename( const LLSD& data ); - void onRenamerLost(); + void commitRename( const LLSD& data ); + void onRenamerLost(); - void closeRenamer( void ); + void closeRenamer( void ); - bool isFolderSelected(); + bool isFolderSelected(); - bool selectFirstItem(); - bool selectLastItem(); - - BOOL addNoOptions(LLMenuGL* menu) const; + bool selectFirstItem(); + bool selectLastItem(); + + BOOL addNoOptions(LLMenuGL* menu) const; protected: - LLHandle<LLView> mPopupMenuHandle; - std::string mMenuFileName; - - LLHandle<LLView> mHoveredItem; - selected_items_t mSelectedItems; - bool mKeyboardSelection, - mAllowMultiSelect, - mAllowDrag, - mShowEmptyMessage, - mShowFolderHierarchy, - mNeedsScroll, - mPinningSelectedItem, - mNeedsAutoSelect, - mAutoSelectOverride, - mNeedsAutoRename, - mUseLabelSuffix, - mDragAndDropThisFrame, - mShowItemLinkOverlays, - mShowSelectionContext, - mShowSingleSelection, - mSuppressFolderMenu, + LLHandle<LLView> mPopupMenuHandle; + std::string mMenuFileName; + + LLHandle<LLView> mHoveredItem; + selected_items_t mSelectedItems; + bool mKeyboardSelection, + mAllowMultiSelect, + mAllowDrag, + mShowEmptyMessage, + mShowFolderHierarchy, + mNeedsScroll, + mPinningSelectedItem, + mNeedsAutoSelect, + mAutoSelectOverride, + mNeedsAutoRename, + mUseLabelSuffix, + mDragAndDropThisFrame, + mShowItemLinkOverlays, + mShowSelectionContext, + mShowSingleSelection, + mSuppressFolderMenu, mSingleFolderMode; - // Renaming variables and methods - LLFolderViewItem* mRenameItem; // The item currently being renamed - LLLineEditor* mRenamer; - - LLRect mScrollConstraintRect; - - LLDepthStack<LLFolderViewFolder> mAutoOpenItems; - LLFolderViewFolder* mAutoOpenCandidate; - LLFrameTimer mAutoOpenTimer; - LLFrameTimer mSearchTimer; - std::string mSearchString; - LLFrameTimer mMultiSelectionFadeTimer; - S32 mArrangeGeneration; - - signal_t mSelectSignal; - signal_t mReshapeSignal; - S32 mSignalSelectCallback; - S32 mMinWidth; - - LLHandle<LLPanel> mParentPanel; - - LLFolderViewModelInterface* mViewModel; + // Renaming variables and methods + LLFolderViewItem* mRenameItem; // The item currently being renamed + LLLineEditor* mRenamer; + + LLRect mScrollConstraintRect; + + LLDepthStack<LLFolderViewFolder> mAutoOpenItems; + LLFolderViewFolder* mAutoOpenCandidate; + LLFrameTimer mAutoOpenTimer; + LLFrameTimer mSearchTimer; + std::string mSearchString; + LLFrameTimer mMultiSelectionFadeTimer; + S32 mArrangeGeneration; + + signal_t mSelectSignal; + signal_t mReshapeSignal; + S32 mSignalSelectCallback; + S32 mMinWidth; + + LLHandle<LLPanel> mParentPanel; + + LLFolderViewModelInterface* mViewModel; LLFolderViewGroupedItemModel* mGroupedItemModel; - /** - * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. - * NOTE: For now it's used only to cut LLFolderViewItem::mLabel text for Landmarks in Places Panel. - */ - bool mUseEllipses; // See EXT-719 + /** + * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. + * NOTE: For now it's used only to cut LLFolderViewItem::mLabel text for Landmarks in Places Panel. + */ + bool mUseEllipses; // See EXT-719 - /** - * Contains item under mouse pointer while dragging - */ - LLFolderViewItem* mDraggingOverItem; // See EXT-719 + /** + * Contains item under mouse pointer while dragging + */ + LLFolderViewItem* mDraggingOverItem; // See EXT-719 - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar; + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar; + + boost::signals2::connection mRenamerTopLostSignalConnection; bool mForceArrange; - + public: - static F32 sAutoOpenTime; - LLTextBox* mStatusTextBox; + static F32 sAutoOpenTime; + LLTextBox* mStatusTextBox; }; @@ -365,9 +367,9 @@ public: class LLFolderViewFunctor { public: - virtual ~LLFolderViewFunctor() {} - virtual void doFolder(LLFolderViewFolder* folder) = 0; - virtual void doItem(LLFolderViewItem* item) = 0; + virtual ~LLFolderViewFunctor() {} + virtual void doFolder(LLFolderViewFolder* folder) = 0; + virtual void doItem(LLFolderViewItem* item) = 0; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -375,67 +377,67 @@ public: // // This will select the first *item* found in the hierarchy. If no item can be // selected, the first matching folder will. -// Since doFolder() is done first but we prioritize item selection, we let the +// Since doFolder() is done first but we prioritize item selection, we let the // first filtered folder set the selection and raise a folder flag. -// The selection might be overridden by the first filtered item in doItem() +// The selection might be overridden by the first filtered item in doItem() // which checks an item flag. Since doFolder() checks the item flag too, the first // item will still be selected if items were to be done first and folders second. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLSelectFirstFilteredItem : public LLFolderViewFunctor { public: - LLSelectFirstFilteredItem() : mItemSelected(FALSE), mFolderSelected(FALSE) {} - virtual ~LLSelectFirstFilteredItem() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); - BOOL wasItemSelected() { return mItemSelected || mFolderSelected; } + LLSelectFirstFilteredItem() : mItemSelected(FALSE), mFolderSelected(FALSE) {} + virtual ~LLSelectFirstFilteredItem() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + BOOL wasItemSelected() { return mItemSelected || mFolderSelected; } protected: - BOOL mItemSelected; - BOOL mFolderSelected; + BOOL mItemSelected; + BOOL mFolderSelected; }; class LLOpenFilteredFolders : public LLFolderViewFunctor { public: - LLOpenFilteredFolders() {} - virtual ~LLOpenFilteredFolders() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); + LLOpenFilteredFolders() {} + virtual ~LLOpenFilteredFolders() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); }; class LLSaveFolderState : public LLFolderViewFunctor { public: - LLSaveFolderState() : mApply(FALSE) {} - virtual ~LLSaveFolderState() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item) {} - void setApply(BOOL apply); - void clearOpenFolders() { mOpenFolders.clear(); } + LLSaveFolderState() : mApply(FALSE) {} + virtual ~LLSaveFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + void setApply(BOOL apply); + void clearOpenFolders() { mOpenFolders.clear(); } protected: - std::set<LLUUID> mOpenFolders; - BOOL mApply; + std::set<LLUUID> mOpenFolders; + BOOL mApply; }; class LLOpenFoldersWithSelection : public LLFolderViewFunctor { public: - LLOpenFoldersWithSelection() {} - virtual ~LLOpenFoldersWithSelection() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); + LLOpenFoldersWithSelection() {} + virtual ~LLOpenFoldersWithSelection() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); }; class LLAllDescendentsPassedFilter : public LLFolderViewFunctor { public: - LLAllDescendentsPassedFilter() : mAllDescendentsPassedFilter(true) {} - /*virtual*/ ~LLAllDescendentsPassedFilter() {} - /*virtual*/ void doFolder(LLFolderViewFolder* folder); - /*virtual*/ void doItem(LLFolderViewItem* item); - bool allDescendentsPassedFilter() const { return mAllDescendentsPassedFilter; } + LLAllDescendentsPassedFilter() : mAllDescendentsPassedFilter(true) {} + /*virtual*/ ~LLAllDescendentsPassedFilter() {} + /*virtual*/ void doFolder(LLFolderViewFolder* folder); + /*virtual*/ void doItem(LLFolderViewItem* item); + bool allDescendentsPassedFilter() const { return mAllDescendentsPassedFilter; } protected: - bool mAllDescendentsPassedFilter; + bool mAllDescendentsPassedFilter; }; // Flags for buildContextMenu() diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 2bd14f6f6a..a9e1171444 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfolderviewitem.cpp * @brief Items and folders that can appear in a hierarchical folder view * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #include "llcallbacklist.h" #include "llcriticaldamp.h" #include "llclipboard.h" -#include "llfocusmgr.h" // gFocusMgr +#include "llfocusmgr.h" // gFocusMgr #include "lltrans.h" #include "llwindow.h" @@ -45,7 +45,7 @@ static LLDefaultChildRegistry::Register<LLFolderViewItem> r("folder_view_item"); -// statics +// statics std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts bool LLFolderViewItem::sColorSetInitialized = false; @@ -69,18 +69,18 @@ const LLColor4U DEFAULT_WHITE(255, 255, 255); //static LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) { - LLFontGL* rtn = sFonts[style]; - if (!rtn) // grab label font with this style, lazily - { - LLFontDescriptor labelfontdesc("SansSerif", "Small", style); - rtn = LLFontGL::getFont(labelfontdesc); - if (!rtn) - { - rtn = LLFontGL::getFontDefault(); - } - sFonts[style] = rtn; - } - return rtn; + LLFontGL* rtn = sFonts[style]; + if (!rtn) // grab label font with this style, lazily + { + LLFontDescriptor labelfontdesc("SansSerif", "Small", style); + rtn = LLFontGL::getFont(labelfontdesc); + if (!rtn) + { + rtn = LLFontGL::getFontDefault(); + } + sFonts[style] = rtn; + } + return rtn; } //static @@ -91,24 +91,24 @@ void LLFolderViewItem::initClass() //static void LLFolderViewItem::cleanupClass() { - sFonts.clear(); + sFonts.clear(); } // NOTE: Optimize this, we call it a *lot* when opening a large inventory LLFolderViewItem::Params::Params() -: root(), - listener(), - folder_arrow_image("folder_arrow_image"), - folder_indentation("folder_indentation"), - selection_image("selection_image"), - item_height("item_height"), - item_top_pad("item_top_pad"), - creation_date(), +: root(), + listener(), + folder_arrow_image("folder_arrow_image"), + folder_indentation("folder_indentation"), + selection_image("selection_image"), + item_height("item_height"), + item_top_pad("item_top_pad"), + creation_date(), allow_wear("allow_wear", true), allow_drop("allow_drop", true), - font_color("font_color"), - font_highlight_color("font_highlight_color"), + font_color("font_color"), + font_highlight_color("font_highlight_color"), left_pad("left_pad", 0), icon_pad("icon_pad", 0), icon_width("icon_width", 0), @@ -122,32 +122,32 @@ LLFolderViewItem::Params::Params() // Default constructor LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) -: LLView(p), - mLabelWidth(0), - mLabelWidthDirty(false), +: LLView(p), + mLabelWidth(0), + mLabelWidthDirty(false), mSuffixNeedsRefresh(false), mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT), - mParentFolder( NULL ), - mIsSelected( FALSE ), - mIsCurSelection( FALSE ), - mSelectPending(FALSE), - mIsItemCut(false), - mCutGeneration(0), - mLabelStyle( LLFontGL::NORMAL ), - mHasVisibleChildren(FALSE), + mParentFolder( NULL ), + mIsSelected( FALSE ), + mIsCurSelection( FALSE ), + mSelectPending(FALSE), + mIsItemCut(false), + mCutGeneration(0), + mLabelStyle( LLFontGL::NORMAL ), + mHasVisibleChildren(FALSE), mLocalIndentation(p.folder_indentation), - mIndentation(0), - mItemHeight(p.item_height), - mControlLabelRotation(0.f), - mDragAndDropTarget(FALSE), - mLabel(p.name), - mRoot(p.root), - mViewModelItem(p.listener), - mIsMouseOverTitle(false), - mAllowWear(p.allow_wear), + mIndentation(0), + mItemHeight(p.item_height), + mControlLabelRotation(0.f), + mDragAndDropTarget(FALSE), + mLabel(p.name), + mRoot(p.root), + mViewModelItem(p.listener), + mIsMouseOverTitle(false), + mAllowWear(p.allow_wear), mAllowDrop(p.allow_drop), - mFontColor(p.font_color), - mFontHighlightColor(p.font_highlight_color), + mFontColor(p.font_color), + mFontHighlightColor(p.font_highlight_color), mLeftPad(p.left_pad), mIconPad(p.icon_pad), mIconWidth(p.icon_width), @@ -158,30 +158,30 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mMaxFolderItemOverlap(p.max_folder_item_overlap), mDoubleClickOverride(p.double_click_override) { - if (!sColorSetInitialized) - { - sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); - sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); - sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); - sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); - sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); - sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); - sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); - sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); - sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); - sColorSetInitialized = true; - } - - if (mViewModelItem) - { - mViewModelItem->setFolderViewItem(this); - } + if (!sColorSetInitialized) + { + sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); + sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); + sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); + sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); + sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); + sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); + sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); + sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); + sColorSetInitialized = true; + } + + if (mViewModelItem) + { + mViewModelItem->setFolderViewItem(this); + } } // Destroys the object LLFolderViewItem::~LLFolderViewItem() { - mViewModelItem = NULL; + mViewModelItem = NULL; gFocusMgr.removeKeyboardFocusWithoutCallback(this); } @@ -207,99 +207,99 @@ BOOL LLFolderViewItem::postBuild() // while LLFolderViewItem::arrange() updates visual part mSuffixNeedsRefresh = true; mLabelWidthDirty = true; - return TRUE; + return TRUE; } LLFolderView* LLFolderViewItem::getRoot() { - return mRoot; + return mRoot; } const LLFolderView* LLFolderViewItem::getRoot() const { - return mRoot; + return mRoot; } // Returns true if this object is a child (or grandchild, etc.) of potential_ancestor. BOOL LLFolderViewItem::isDescendantOf( const LLFolderViewFolder* potential_ancestor ) { - LLFolderViewItem* root = this; - while( root->mParentFolder ) - { - if( root->mParentFolder == potential_ancestor ) - { - return TRUE; - } - root = root->mParentFolder; - } - return FALSE; + LLFolderViewItem* root = this; + while( root->mParentFolder ) + { + if( root->mParentFolder == potential_ancestor ) + { + return TRUE; + } + root = root->mParentFolder; + } + return FALSE; } LLFolderViewItem* LLFolderViewItem::getNextOpenNode(BOOL include_children) { - if (!mParentFolder) - { - return NULL; - } + if (!mParentFolder) + { + return NULL; + } - LLFolderViewItem* itemp = mParentFolder->getNextFromChild( this, include_children ); - while(itemp && !itemp->getVisible()) - { - LLFolderViewItem* next_itemp = itemp->mParentFolder->getNextFromChild( itemp, include_children ); - if (itemp == next_itemp) - { - // hit last item - return itemp->getVisible() ? itemp : this; - } - itemp = next_itemp; - } + LLFolderViewItem* itemp = mParentFolder->getNextFromChild( this, include_children ); + while(itemp && !itemp->getVisible()) + { + LLFolderViewItem* next_itemp = itemp->mParentFolder->getNextFromChild( itemp, include_children ); + if (itemp == next_itemp) + { + // hit last item + return itemp->getVisible() ? itemp : this; + } + itemp = next_itemp; + } - return itemp; + return itemp; } LLFolderViewItem* LLFolderViewItem::getPreviousOpenNode(BOOL include_children) { - if (!mParentFolder) - { - return NULL; - } + if (!mParentFolder) + { + return NULL; + } - LLFolderViewItem* itemp = mParentFolder->getPreviousFromChild( this, include_children ); + LLFolderViewItem* itemp = mParentFolder->getPreviousFromChild( this, include_children ); - // Skip over items that are invisible or are hidden from the UI. - while(itemp && !itemp->getVisible()) - { - LLFolderViewItem* next_itemp = itemp->mParentFolder->getPreviousFromChild( itemp, include_children ); - if (itemp == next_itemp) - { - // hit first item - return itemp->getVisible() ? itemp : this; - } - itemp = next_itemp; - } + // Skip over items that are invisible or are hidden from the UI. + while(itemp && !itemp->getVisible()) + { + LLFolderViewItem* next_itemp = itemp->mParentFolder->getPreviousFromChild( itemp, include_children ); + if (itemp == next_itemp) + { + // hit first item + return itemp->getVisible() ? itemp : this; + } + itemp = next_itemp; + } - return itemp; + return itemp; } -BOOL LLFolderViewItem::passedFilter(S32 filter_generation) +BOOL LLFolderViewItem::passedFilter(S32 filter_generation) { - return getViewModelItem()->passedFilter(filter_generation); + return getViewModelItem()->passedFilter(filter_generation); } BOOL LLFolderViewItem::isPotentiallyVisible(S32 filter_generation) { - if (filter_generation < 0) - { - filter_generation = getFolderViewModel()->getFilter().getFirstSuccessGeneration(); - } - LLFolderViewModelItem* model = getViewModelItem(); - BOOL visible = model->passedFilter(filter_generation); - if (model->getMarkedDirtyGeneration() >= filter_generation) - { - // unsure visibility state - // retaining previous visibility until item is updated or filter generation changes - visible |= getVisible(); - } - return visible; + if (filter_generation < 0) + { + filter_generation = getFolderViewModel()->getFilter().getFirstSuccessGeneration(); + } + LLFolderViewModelItem* model = getViewModelItem(); + BOOL visible = model->passedFilter(filter_generation); + if (model->getMarkedDirtyGeneration() >= filter_generation) + { + // unsure visibility state + // retaining previous visibility until item is updated or filter generation changes + visible |= getVisible(); + } + return visible; } void LLFolderViewItem::refresh() @@ -331,21 +331,21 @@ void LLFolderViewItem::refresh() void LLFolderViewItem::refreshSuffix() { - LLFolderViewModelItem const* vmi = getViewModelItem(); + LLFolderViewModelItem const* vmi = getViewModelItem(); // icons are slightly expensive to get, can be optimized // see LLInventoryIcon::getIcon() - mIcon = vmi->getIcon(); + mIcon = vmi->getIcon(); mIconOpen = vmi->getIconOpen(); mIconOverlay = vmi->getIconOverlay(); - if (mRoot->useLabelSuffix()) - { + if (mRoot->useLabelSuffix()) + { // Very Expensive! // Can do a number of expensive checks, like checking active motions, wearables or friend list mLabelStyle = vmi->getLabelStyle(); mLabelSuffix = vmi->getLabelSuffix(); - } + } mLabelWidthDirty = true; mSuffixNeedsRefresh = false; @@ -353,39 +353,39 @@ void LLFolderViewItem::refreshSuffix() // Utility function for LLFolderView void LLFolderViewItem::arrangeAndSet(BOOL set_selection, - BOOL take_keyboard_focus) + BOOL take_keyboard_focus) { - LLFolderView* root = getRoot(); - if (getParentFolder()) - { - getParentFolder()->requestArrange(); - } - if(set_selection) - { - getRoot()->setSelection(this, TRUE, take_keyboard_focus); - if(root) - { - root->scrollToShowSelection(); - } - } + LLFolderView* root = getRoot(); + if (getParentFolder()) + { + getParentFolder()->requestArrange(); + } + if(set_selection) + { + getRoot()->setSelection(this, TRUE, take_keyboard_focus); + if(root) + { + root->scrollToShowSelection(); + } + } } std::set<LLFolderViewItem*> LLFolderViewItem::getSelectionList() const { - std::set<LLFolderViewItem*> selection; - return selection; + std::set<LLFolderViewItem*> selection; + return selection; } // addToFolder() returns TRUE if it succeeds. FALSE otherwise void LLFolderViewItem::addToFolder(LLFolderViewFolder* folder) { - folder->addItem(this); + folder->addItem(this); - // Compute indentation since parent folder changed - mIndentation = (getParentFolder()) - ? getParentFolder()->getIndentation() + mLocalIndentation - : 0; + // Compute indentation since parent folder changed + mIndentation = (getParentFolder()) + ? getParentFolder()->getIndentation() + mLocalIndentation + : 0; } @@ -393,38 +393,38 @@ void LLFolderViewItem::addToFolder(LLFolderViewFolder* folder) // makes sure that this view and its children are the right size. S32 LLFolderViewItem::arrange( S32* width, S32* height ) { - // Only indent deeper items in hierarchy - mIndentation = (getParentFolder()) - ? getParentFolder()->getIndentation() + mLocalIndentation - : 0; - if (mLabelWidthDirty) - { + // Only indent deeper items in hierarchy + mIndentation = (getParentFolder()) + ? getParentFolder()->getIndentation() + mLocalIndentation + : 0; + if (mLabelWidthDirty) + { if (mSuffixNeedsRefresh) { // Expensive. But despite refreshing label, // it is purely visual, so it is fine to do at our laisure refreshSuffix(); } - mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight; - mLabelWidthDirty = false; - } + mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight; + mLabelWidthDirty = false; + } - *width = llmax(*width, mLabelWidth); + *width = llmax(*width, mLabelWidth); - // determine if we need to use ellipses to avoid horizontal scroll. EXT-719 - bool use_ellipses = getRoot()->getUseEllipses(); - if (use_ellipses) - { - // limit to set rect to avoid horizontal scrollbar - *width = llmin(*width, getRoot()->getRect().getWidth()); - } - *height = getItemHeight(); - return *height; + // determine if we need to use ellipses to avoid horizontal scroll. EXT-719 + bool use_ellipses = getRoot()->getUseEllipses(); + if (use_ellipses) + { + // limit to set rect to avoid horizontal scrollbar + *width = llmin(*width, getRoot()->getRect().getWidth()); + } + *height = getItemHeight(); + return *height; } S32 LLFolderViewItem::getItemHeight() const { - return mItemHeight; + return mItemHeight; } S32 LLFolderViewItem::getLabelXPos() @@ -449,68 +449,68 @@ S32 LLFolderViewItem::getTextPad() // together. BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus) { - if (selection == this && !mIsSelected) - { - selectItem(); - } - else if (mIsSelected) // Deselect everything else. - { - deselectItem(); - } - return mIsSelected; + if (selection == this && !mIsSelected) + { + selectItem(); + } + else if (mIsSelected) // Deselect everything else. + { + deselectItem(); + } + return mIsSelected; } BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected) { - if (selection == this) - { - if (mIsSelected) - { - deselectItem(); - } - else - { - selectItem(); - } - return TRUE; - } - return FALSE; + if (selection == this) + { + if (mIsSelected) + { + deselectItem(); + } + else + { + selectItem(); + } + return TRUE; + } + return FALSE; } void LLFolderViewItem::deselectItem(void) { - mIsSelected = FALSE; + mIsSelected = FALSE; } void LLFolderViewItem::selectItem(void) { - if (mIsSelected == FALSE) - { - mIsSelected = TRUE; - getViewModelItem()->selectItem(); - } + if (mIsSelected == FALSE) + { + mIsSelected = TRUE; + getViewModelItem()->selectItem(); + } } BOOL LLFolderViewItem::isMovable() { - return getViewModelItem()->isItemMovable(); + return getViewModelItem()->isItemMovable(); } BOOL LLFolderViewItem::isRemovable() { - return getViewModelItem()->isItemRemovable(); + return getViewModelItem()->isItemRemovable(); } void LLFolderViewItem::destroyView() { - getRoot()->removeFromSelectionList(this); + getRoot()->removeFromSelectionList(this); - if (mParentFolder) - { - // removeView deletes me - mParentFolder->extractItem(this); - } - delete this; + if (mParentFolder) + { + // removeView deletes me + mParentFolder->extractItem(this); + } + delete this; } // Call through to the viewed object and return true if it can be @@ -518,250 +518,248 @@ void LLFolderViewItem::destroyView() //BOOL LLFolderViewItem::removeRecursively(BOOL single_item) BOOL LLFolderViewItem::remove() { - if(!isRemovable()) - { - return FALSE; - } - return getViewModelItem()->removeItem(); + if(!isRemovable()) + { + return FALSE; + } + return getViewModelItem()->removeItem(); } // Build an appropriate context menu for the item. void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags) { - getViewModelItem()->buildContextMenu(menu, flags); + getViewModelItem()->buildContextMenu(menu, flags); } void LLFolderViewItem::openItem( void ) { - if (mAllowWear || !getViewModelItem()->isItemWearable()) - { - getViewModelItem()->openItem(); - } + if (mAllowWear || !getViewModelItem()->isItemWearable()) + { + getViewModelItem()->openItem(); + } } void LLFolderViewItem::rename(const std::string& new_name) { - if( !new_name.empty() ) - { - getViewModelItem()->renameItem(new_name); - } + if( !new_name.empty() ) + { + getViewModelItem()->renameItem(new_name); + } } const std::string& LLFolderViewItem::getName( void ) const { - static const std::string noName(""); - return getViewModelItem() ? getViewModelItem()->getName() : noName; + static const std::string noName(""); + return getViewModelItem() ? getViewModelItem()->getName() : noName; } // LLView functionality BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) { - if(!mIsSelected) - { - getRoot()->setSelection(this, FALSE); - } - make_ui_sound("UISndClick"); - return TRUE; + if(!mIsSelected) + { + getRoot()->setSelection(this, FALSE); + } + make_ui_sound("UISndClick"); + return TRUE; } BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) { - if (LLView::childrenHandleMouseDown(x, y, mask)) - { - return TRUE; - } - - // No handler needed for focus lost since this class has no - // state that depends on it. - gFocusMgr.setMouseCapture( this ); - - if (!mIsSelected) - { - if(mask & MASK_CONTROL) - { - getRoot()->changeSelection(this, !mIsSelected); - } - else if (mask & MASK_SHIFT) - { - getParentFolder()->extendSelectionTo(this); - } - else - { - getRoot()->setSelection(this, FALSE); - } - make_ui_sound("UISndClick"); - } - else - { - // If selected, we reserve the decision of deselecting/reselecting to the mouse up moment. - // This is necessary so we maintain selection consistent when starting a drag. - mSelectPending = TRUE; - } - - mDragStartX = x; - mDragStartY = y; - return TRUE; + if (LLView::childrenHandleMouseDown(x, y, mask)) + { + return TRUE; + } + + // No handler needed for focus lost since this class has no + // state that depends on it. + gFocusMgr.setMouseCapture( this ); + + if (!mIsSelected) + { + if(mask & MASK_CONTROL) + { + getRoot()->changeSelection(this, !mIsSelected); + } + else if (mask & MASK_SHIFT) + { + getParentFolder()->extendSelectionTo(this); + } + else + { + getRoot()->setSelection(this, FALSE); + } + make_ui_sound("UISndClick"); + } + else + { + // If selected, we reserve the decision of deselecting/reselecting to the mouse up moment. + // This is necessary so we maintain selection consistent when starting a drag. + mSelectPending = TRUE; + } + + mDragStartX = x; + mDragStartY = y; + return TRUE; } BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) { - static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3); - - mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); - - if( hasMouseCapture() && isMovable() ) - { - LLFolderView* root = getRoot(); - - if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold() - && root->getAllowDrag() - && root->getCurSelectedItem() - && root->startDrag()) - { - // RN: when starting drag and drop, clear out last auto-open - root->autoOpenTest(NULL); - root->setShowSelectionContext(TRUE); - - // Release keyboard focus, so that if stuff is dropped into the - // world, pressing the delete key won't blow away the inventory - // item. - gFocusMgr.setKeyboardFocus(NULL); - - getWindow()->setCursor(UI_CURSOR_ARROW); - } - else if (x != mDragStartX || y != mDragStartY) - { - getWindow()->setCursor(UI_CURSOR_NOLOCKED); - } - - root->clearHoveredItem(); - return TRUE; - } - else - { - LLFolderView* pRoot = getRoot(); - pRoot->setHoveredItem(this); - pRoot->setShowSelectionContext(FALSE); - getWindow()->setCursor(UI_CURSOR_ARROW); - // let parent handle this then... - return FALSE; - } + mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); + + if( hasMouseCapture() && isMovable() ) + { + LLFolderView* root = getRoot(); + + if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD + && root->getAllowDrag() + && root->getCurSelectedItem() + && root->startDrag()) + { + // RN: when starting drag and drop, clear out last auto-open + root->autoOpenTest(NULL); + root->setShowSelectionContext(TRUE); + + // Release keyboard focus, so that if stuff is dropped into the + // world, pressing the delete key won't blow away the inventory + // item. + gFocusMgr.setKeyboardFocus(NULL); + + getWindow()->setCursor(UI_CURSOR_ARROW); + } + else if (x != mDragStartX || y != mDragStartY) + { + getWindow()->setCursor(UI_CURSOR_NOLOCKED); + } + + root->clearHoveredItem(); + return TRUE; + } + else + { + LLFolderView* pRoot = getRoot(); + pRoot->setHoveredItem(this); + pRoot->setShowSelectionContext(FALSE); + getWindow()->setCursor(UI_CURSOR_ARROW); + // let parent handle this then... + return FALSE; + } } BOOL LLFolderViewItem::handleDoubleClick( S32 x, S32 y, MASK mask ) { - openItem(); - return TRUE; + openItem(); + return TRUE; } BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) { - if (LLView::childrenHandleMouseUp(x, y, mask)) - { - return TRUE; - } - - // if mouse hasn't moved since mouse down... - if ( pointInView(x, y) && mSelectPending ) - { - //...then select - if(mask & MASK_CONTROL) - { - getRoot()->changeSelection(this, !mIsSelected); - } - else if (mask & MASK_SHIFT) - { - getParentFolder()->extendSelectionTo(this); - } - else - { - getRoot()->setSelection(this, FALSE); - } - } - - mSelectPending = FALSE; - - if( hasMouseCapture() ) - { - if (getRoot()) - { - getRoot()->setShowSelectionContext(FALSE); - } - gFocusMgr.setMouseCapture( NULL ); - } - return TRUE; + if (LLView::childrenHandleMouseUp(x, y, mask)) + { + return TRUE; + } + + // if mouse hasn't moved since mouse down... + if ( pointInView(x, y) && mSelectPending ) + { + //...then select + if(mask & MASK_CONTROL) + { + getRoot()->changeSelection(this, !mIsSelected); + } + else if (mask & MASK_SHIFT) + { + getParentFolder()->extendSelectionTo(this); + } + else + { + getRoot()->setSelection(this, FALSE); + } + } + + mSelectPending = FALSE; + + if( hasMouseCapture() ) + { + if (getRoot()) + { + getRoot()->setShowSelectionContext(FALSE); + } + gFocusMgr.setMouseCapture( NULL ); + } + return TRUE; } void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask) { - mIsMouseOverTitle = false; + mIsMouseOverTitle = false; - // NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it - LLFolderView* pRoot = getRoot(); - if (this == pRoot->getHoveredItem()) - { - pRoot->clearHoveredItem(); - } + // NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it + LLFolderView* pRoot = getRoot(); + if (this == pRoot->getHoveredItem()) + { + pRoot->clearHoveredItem(); + } } BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - BOOL handled = FALSE; - BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg); - handled = accepted; - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - if(mParentFolder && !handled) - { - // store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event. - mRoot->setDraggingOverItem(this); - handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); - mRoot->setDraggingOverItem(NULL); - } - if (handled) - { - LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewItem" << LL_ENDL; - } - - return handled; + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL handled = FALSE; + BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg); + handled = accepted; + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + if(mParentFolder && !handled) + { + // store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event. + mRoot->setDraggingOverItem(this); + handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + mRoot->setDraggingOverItem(NULL); + } + if (handled) + { + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewItem" << LL_ENDL; + } + + return handled; } void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color) { - //--------------------------------------------------------------------------------// - // Draw open folder arrow - // - const S32 TOP_PAD = default_params.item_top_pad; + //--------------------------------------------------------------------------------// + // Draw open folder arrow + // + const S32 TOP_PAD = default_params.item_top_pad; - if (hasVisibleChildren() || !isFolderComplete()) - { - LLUIImage* arrow_image = default_params.folder_arrow_image; - gl_draw_scaled_rotated_image( - mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, - mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color); - } + if (hasVisibleChildren() || !isFolderComplete()) + { + LLUIImage* arrow_image = default_params.folder_arrow_image; + gl_draw_scaled_rotated_image( + mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, + mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color); + } } /*virtual*/ bool LLFolderViewItem::isHighlightAllowed() { - return mIsSelected; + return mIsSelected; } /*virtual*/ bool LLFolderViewItem::isHighlightActive() { - return mIsCurSelection; + return mIsCurSelection; } /*virtual*/ bool LLFolderViewItem::isFadeItem() @@ -777,31 +775,31 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L return mIsItemCut; } -void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, +void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor) { const S32 focus_top = getRect().getHeight(); const S32 focus_bottom = getRect().getHeight() - mItemHeight; const bool folder_open = (getRect().getHeight() > mItemHeight + 4); const S32 FOCUS_LEFT = 1; - - // Determine which background color to use for highlighting - LLUIColor bgColor = (isFlashing() ? flashColor : selectColor); + + // Determine which background color to use for highlighting + LLUIColor bgColor = (isFlashing() ? flashColor : selectColor); //--------------------------------------------------------------------------------// // Draw highlight for selected items - // Note: Always render "current" item or flashing item, only render other selected - // items if mShowSingleSelection is FALSE. + // Note: Always render "current" item or flashing item, only render other selected + // items if mShowSingleSelection is FALSE. // - if (isHighlightAllowed()) - + if (isHighlightAllowed()) + { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // Highlight for selected but not current items + + // Highlight for selected but not current items if (!isHighlightActive() && !isFlashing()) { - LLColor4 bg_color = bgColor; + LLColor4 bg_color = bgColor; // do time-based fade of extra objects F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f); if (getRoot() && getRoot()->getShowSingleSelection()) @@ -814,25 +812,25 @@ void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeybo // fading in bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); } - gl_rect_2d(FOCUS_LEFT, - focus_top, - getRect().getWidth() - 2, - focus_bottom, - bg_color, hasKeyboardFocus); + gl_rect_2d(FOCUS_LEFT, + focus_top, + getRect().getWidth() - 2, + focus_bottom, + bg_color, hasKeyboardFocus); } - // Highlight for currently selected or flashing item + // Highlight for currently selected or flashing item if (isHighlightActive()) { - // Background - gl_rect_2d(FOCUS_LEFT, + // Background + gl_rect_2d(FOCUS_LEFT, focus_top, getRect().getWidth() - 2, focus_bottom, bgColor, hasKeyboardFocus); - // Outline - gl_rect_2d(FOCUS_LEFT, - focus_top, + // Outline + gl_rect_2d(FOCUS_LEFT, + focus_top, getRect().getWidth() - 2, focus_bottom, focusOutlineColor, FALSE); @@ -858,7 +856,7 @@ void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeybo else if (mIsMouseOverTitle) { gl_rect_2d(FOCUS_LEFT, - focus_top, + focus_top, getRect().getWidth() - 2, focus_bottom, mouseOverColor, FALSE); @@ -870,8 +868,8 @@ void LLFolderViewItem::drawHighlight(const BOOL showContent, const BOOL hasKeybo if (mDragAndDropTarget) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(FOCUS_LEFT, - focus_top, + gl_rect_2d(FOCUS_LEFT, + focus_top, getRect().getWidth() - 2, focus_bottom, bgColor, FALSE); @@ -902,10 +900,10 @@ void LLFolderViewItem::draw() const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE); const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled - const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>(); - const S32 TOP_PAD = default_params.item_top_pad; - - const LLFontGL* font = getLabelFontForStyle(mLabelStyle); + const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>(); + const S32 TOP_PAD = default_params.item_top_pad; + + const LLFontGL* font = getLabelFontForStyle(mLabelStyle); getViewModelItem()->update(); @@ -916,52 +914,52 @@ void LLFolderViewItem::draw() drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor); - //--------------------------------------------------------------------------------// - // Draw open icon - // - const S32 icon_x = mIndentation + mArrowSize + mTextPad; - if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders - { - mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); - } - else if (mIcon) - { - mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); - } - - if (mIconOverlay && getRoot()->showItemLinkOverlays()) - { - mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); - } - - //--------------------------------------------------------------------------------// - // Exit if no label to draw - // - if (mLabel.empty()) - { - return; - } - - std::string::size_type filter_string_length = mViewModelItem->hasFilterStringMatch() ? mViewModelItem->getFilterStringSize() : 0; - F32 right_x = 0; - F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; - F32 text_left = (F32)getLabelXPos(); - std::string combined_string = mLabel + mLabelSuffix; + //--------------------------------------------------------------------------------// + // Draw open icon + // + const S32 icon_x = mIndentation + mArrowSize + mTextPad; + if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders + { + mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); + } + else if (mIcon) + { + mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + } + + if (mIconOverlay && getRoot()->showItemLinkOverlays()) + { + mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + } + + //--------------------------------------------------------------------------------// + // Exit if no label to draw + // + if (mLabel.empty()) + { + return; + } + + std::string::size_type filter_string_length = mViewModelItem->hasFilterStringMatch() ? mViewModelItem->getFilterStringSize() : 0; + F32 right_x = 0; + F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 text_left = (F32)getLabelXPos(); + std::string combined_string = mLabel + mLabelSuffix; const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL); S32 filter_offset = mViewModelItem->getFilterStringOffset(); - if (filter_string_length > 0) - { + if (filter_string_length > 0) + { S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); S32 top = getRect().getHeight() - TOP_PAD; if(mLabelSuffix.empty() || (font == suffix_font)) { S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2; - S32 right = left + font->getWidth(combined_string, mViewModelItem->getFilterStringOffset(), filter_string_length) + 2; + S32 right = left + font->getWidth(combined_string, mViewModelItem->getFilterStringOffset(), filter_string_length) + 2; - LLUIImage* box_image = default_params.selection_image; - LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + LLUIImage* box_image = default_params.selection_image; + LLRect box_rect(left, top, right, bottom); + box_image->draw(box_rect, sFilterBGColor); } else { @@ -996,19 +994,19 @@ void LLFolderViewItem::draw() } drawLabel(font, text_left, y, color, right_x); - //--------------------------------------------------------------------------------// - // Draw label suffix - // - if (!mLabelSuffix.empty()) - { + //--------------------------------------------------------------------------------// + // Draw label suffix + // + if (!mLabelSuffix.empty()) + { suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x); - } + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x); + } - //--------------------------------------------------------------------------------// - // Highlight string match - // + //--------------------------------------------------------------------------------// + // Highlight string match + // if (filter_string_length > 0) { if(mLabelSuffix.empty() || (font == suffix_font)) @@ -1030,7 +1028,7 @@ void LLFolderViewItem::draw() sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x); } - + S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; if(suffix_filter_length > 0) { @@ -1052,17 +1050,17 @@ void LLFolderViewItem::draw() const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const { - return getRoot()->getFolderViewModel(); + return getRoot()->getFolderViewModel(); } - + LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) { - return getRoot()->getFolderViewModel(); + return getRoot()->getFolderViewModel(); } bool LLFolderViewItem::isInSelection() const { - return mIsSelected || (mParentFolder && mParentFolder->isInSelection()); + return mIsSelected || (mParentFolder && mParentFolder->isInSelection()); } @@ -1071,58 +1069,58 @@ bool LLFolderViewItem::isInSelection() const /// Class LLFolderViewFolder ///---------------------------------------------------------------------------- -LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): - LLFolderViewItem( p ), - mIsOpen(FALSE), - mExpanderHighlighted(FALSE), - mCurHeight(0.f), - mTargetHeight(0.f), - mAutoOpenCountdown(0.f), - mIsFolderComplete(false), // folder might have children that are not loaded yet. - mAreChildrenInited(false), // folder might have children that are not built yet. - mLastArrangeGeneration( -1 ), - mLastCalculatedWidth(0) +LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): + LLFolderViewItem( p ), + mIsOpen(FALSE), + mExpanderHighlighted(FALSE), + mCurHeight(0.f), + mTargetHeight(0.f), + mAutoOpenCountdown(0.f), + mIsFolderComplete(false), // folder might have children that are not loaded yet. + mAreChildrenInited(false), // folder might have children that are not built yet. + mLastArrangeGeneration( -1 ), + mLastCalculatedWidth(0) { } void LLFolderViewFolder::updateLabelRotation() { - if (mAutoOpenCountdown != 0.f) - { - mControlLabelRotation = mAutoOpenCountdown * -90.f; - } - else if (isOpen()) - { - mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLSmoothInterpolation::getInterpolant(0.04f)); - } - else - { - mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLSmoothInterpolation::getInterpolant(0.025f)); - } + if (mAutoOpenCountdown != 0.f) + { + mControlLabelRotation = mAutoOpenCountdown * -90.f; + } + else if (isOpen()) + { + mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLSmoothInterpolation::getInterpolant(0.04f)); + } + else + { + mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLSmoothInterpolation::getInterpolant(0.025f)); + } } // Destroys the object LLFolderViewFolder::~LLFolderViewFolder( void ) { - // The LLView base class takes care of object destruction. make sure that we - // don't have mouse or keyboard focus - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + // The LLView base class takes care of object destruction. make sure that we + // don't have mouse or keyboard focus + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() } // addToFolder() returns TRUE if it succeeds. FALSE otherwise void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder) { - folder->addFolder(this); + folder->addFolder(this); - // Compute indentation since parent folder changed - mIndentation = (getParentFolder()) - ? getParentFolder()->getIndentation() + mLocalIndentation - : 0; + // Compute indentation since parent folder changed + mIndentation = (getParentFolder()) + ? getParentFolder()->getIndentation() + mLocalIndentation + : 0; - if(isOpen() && folder->isOpen()) - { - requestArrange(); - } + if(isOpen() && folder->isOpen()) + { + requestArrange(); + } } static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange"); @@ -1136,177 +1134,177 @@ static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange"); // * Makes sure that this view and its children are the right size S32 LLFolderViewFolder::arrange( S32* width, S32* height ) { - // Sort before laying out contents + // Sort before laying out contents // Note that we sort from the root (CHUI-849) if (mAreChildrenInited) { getRoot()->getFolderViewModel()->sort(this); } - LL_RECORD_BLOCK_TIME(FTM_ARRANGE); - - // evaluate mHasVisibleChildren - mHasVisibleChildren = false; - if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter()) - { - // We have to verify that there's at least one child that's not filtered out - bool found = false; - // Try the items first - for (items_t::iterator iit = mItems.begin(); iit != mItems.end(); ++iit) - { - LLFolderViewItem* itemp = (*iit); - found = itemp->isPotentiallyVisible(); - if (found) - break; - } - if (!found) - { - // If no item found, try the folders - for (folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) - { - LLFolderViewFolder* folderp = (*fit); - found = folderp->isPotentiallyVisible(); - if (found) - break; - } - } - - mHasVisibleChildren = found; - } - if (!mIsFolderComplete && mAreChildrenInited) - { - mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); - } - - - - // calculate height as a single item (without any children), and reshapes rectangle to match - LLFolderViewItem::arrange( width, height ); - - // clamp existing animated height so as to never get smaller than a single item - mCurHeight = llmax((F32)*height, mCurHeight); - - // initialize running height value as height of single item in case we have no children - F32 running_height = (F32)*height; - F32 target_height = (F32)*height; - - // are my children visible? - if (needsArrange()) - { - // set last arrange generation first, in case children are animating - // and need to be arranged again - mLastArrangeGeneration = getRoot()->getArrangeGeneration(); - if (isOpen()) - { - // Add sizes of children - S32 parent_item_height = getRect().getHeight(); - - for(folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) - { - LLFolderViewFolder* folderp = (*fit); - folderp->setVisible(folderp->isPotentiallyVisible()); - - if (folderp->getVisible()) - { - S32 child_width = *width; - S32 child_height = 0; - S32 child_top = parent_item_height - ll_round(running_height); - - target_height += folderp->arrange( &child_width, &child_height ); - - running_height += (F32)child_height; - *width = llmax(*width, child_width); - folderp->setOrigin( 0, child_top - folderp->getRect().getHeight() ); - } - } - for(items_t::iterator iit = mItems.begin(); - iit != mItems.end(); ++iit) - { - LLFolderViewItem* itemp = (*iit); - itemp->setVisible(itemp->isPotentiallyVisible()); - - if (itemp->getVisible()) - { - S32 child_width = *width; - S32 child_height = 0; - S32 child_top = parent_item_height - ll_round(running_height); - - target_height += itemp->arrange( &child_width, &child_height ); - // don't change width, as this item is as wide as its parent folder by construction - itemp->reshape( itemp->getRect().getWidth(), child_height); - - running_height += (F32)child_height; - *width = llmax(*width, child_width); - itemp->setOrigin( 0, child_top - itemp->getRect().getHeight() ); - } - } - } - - mTargetHeight = target_height; - // cache this width so next time we can just return it - mLastCalculatedWidth = *width; - } - else - { - // just use existing width - *width = mLastCalculatedWidth; - } - - // animate current height towards target height - if (llabs(mCurHeight - mTargetHeight) > 1.f) - { - mCurHeight = lerp(mCurHeight, mTargetHeight, LLSmoothInterpolation::getInterpolant(isOpen() ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); - - requestArrange(); - - // hide child elements that fall out of current animated height - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - // number of pixels that bottom of folder label is from top of parent folder - if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() - > ll_round(mCurHeight) + mMaxFolderItemOverlap) - { - // hide if beyond current folder height - (*fit)->setVisible(FALSE); - } - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - // number of pixels that bottom of item label is from top of parent folder - if (getRect().getHeight() - (*iit)->getRect().mBottom - > ll_round(mCurHeight) + mMaxFolderItemOverlap) - { - (*iit)->setVisible(FALSE); - } - } - } - else - { - mCurHeight = mTargetHeight; - } - - // don't change width as this item is already as wide as its parent folder - reshape(getRect().getWidth(),ll_round(mCurHeight)); - - // pass current height value back to parent - *height = ll_round(mCurHeight); - - return ll_round(mTargetHeight); + LL_RECORD_BLOCK_TIME(FTM_ARRANGE); + + // evaluate mHasVisibleChildren + mHasVisibleChildren = false; + if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter()) + { + // We have to verify that there's at least one child that's not filtered out + bool found = false; + // Try the items first + for (items_t::iterator iit = mItems.begin(); iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + found = itemp->isPotentiallyVisible(); + if (found) + break; + } + if (!found) + { + // If no item found, try the folders + for (folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) + { + LLFolderViewFolder* folderp = (*fit); + found = folderp->isPotentiallyVisible(); + if (found) + break; + } + } + + mHasVisibleChildren = found; + } + if (!mIsFolderComplete && mAreChildrenInited) + { + mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); + } + + + + // calculate height as a single item (without any children), and reshapes rectangle to match + LLFolderViewItem::arrange( width, height ); + + // clamp existing animated height so as to never get smaller than a single item + mCurHeight = llmax((F32)*height, mCurHeight); + + // initialize running height value as height of single item in case we have no children + F32 running_height = (F32)*height; + F32 target_height = (F32)*height; + + // are my children visible? + if (needsArrange()) + { + // set last arrange generation first, in case children are animating + // and need to be arranged again + mLastArrangeGeneration = getRoot()->getArrangeGeneration(); + if (isOpen()) + { + // Add sizes of children + S32 parent_item_height = getRect().getHeight(); + + for(folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) + { + LLFolderViewFolder* folderp = (*fit); + folderp->setVisible(folderp->isPotentiallyVisible()); + + if (folderp->getVisible()) + { + S32 child_width = *width; + S32 child_height = 0; + S32 child_top = parent_item_height - ll_round(running_height); + + target_height += folderp->arrange( &child_width, &child_height ); + + running_height += (F32)child_height; + *width = llmax(*width, child_width); + folderp->setOrigin( 0, child_top - folderp->getRect().getHeight() ); + } + } + for(items_t::iterator iit = mItems.begin(); + iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + itemp->setVisible(itemp->isPotentiallyVisible()); + + if (itemp->getVisible()) + { + S32 child_width = *width; + S32 child_height = 0; + S32 child_top = parent_item_height - ll_round(running_height); + + target_height += itemp->arrange( &child_width, &child_height ); + // don't change width, as this item is as wide as its parent folder by construction + itemp->reshape( itemp->getRect().getWidth(), child_height); + + running_height += (F32)child_height; + *width = llmax(*width, child_width); + itemp->setOrigin( 0, child_top - itemp->getRect().getHeight() ); + } + } + } + + mTargetHeight = target_height; + // cache this width so next time we can just return it + mLastCalculatedWidth = *width; + } + else + { + // just use existing width + *width = mLastCalculatedWidth; + } + + // animate current height towards target height + if (llabs(mCurHeight - mTargetHeight) > 1.f) + { + mCurHeight = lerp(mCurHeight, mTargetHeight, LLSmoothInterpolation::getInterpolant(isOpen() ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); + + requestArrange(); + + // hide child elements that fall out of current animated height + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + // number of pixels that bottom of folder label is from top of parent folder + if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() + > ll_round(mCurHeight) + mMaxFolderItemOverlap) + { + // hide if beyond current folder height + (*fit)->setVisible(FALSE); + } + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + // number of pixels that bottom of item label is from top of parent folder + if (getRect().getHeight() - (*iit)->getRect().mBottom + > ll_round(mCurHeight) + mMaxFolderItemOverlap) + { + (*iit)->setVisible(FALSE); + } + } + } + else + { + mCurHeight = mTargetHeight; + } + + // don't change width as this item is already as wide as its parent folder + reshape(getRect().getWidth(),ll_round(mCurHeight)); + + // pass current height value back to parent + *height = ll_round(mCurHeight); + + return ll_round(mTargetHeight); } BOOL LLFolderViewFolder::needsArrange() { - return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); + return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); } bool LLFolderViewFolder::descendantsPassedFilter(S32 filter_generation) { - return getViewModelItem()->descendantsPassedFilter(filter_generation); + return getViewModelItem()->descendantsPassedFilter(filter_generation); } // Passes selection information on to children and record selection @@ -1314,50 +1312,50 @@ bool LLFolderViewFolder::descendantsPassedFilter(S32 filter_generation) BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus) { - BOOL rv = FALSE; - if (selection == this) - { - if (!isSelected()) - { - selectItem(); - } - rv = TRUE; - } - else - { - if (isSelected()) - { - deselectItem(); - } - rv = FALSE; - } - BOOL child_selected = FALSE; - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if((*fit)->setSelection(selection, openitem, take_keyboard_focus)) - { - rv = TRUE; - child_selected = TRUE; - } - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if((*iit)->setSelection(selection, openitem, take_keyboard_focus)) - { - rv = TRUE; - child_selected = TRUE; - } - } - if(openitem && child_selected && !mSingleFolderMode) - { - setOpenArrangeRecursively(TRUE); - } - return rv; + BOOL rv = FALSE; + if (selection == this) + { + if (!isSelected()) + { + selectItem(); + } + rv = TRUE; + } + else + { + if (isSelected()) + { + deselectItem(); + } + rv = FALSE; + } + BOOL child_selected = FALSE; + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if((*fit)->setSelection(selection, openitem, take_keyboard_focus)) + { + rv = TRUE; + child_selected = TRUE; + } + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if((*iit)->setSelection(selection, openitem, take_keyboard_focus)) + { + rv = TRUE; + child_selected = TRUE; + } + } + if(openitem && child_selected && !mSingleFolderMode) + { + setOpenArrangeRecursively(TRUE); + } + return rv; } // This method is used to change the selection of an item. @@ -1366,302 +1364,302 @@ BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem // Returns TRUE if the selection state of this folder, or of a child, was changed. BOOL LLFolderViewFolder::changeSelection(LLFolderViewItem* selection, BOOL selected) { - BOOL rv = FALSE; - if(selection == this) - { - if (isSelected() != selected) - { - rv = TRUE; - if (selected) - { - selectItem(); - } - else - { - deselectItem(); - } - } - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if((*fit)->changeSelection(selection, selected)) - { - rv = TRUE; - } - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if((*iit)->changeSelection(selection, selected)) - { - rv = TRUE; - } - } - return rv; + BOOL rv = FALSE; + if(selection == this) + { + if (isSelected() != selected) + { + rv = TRUE; + if (selected) + { + selectItem(); + } + else + { + deselectItem(); + } + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if((*fit)->changeSelection(selection, selected)) + { + rv = TRUE; + } + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if((*iit)->changeSelection(selection, selected)) + { + rv = TRUE; + } + } + return rv; } LLFolderViewFolder* LLFolderViewFolder::getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse) { - if (!item_a->getParentFolder() || !item_b->getParentFolder()) return NULL; - - std::deque<LLFolderViewFolder*> item_a_ancestors; - - LLFolderViewFolder* parent = item_a->getParentFolder(); - while(parent) - { - item_a_ancestors.push_back(parent); - parent = parent->getParentFolder(); - } - - std::deque<LLFolderViewFolder*> item_b_ancestors; - - parent = item_b->getParentFolder(); - while(parent) - { - item_b_ancestors.push_back(parent); - parent = parent->getParentFolder(); - } - - LLFolderViewFolder* common_ancestor = item_a->getRoot(); - - while(item_a_ancestors.size() > item_b_ancestors.size()) - { - item_a = item_a_ancestors.front(); - item_a_ancestors.pop_front(); - } - - while(item_b_ancestors.size() > item_a_ancestors.size()) - { - item_b = item_b_ancestors.front(); - item_b_ancestors.pop_front(); - } - - while(item_a_ancestors.size()) - { - common_ancestor = item_a_ancestors.front(); - - if (item_a_ancestors.front() == item_b_ancestors.front()) - { - // which came first, sibling a or sibling b? - for (folders_t::iterator it = common_ancestor->mFolders.begin(), end_it = common_ancestor->mFolders.end(); - it != end_it; - ++it) - { - LLFolderViewItem* item = *it; - - if (item == item_a) - { - reverse = false; - return common_ancestor; - } - if (item == item_b) - { - reverse = true; - return common_ancestor; - } - } - - for (items_t::iterator it = common_ancestor->mItems.begin(), end_it = common_ancestor->mItems.end(); - it != end_it; - ++it) - { - LLFolderViewItem* item = *it; - - if (item == item_a) - { - reverse = false; - return common_ancestor; - } - if (item == item_b) - { - reverse = true; - return common_ancestor; - } - } - break; - } - - item_a = item_a_ancestors.front(); - item_a_ancestors.pop_front(); - item_b = item_b_ancestors.front(); - item_b_ancestors.pop_front(); - } - - return NULL; + if (!item_a->getParentFolder() || !item_b->getParentFolder()) return NULL; + + std::deque<LLFolderViewFolder*> item_a_ancestors; + + LLFolderViewFolder* parent = item_a->getParentFolder(); + while(parent) + { + item_a_ancestors.push_back(parent); + parent = parent->getParentFolder(); + } + + std::deque<LLFolderViewFolder*> item_b_ancestors; + + parent = item_b->getParentFolder(); + while(parent) + { + item_b_ancestors.push_back(parent); + parent = parent->getParentFolder(); + } + + LLFolderViewFolder* common_ancestor = item_a->getRoot(); + + while(item_a_ancestors.size() > item_b_ancestors.size()) + { + item_a = item_a_ancestors.front(); + item_a_ancestors.pop_front(); + } + + while(item_b_ancestors.size() > item_a_ancestors.size()) + { + item_b = item_b_ancestors.front(); + item_b_ancestors.pop_front(); + } + + while(item_a_ancestors.size()) + { + common_ancestor = item_a_ancestors.front(); + + if (item_a_ancestors.front() == item_b_ancestors.front()) + { + // which came first, sibling a or sibling b? + for (folders_t::iterator it = common_ancestor->mFolders.begin(), end_it = common_ancestor->mFolders.end(); + it != end_it; + ++it) + { + LLFolderViewItem* item = *it; + + if (item == item_a) + { + reverse = false; + return common_ancestor; + } + if (item == item_b) + { + reverse = true; + return common_ancestor; + } + } + + for (items_t::iterator it = common_ancestor->mItems.begin(), end_it = common_ancestor->mItems.end(); + it != end_it; + ++it) + { + LLFolderViewItem* item = *it; + + if (item == item_a) + { + reverse = false; + return common_ancestor; + } + if (item == item_b) + { + reverse = true; + return common_ancestor; + } + } + break; + } + + item_a = item_a_ancestors.front(); + item_a_ancestors.pop_front(); + item_b = item_b_ancestors.front(); + item_b_ancestors.pop_front(); + } + + return NULL; } void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector<LLFolderViewItem*>& items) { - bool selecting = start == NULL; - if (reverse) - { - for (items_t::reverse_iterator it = mItems.rbegin(), end_it = mItems.rend(); - it != end_it; - ++it) - { - if (*it == end) - { - return; - } - if (selecting && (*it)->getVisible()) - { - items.push_back(*it); - } - - if (*it == start) - { - selecting = true; - } - } - for (folders_t::reverse_iterator it = mFolders.rbegin(), end_it = mFolders.rend(); - it != end_it; - ++it) - { - if (*it == end) - { - return; - } - - if (selecting && (*it)->getVisible()) - { - items.push_back(*it); - } - - if (*it == start) - { - selecting = true; - } - } - } - else - { - for (folders_t::iterator it = mFolders.begin(), end_it = mFolders.end(); - it != end_it; - ++it) - { - if (*it == end) - { - return; - } - - if (selecting && (*it)->getVisible()) - { - items.push_back(*it); - } - - if (*it == start) - { - selecting = true; - } - } - for (items_t::iterator it = mItems.begin(), end_it = mItems.end(); - it != end_it; - ++it) - { - if (*it == end) - { - return; - } - - if (selecting && (*it)->getVisible()) - { - items.push_back(*it); - } - - if (*it == start) - { - selecting = true; - } - } - } + bool selecting = start == NULL; + if (reverse) + { + for (items_t::reverse_iterator it = mItems.rbegin(), end_it = mItems.rend(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + if (selecting && (*it)->getVisible()) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + for (folders_t::reverse_iterator it = mFolders.rbegin(), end_it = mFolders.rend(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting && (*it)->getVisible()) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + } + else + { + for (folders_t::iterator it = mFolders.begin(), end_it = mFolders.end(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting && (*it)->getVisible()) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + for (items_t::iterator it = mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + if (*it == end) + { + return; + } + + if (selecting && (*it)->getVisible()) + { + items.push_back(*it); + } + + if (*it == start) + { + selecting = true; + } + } + } } void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection) { - if (getRoot()->getAllowMultiSelect() == FALSE) return; - - LLFolderViewItem* cur_selected_item = getRoot()->getCurSelectedItem(); - if (cur_selected_item == NULL) - { - cur_selected_item = new_selection; - } - - - bool reverse = false; - LLFolderViewFolder* common_ancestor = getCommonAncestor(cur_selected_item, new_selection, reverse); - if (!common_ancestor) return; - - LLFolderViewItem* last_selected_item_from_cur = cur_selected_item; - LLFolderViewFolder* cur_folder = cur_selected_item->getParentFolder(); - - std::vector<LLFolderViewItem*> items_to_select_forward; - - while(cur_folder != common_ancestor) - { - cur_folder->gatherChildRangeExclusive(last_selected_item_from_cur, NULL, reverse, items_to_select_forward); - - last_selected_item_from_cur = cur_folder; - cur_folder = cur_folder->getParentFolder(); - } - - std::vector<LLFolderViewItem*> items_to_select_reverse; - - LLFolderViewItem* last_selected_item_from_new = new_selection; - cur_folder = new_selection->getParentFolder(); - while(cur_folder != common_ancestor) - { - cur_folder->gatherChildRangeExclusive(last_selected_item_from_new, NULL, !reverse, items_to_select_reverse); - - last_selected_item_from_new = cur_folder; - cur_folder = cur_folder->getParentFolder(); - } - - common_ancestor->gatherChildRangeExclusive(last_selected_item_from_cur, last_selected_item_from_new, reverse, items_to_select_forward); - - for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_reverse.rbegin(), end_it = items_to_select_reverse.rend(); - it != end_it; - ++it) - { - items_to_select_forward.push_back(*it); - } - - LLFolderView* root = getRoot(); - - BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected - - // array always go from 'will be selected' to ' will be unselected', iterate - // in opposite direction to simplify identification of 'point of origin' in - // case it is in the list we are working with - for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend(); - it != end_it; - ++it) - { - LLFolderViewItem* item = *it; - BOOL selected = item->isSelected(); - if (!selection_reverse && selected) - { - // it is our 'point of origin' where we shift/expand from - // don't deselect it - selection_reverse = TRUE; - } - else - { - root->changeSelection(item, !selected); - } - } - - if (selection_reverse) - { - // at some point we reversed selection, first element should be deselected - root->changeSelection(last_selected_item_from_cur, FALSE); - } - - // element we expand to should always be selected - root->changeSelection(new_selection, TRUE); + if (getRoot()->getAllowMultiSelect() == FALSE) return; + + LLFolderViewItem* cur_selected_item = getRoot()->getCurSelectedItem(); + if (cur_selected_item == NULL) + { + cur_selected_item = new_selection; + } + + + bool reverse = false; + LLFolderViewFolder* common_ancestor = getCommonAncestor(cur_selected_item, new_selection, reverse); + if (!common_ancestor) return; + + LLFolderViewItem* last_selected_item_from_cur = cur_selected_item; + LLFolderViewFolder* cur_folder = cur_selected_item->getParentFolder(); + + std::vector<LLFolderViewItem*> items_to_select_forward; + + while(cur_folder != common_ancestor) + { + cur_folder->gatherChildRangeExclusive(last_selected_item_from_cur, NULL, reverse, items_to_select_forward); + + last_selected_item_from_cur = cur_folder; + cur_folder = cur_folder->getParentFolder(); + } + + std::vector<LLFolderViewItem*> items_to_select_reverse; + + LLFolderViewItem* last_selected_item_from_new = new_selection; + cur_folder = new_selection->getParentFolder(); + while(cur_folder != common_ancestor) + { + cur_folder->gatherChildRangeExclusive(last_selected_item_from_new, NULL, !reverse, items_to_select_reverse); + + last_selected_item_from_new = cur_folder; + cur_folder = cur_folder->getParentFolder(); + } + + common_ancestor->gatherChildRangeExclusive(last_selected_item_from_cur, last_selected_item_from_new, reverse, items_to_select_forward); + + for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_reverse.rbegin(), end_it = items_to_select_reverse.rend(); + it != end_it; + ++it) + { + items_to_select_forward.push_back(*it); + } + + LLFolderView* root = getRoot(); + + BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected + + // array always go from 'will be selected' to ' will be unselected', iterate + // in opposite direction to simplify identification of 'point of origin' in + // case it is in the list we are working with + for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend(); + it != end_it; + ++it) + { + LLFolderViewItem* item = *it; + BOOL selected = item->isSelected(); + if (!selection_reverse && selected) + { + // it is our 'point of origin' where we shift/expand from + // don't deselect it + selection_reverse = TRUE; + } + else + { + root->changeSelection(item, !selected); + } + } + + if (selection_reverse) + { + // at some point we reversed selection, first element should be deselected + root->changeSelection(last_selected_item_from_cur, FALSE); + } + + // element we expand to should always be selected + root->changeSelection(new_selection, TRUE); } @@ -1669,113 +1667,113 @@ void LLFolderViewFolder::destroyView() { while (!mItems.empty()) { - LLFolderViewItem *itemp = mItems.back(); + LLFolderViewItem *itemp = mItems.back(); mItems.pop_back(); - itemp->destroyView(); // LLFolderViewItem::destroyView() removes entry from mItems + itemp->destroyView(); // LLFolderViewItem::destroyView() removes entry from mItems } - while (!mFolders.empty()) - { - LLFolderViewFolder *folderp = mFolders.back(); + while (!mFolders.empty()) + { + LLFolderViewFolder *folderp = mFolders.back(); mFolders.pop_back(); - folderp->destroyView(); // LLFolderVievFolder::destroyView() removes entry from mFolders - } + folderp->destroyView(); // LLFolderVievFolder::destroyView() removes entry from mFolders + } - LLFolderViewItem::destroyView(); + LLFolderViewItem::destroyView(); } // extractItem() removes the specified item from the folder, but // doesn't delete it. void LLFolderViewFolder::extractItem( LLFolderViewItem* item, bool deparent_model ) { - if (item->isSelected()) - getRoot()->clearSelection(); - items_t::iterator it = std::find(mItems.begin(), mItems.end(), item); - if(it == mItems.end()) - { - // This is an evil downcast. However, it's only doing - // pointer comparison to find if (which it should be ) the - // item is in the container, so it's pretty safe. - LLFolderViewFolder* f = static_cast<LLFolderViewFolder*>(item); - folders_t::iterator ft; - ft = std::find(mFolders.begin(), mFolders.end(), f); - if (ft != mFolders.end()) - { - mFolders.erase(ft); - } - } - else - { - mItems.erase(it); - } - //item has been removed, need to update filter + if (item->isSelected()) + getRoot()->clearSelection(); + items_t::iterator it = std::find(mItems.begin(), mItems.end(), item); + if(it == mItems.end()) + { + // This is an evil downcast. However, it's only doing + // pointer comparison to find if (which it should be ) the + // item is in the container, so it's pretty safe. + LLFolderViewFolder* f = static_cast<LLFolderViewFolder*>(item); + folders_t::iterator ft; + ft = std::find(mFolders.begin(), mFolders.end(), f); + if (ft != mFolders.end()) + { + mFolders.erase(ft); + } + } + else + { + mItems.erase(it); + } + //item has been removed, need to update filter if (deparent_model) { // in some cases model does not belong to parent view, is shared between views getViewModelItem()->removeChild(item->getViewModelItem()); } - //because an item is going away regardless of filter status, force rearrange - requestArrange(); - removeChild(item); + //because an item is going away regardless of filter status, force rearrange + requestArrange(); + removeChild(item); } BOOL LLFolderViewFolder::isMovable() { - if( !(getViewModelItem()->isItemMovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isMovable()) - { - return FALSE; - } - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isMovable()) - { - return FALSE; - } - } - return TRUE; + if( !(getViewModelItem()->isItemMovable()) ) + { + return FALSE; + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if(!(*iit)->isMovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isMovable()) + { + return FALSE; + } + } + return TRUE; } BOOL LLFolderViewFolder::isRemovable() { - if( !(getViewModelItem()->isItemRemovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isRemovable()) - { - return FALSE; - } - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isRemovable()) - { - return FALSE; - } - } - return TRUE; + if( !(getViewModelItem()->isItemRemovable()) ) + { + return FALSE; + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if(!(*iit)->isRemovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isRemovable()) + { + return FALSE; + } + } + return TRUE; } void LLFolderViewFolder::destroyRoot() @@ -1783,54 +1781,54 @@ void LLFolderViewFolder::destroyRoot() delete this; } -// this is an internal method used for adding items to folders. +// this is an internal method used for adding items to folders. void LLFolderViewFolder::addItem(LLFolderViewItem* item) { - if (item->getParentFolder()) - { - item->getParentFolder()->extractItem(item); - } - item->setParentFolder(this); - - mItems.push_back(item); - - item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); - item->setVisible(FALSE); - - addChild(item); - - // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it - // Note: this happens when models are created before views or shared between views - if (!item->getViewModelItem()->hasParent()) - { - getViewModelItem()->addChild(item->getViewModelItem()); - } -} - -// this is an internal method used for adding items to folders. + if (item->getParentFolder()) + { + item->getParentFolder()->extractItem(item); + } + item->setParentFolder(this); + + mItems.push_back(item); + + item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); + item->setVisible(FALSE); + + addChild(item); + + // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it + // Note: this happens when models are created before views or shared between views + if (!item->getViewModelItem()->hasParent()) + { + getViewModelItem()->addChild(item->getViewModelItem()); + } +} + +// this is an internal method used for adding items to folders. void LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) { - if (folder->mParentFolder) - { - folder->mParentFolder->extractItem(folder); - } - folder->mParentFolder = this; - mFolders.push_back(folder); - folder->setOrigin(0, 0); - folder->reshape(getRect().getWidth(), 0); - folder->setVisible(FALSE); - // rearrange all descendants too, as our indentation level might have changed - //folder->requestArrange(); - //requestSort(); - - addChild(folder); - - // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it - // Note: this happens when models are created before views or shared between views - if (!folder->getViewModelItem()->hasParent()) - { - getViewModelItem()->addChild(folder->getViewModelItem()); - } + if (folder->mParentFolder) + { + folder->mParentFolder->extractItem(folder); + } + folder->mParentFolder = this; + mFolders.push_back(folder); + folder->setOrigin(0, 0); + folder->reshape(getRect().getWidth(), 0); + folder->setVisible(FALSE); + // rearrange all descendants too, as our indentation level might have changed + //folder->requestArrange(); + //requestSort(); + + addChild(folder); + + // When the model is already hooked into a hierarchy (i.e. has a parent), do not reparent it + // Note: this happens when models are created before views or shared between views + if (!folder->getViewModelItem()->hasParent()) + { + getViewModelItem()->addChild(folder->getViewModelItem()); + } } void LLFolderViewFolder::requestArrange() @@ -1845,7 +1843,7 @@ void LLFolderViewFolder::requestArrange() void LLFolderViewFolder::toggleOpen() { - setOpen(!isOpen()); + setOpen(!isOpen()); } // Force a folder open or closed @@ -1868,223 +1866,223 @@ void LLFolderViewFolder::setOpen(BOOL openitem) void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse) { - BOOL was_open = isOpen(); - mIsOpen = openitem; - if(!was_open && openitem) - { - getViewModelItem()->openItem(); - // openItem() will request content, it won't be incomplete - mIsFolderComplete = true; - } - else if(was_open && !openitem) - { - getViewModelItem()->closeItem(); - } - - if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) - { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->setOpenArrangeRecursively(openitem, RECURSE_DOWN); /* Flawfinder: ignore */ - } - } - if (mParentFolder - && (recurse == RECURSE_UP - || recurse == RECURSE_UP_DOWN)) - { - mParentFolder->setOpenArrangeRecursively(openitem, RECURSE_UP); - } - - if (was_open != isOpen()) - { - requestArrange(); - } + BOOL was_open = isOpen(); + mIsOpen = openitem; + if(!was_open && openitem) + { + getViewModelItem()->openItem(); + // openItem() will request content, it won't be incomplete + mIsFolderComplete = true; + } + else if(was_open && !openitem) + { + getViewModelItem()->closeItem(); + } + + if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) + { + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setOpenArrangeRecursively(openitem, RECURSE_DOWN); /* Flawfinder: ignore */ + } + } + if (mParentFolder + && (recurse == RECURSE_UP + || recurse == RECURSE_UP_DOWN)) + { + mParentFolder->setOpenArrangeRecursively(openitem, RECURSE_UP); + } + + if (was_open != isOpen()) + { + requestArrange(); + } } BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, - BOOL drop, - EDragAndDropType c_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - BOOL accepted = mViewModelItem->dragOrDrop(mask,drop,c_type,cargo_data, tooltip_msg); - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } + BOOL drop, + EDragAndDropType c_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL accepted = mViewModelItem->dragOrDrop(mask,drop,c_type,cargo_data, tooltip_msg); + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } - // drag and drop to child item, so clear pending auto-opens - getRoot()->autoOpenTest(NULL); + // drag and drop to child item, so clear pending auto-opens + getRoot()->autoOpenTest(NULL); - return TRUE; + return TRUE; } void LLFolderViewFolder::openItem( void ) { - toggleOpen(); + toggleOpen(); } void LLFolderViewFolder::applyFunctorToChildren(LLFolderViewFunctor& functor) { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - functor.doItem((*fit)); - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - functor.doItem((*iit)); - } + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + functor.doItem((*fit)); + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + functor.doItem((*iit)); + } } void LLFolderViewFolder::applyFunctorRecursively(LLFolderViewFunctor& functor) { - functor.doFolder(this); + functor.doFolder(this); - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->applyFunctorRecursively(functor); - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - functor.doItem((*iit)); - } + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->applyFunctorRecursively(functor); + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + functor.doItem((*iit)); + } } // LLView functionality BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - BOOL handled = FALSE; + BOOL handled = FALSE; - if (isOpen()) - { - handled = (childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL); - } + if (isOpen()) + { + handled = (childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL); + } - if (!handled) - { - handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + if (!handled) + { + handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewFolder" << LL_ENDL; - } + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewFolder" << LL_ENDL; + } - return TRUE; + return TRUE; } BOOL LLFolderViewFolder::handleDragAndDropToThisFolder(MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { if (!mAllowDrop) { - *accept = ACCEPT_NO; + *accept = ACCEPT_NO; tooltip_msg = LLTrans::getString("TooltipOutboxCannotDropOnRoot"); return TRUE; } - - BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg); - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - - if (!drop && accepted) - { - getRoot()->autoOpenTest(this); - } - - return TRUE; + BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg); + + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + + if (!drop && accepted) + { + getRoot()->autoOpenTest(this); + } + + return TRUE; } BOOL LLFolderViewFolder::handleRightMouseDown( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; + BOOL handled = FALSE; - if( isOpen() ) - { - handled = childrenHandleRightMouseDown( x, y, mask ) != NULL; - } - if (!handled) - { - handled = LLFolderViewItem::handleRightMouseDown( x, y, mask ); - } - return handled; + if( isOpen() ) + { + handled = childrenHandleRightMouseDown( x, y, mask ) != NULL; + } + if (!handled) + { + handled = LLFolderViewItem::handleRightMouseDown( x, y, mask ); + } + return handled; } BOOL LLFolderViewFolder::handleHover(S32 x, S32 y, MASK mask) { - mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); + mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight)); - BOOL handled = LLView::handleHover(x, y, mask); + BOOL handled = LLView::handleHover(x, y, mask); - if (!handled) - { - // this doesn't do child processing - handled = LLFolderViewItem::handleHover(x, y, mask); - } + if (!handled) + { + // this doesn't do child processing + handled = LLFolderViewItem::handleHover(x, y, mask); + } - return handled; + return handled; } BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; - if( isOpen() ) - { - handled = childrenHandleMouseDown(x,y,mask) != NULL; - } - if( !handled ) - { - if((mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad) + BOOL handled = FALSE; + if( isOpen() ) + { + handled = childrenHandleMouseDown(x,y,mask) != NULL; + } + if( !handled ) + { + if((mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad) && !mSingleFolderMode) - { - toggleOpen(); - handled = TRUE; - } - else - { - // do normal selection logic - handled = LLFolderViewItem::handleMouseDown(x, y, mask); - } - } + { + toggleOpen(); + handled = TRUE; + } + else + { + // do normal selection logic + handled = LLFolderViewItem::handleMouseDown(x, y, mask); + } + } - return handled; + return handled; } BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; + BOOL handled = FALSE; if(mSingleFolderMode) { static LLUICachedControl<bool> double_click_new_window("SingleModeDoubleClickOpenWindow", false); @@ -2104,12 +2102,12 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) return TRUE; } - if( isOpen() ) - { - handled = childrenHandleDoubleClick( x, y, mask ) != NULL; - } - if( !handled ) - { + if( isOpen() ) + { + handled = childrenHandleDoubleClick( x, y, mask ) != NULL; + } + if( !handled ) + { if(mDoubleClickOverride) { static LLUICachedControl<U32> double_click_action("MultiModeDoubleClickFolder", false); @@ -2124,245 +2122,245 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) return TRUE; } } - if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad) - { - // don't select when user double-clicks plus sign - // so as not to contradict single-click behavior - toggleOpen(); - } - else - { - getRoot()->setSelection(this, FALSE); - toggleOpen(); - } - handled = TRUE; - } - return handled; + if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad) + { + // don't select when user double-clicks plus sign + // so as not to contradict single-click behavior + toggleOpen(); + } + else + { + getRoot()->setSelection(this, FALSE); + toggleOpen(); + } + handled = TRUE; + } + return handled; } void LLFolderViewFolder::draw() { - updateLabelRotation(); + updateLabelRotation(); - LLFolderViewItem::draw(); + LLFolderViewItem::draw(); - // draw children if root folder, or any other folder that is open or animating to closed state - if( getRoot() == this || (isOpen() || mCurHeight != mTargetHeight )) - { - LLView::draw(); - } + // draw children if root folder, or any other folder that is open or animating to closed state + if( getRoot() == this || (isOpen() || mCurHeight != mTargetHeight )) + { + LLView::draw(); + } - mExpanderHighlighted = FALSE; + mExpanderHighlighted = FALSE; } // this does prefix traversal, as folders are listed above their contents LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) { - BOOL found_item = FALSE; - - LLFolderViewItem* result = NULL; - // when not starting from a given item, start at beginning - if(item == NULL) - { - found_item = TRUE; - } - - // find current item among children - folders_t::iterator fit = mFolders.begin(); - folders_t::iterator fend = mFolders.end(); - - items_t::iterator iit = mItems.begin(); - items_t::iterator iend = mItems.end(); - - // if not trivially starting at the beginning, we have to find the current item - if (!found_item) - { - // first, look among folders, since they are always above items - for(; fit != fend; ++fit) - { - if(item == (*fit)) - { - found_item = TRUE; - // if we are on downwards traversal - if (include_children && (*fit)->isOpen()) - { - // look for first descendant - return (*fit)->getNextFromChild(NULL, TRUE); - } - // otherwise advance to next folder - ++fit; - include_children = TRUE; - break; - } - } - - // didn't find in folders? Check items... - if (!found_item) - { - for(; iit != iend; ++iit) - { - if(item == (*iit)) - { - found_item = TRUE; - // point to next item - ++iit; - break; - } - } - } - } - - if (!found_item) - { - // you should never call this method with an item that isn't a child - // so we should always find something - llassert(FALSE); - return NULL; - } - - // at this point, either iit or fit point to a candidate "next" item - // if both are out of range, we need to punt up to our parent - - // now, starting from found folder, continue through folders - // searching for next visible folder - while(fit != fend && !(*fit)->getVisible()) - { - // turn on downwards traversal for next folder - ++fit; - } - - if (fit != fend) - { - result = (*fit); - } - else - { - // otherwise, scan for next visible item - while(iit != iend && !(*iit)->getVisible()) - { - ++iit; - } - - // check to see if we have a valid item - if (iit != iend) - { - result = (*iit); - } - } - - if( !result && mParentFolder ) - { - // If there are no siblings or children to go to, recurse up one level in the tree - // and skip children for this folder, as we've already discounted them - result = mParentFolder->getNextFromChild(this, FALSE); - } - - return result; + BOOL found_item = FALSE; + + LLFolderViewItem* result = NULL; + // when not starting from a given item, start at beginning + if(item == NULL) + { + found_item = TRUE; + } + + // find current item among children + folders_t::iterator fit = mFolders.begin(); + folders_t::iterator fend = mFolders.end(); + + items_t::iterator iit = mItems.begin(); + items_t::iterator iend = mItems.end(); + + // if not trivially starting at the beginning, we have to find the current item + if (!found_item) + { + // first, look among folders, since they are always above items + for(; fit != fend; ++fit) + { + if(item == (*fit)) + { + found_item = TRUE; + // if we are on downwards traversal + if (include_children && (*fit)->isOpen()) + { + // look for first descendant + return (*fit)->getNextFromChild(NULL, TRUE); + } + // otherwise advance to next folder + ++fit; + include_children = TRUE; + break; + } + } + + // didn't find in folders? Check items... + if (!found_item) + { + for(; iit != iend; ++iit) + { + if(item == (*iit)) + { + found_item = TRUE; + // point to next item + ++iit; + break; + } + } + } + } + + if (!found_item) + { + // you should never call this method with an item that isn't a child + // so we should always find something + llassert(FALSE); + return NULL; + } + + // at this point, either iit or fit point to a candidate "next" item + // if both are out of range, we need to punt up to our parent + + // now, starting from found folder, continue through folders + // searching for next visible folder + while(fit != fend && !(*fit)->getVisible()) + { + // turn on downwards traversal for next folder + ++fit; + } + + if (fit != fend) + { + result = (*fit); + } + else + { + // otherwise, scan for next visible item + while(iit != iend && !(*iit)->getVisible()) + { + ++iit; + } + + // check to see if we have a valid item + if (iit != iend) + { + result = (*iit); + } + } + + if( !result && mParentFolder ) + { + // If there are no siblings or children to go to, recurse up one level in the tree + // and skip children for this folder, as we've already discounted them + result = mParentFolder->getNextFromChild(this, FALSE); + } + + return result; } // this does postfix traversal, as folders are listed above their contents LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* item, BOOL include_children ) { - BOOL found_item = FALSE; - - LLFolderViewItem* result = NULL; - // when not starting from a given item, start at end - if(item == NULL) - { - found_item = TRUE; - } - - // find current item among children - folders_t::reverse_iterator fit = mFolders.rbegin(); - folders_t::reverse_iterator fend = mFolders.rend(); - - items_t::reverse_iterator iit = mItems.rbegin(); - items_t::reverse_iterator iend = mItems.rend(); - - // if not trivially starting at the end, we have to find the current item - if (!found_item) - { - // first, look among items, since they are always below the folders - for(; iit != iend; ++iit) - { - if(item == (*iit)) - { - found_item = TRUE; - // point to next item - ++iit; - break; - } - } - - // didn't find in items? Check folders... - if (!found_item) - { - for(; fit != fend; ++fit) - { - if(item == (*fit)) - { - found_item = TRUE; - // point to next folder - ++fit; - break; - } - } - } - } - - if (!found_item) - { - // you should never call this method with an item that isn't a child - // so we should always find something - llassert(FALSE); - return NULL; - } - - // at this point, either iit or fit point to a candidate "next" item - // if both are out of range, we need to punt up to our parent - - // now, starting from found item, continue through items - // searching for next visible item - while(iit != iend && !(*iit)->getVisible()) - { - ++iit; - } - - if (iit != iend) - { - // we found an appropriate item - result = (*iit); - } - else - { - // otherwise, scan for next visible folder - while(fit != fend && !(*fit)->getVisible()) - { - ++fit; - } - - // check to see if we have a valid folder - if (fit != fend) - { - // try selecting child element of this folder - if ((*fit)->isOpen() && include_children) - { - result = (*fit)->getPreviousFromChild(NULL); - } - else - { - result = (*fit); - } - } - } - - if( !result ) - { - // If there are no siblings or children to go to, recurse up one level in the tree - // which gets back to this folder, which will only be visited if it is a valid, visible item - result = this; - } - - return result; + BOOL found_item = FALSE; + + LLFolderViewItem* result = NULL; + // when not starting from a given item, start at end + if(item == NULL) + { + found_item = TRUE; + } + + // find current item among children + folders_t::reverse_iterator fit = mFolders.rbegin(); + folders_t::reverse_iterator fend = mFolders.rend(); + + items_t::reverse_iterator iit = mItems.rbegin(); + items_t::reverse_iterator iend = mItems.rend(); + + // if not trivially starting at the end, we have to find the current item + if (!found_item) + { + // first, look among items, since they are always below the folders + for(; iit != iend; ++iit) + { + if(item == (*iit)) + { + found_item = TRUE; + // point to next item + ++iit; + break; + } + } + + // didn't find in items? Check folders... + if (!found_item) + { + for(; fit != fend; ++fit) + { + if(item == (*fit)) + { + found_item = TRUE; + // point to next folder + ++fit; + break; + } + } + } + } + + if (!found_item) + { + // you should never call this method with an item that isn't a child + // so we should always find something + llassert(FALSE); + return NULL; + } + + // at this point, either iit or fit point to a candidate "next" item + // if both are out of range, we need to punt up to our parent + + // now, starting from found item, continue through items + // searching for next visible item + while(iit != iend && !(*iit)->getVisible()) + { + ++iit; + } + + if (iit != iend) + { + // we found an appropriate item + result = (*iit); + } + else + { + // otherwise, scan for next visible folder + while(fit != fend && !(*fit)->getVisible()) + { + ++fit; + } + + // check to see if we have a valid folder + if (fit != fend) + { + // try selecting child element of this folder + if ((*fit)->isOpen() && include_children) + { + result = (*fit)->getPreviousFromChild(NULL); + } + else + { + result = (*fit); + } + } + } + + if( !result ) + { + // If there are no siblings or children to go to, recurse up one level in the tree + // which gets back to this folder, which will only be visited if it is a valid, visible item + result = this; + } + + return result; } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 5c2a1ecff0..351613e387 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -1,25 +1,25 @@ -/** +/** * @file llfolderviewitem.h * @brief Items and folders that can appear in a hierarchical folder view * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,24 +47,24 @@ class LLFolderViewModelInterface; class LLFolderViewItem : public LLView { public: - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Optional<LLUIImage*> folder_arrow_image, - selection_image; - Mandatory<LLFolderView*> root; - Mandatory<LLFolderViewModelItem*> listener; - - Optional<S32> folder_indentation, // pixels - item_height, - item_top_pad; - - Optional<time_t> creation_date; - Optional<bool> allow_wear; - Optional<bool> allow_drop; - - Optional<LLUIColor> font_color; - Optional<LLUIColor> font_highlight_color; - + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Optional<LLUIImage*> folder_arrow_image, + selection_image; + Mandatory<LLFolderView*> root; + Mandatory<LLFolderViewModelItem*> listener; + + Optional<S32> folder_indentation, // pixels + item_height, + item_top_pad; + + Optional<time_t> creation_date; + Optional<bool> allow_wear; + Optional<bool> allow_drop; + + Optional<LLUIColor> font_color; + Optional<LLUIColor> font_highlight_color; + Optional<S32> left_pad, icon_pad, icon_width, @@ -74,38 +74,38 @@ public: max_folder_item_overlap; Optional<bool> single_folder_mode, double_click_override; - Params(); - }; + Params(); + }; - static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4; - // animation parameters - static const F32 FOLDER_CLOSE_TIME_CONSTANT, - FOLDER_OPEN_TIME_CONSTANT; + static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4; + // animation parameters + static const F32 FOLDER_CLOSE_TIME_CONSTANT, + FOLDER_OPEN_TIME_CONSTANT; protected: - friend class LLUICtrlFactory; - friend class LLFolderViewModelItem; + friend class LLUICtrlFactory; + friend class LLFolderViewModelItem; - LLFolderViewItem(const Params& p); + LLFolderViewItem(const Params& p); - std::string mLabel; - S32 mLabelWidth; - bool mLabelWidthDirty; + std::string mLabel; + S32 mLabelWidth; + bool mLabelWidthDirty; S32 mLabelPaddingRight; - LLFolderViewFolder* mParentFolder; - LLPointer<LLFolderViewModelItem> mViewModelItem; - LLFontGL::StyleFlags mLabelStyle; - std::string mLabelSuffix; - bool mSuffixNeedsRefresh; //suffix and icons - LLUIImagePtr mIcon, - mIconOpen, - mIconOverlay; + LLFolderViewFolder* mParentFolder; + LLPointer<LLFolderViewModelItem> mViewModelItem; + LLFontGL::StyleFlags mLabelStyle; + std::string mLabelSuffix; + bool mSuffixNeedsRefresh; //suffix and icons + LLUIImagePtr mIcon, + mIconOpen, + mIconOverlay; S32 mLocalIndentation; - S32 mIndentation; - S32 mItemHeight; - S32 mDragStartX, - mDragStartY; + S32 mIndentation; + S32 mItemHeight; + S32 mDragStartX, + mDragStartY; S32 mLeftPad, mIconPad, @@ -115,163 +115,163 @@ protected: mArrowSize, mMaxFolderItemOverlap; - F32 mControlLabelRotation; - LLFolderView* mRoot; - bool mHasVisibleChildren, - mIsCurSelection, - mDragAndDropTarget, - mIsMouseOverTitle, - mAllowWear, + F32 mControlLabelRotation; + LLFolderView* mRoot; + bool mHasVisibleChildren, + mIsCurSelection, + mDragAndDropTarget, + mIsMouseOverTitle, + mAllowWear, mAllowDrop, mSingleFolderMode, mDoubleClickOverride, - mSelectPending, - mIsItemCut; - - S32 mCutGeneration; - - LLUIColor mFontColor; - LLUIColor mFontHighlightColor; - - // For now assuming all colors are the same in derived classes. - static bool sColorSetInitialized; - static LLUIColor sFgColor; - static LLUIColor sFgDisabledColor; - static LLUIColor sHighlightBgColor; - static LLUIColor sFlashBgColor; - static LLUIColor sFocusOutlineColor; - static LLUIColor sMouseOverColor; - static LLUIColor sFilterBGColor; - static LLUIColor sFilterTextColor; - static LLUIColor sSuffixColor; - static LLUIColor sSearchStatusColor; - - // this is an internal method used for adding items to folders. A - // no-op at this level, but reimplemented in derived classes. - virtual void addItem(LLFolderViewItem*) { } - virtual void addFolder(LLFolderViewFolder*) { } - virtual bool isHighlightAllowed(); - virtual bool isHighlightActive(); - virtual bool isFadeItem(); - virtual bool isFlashing() { return false; } - virtual void setFlashState(bool) { } - - static LLFontGL* getLabelFontForStyle(U8 style); - - BOOL mIsSelected; + mSelectPending, + mIsItemCut; + + S32 mCutGeneration; + + LLUIColor mFontColor; + LLUIColor mFontHighlightColor; + + // For now assuming all colors are the same in derived classes. + static bool sColorSetInitialized; + static LLUIColor sFgColor; + static LLUIColor sFgDisabledColor; + static LLUIColor sHighlightBgColor; + static LLUIColor sFlashBgColor; + static LLUIColor sFocusOutlineColor; + static LLUIColor sMouseOverColor; + static LLUIColor sFilterBGColor; + static LLUIColor sFilterTextColor; + static LLUIColor sSuffixColor; + static LLUIColor sSearchStatusColor; + + // this is an internal method used for adding items to folders. A + // no-op at this level, but reimplemented in derived classes. + virtual void addItem(LLFolderViewItem*) { } + virtual void addFolder(LLFolderViewFolder*) { } + virtual bool isHighlightAllowed(); + virtual bool isHighlightActive(); + virtual bool isFadeItem(); + virtual bool isFlashing() { return false; } + virtual void setFlashState(bool) { } + + static LLFontGL* getLabelFontForStyle(U8 style); + + BOOL mIsSelected; public: - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); - BOOL postBuild(); + BOOL postBuild(); - virtual void openItem( void ); + virtual void openItem( void ); - void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus); + void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus); - virtual ~LLFolderViewItem( void ); + virtual ~LLFolderViewItem( void ); - // addToFolder() returns TRUE if it succeeds. FALSE otherwise - virtual void addToFolder(LLFolderViewFolder* folder); + // addToFolder() returns TRUE if it succeeds. FALSE otherwise + virtual void addToFolder(LLFolderViewFolder* folder); - // Finds width and height of this object and it's children. Also - // makes sure that this view and it's children are the right size. - virtual S32 arrange( S32* width, S32* height ); - virtual S32 getItemHeight() const; + // Finds width and height of this object and it's children. Also + // makes sure that this view and it's children are the right size. + virtual S32 arrange( S32* width, S32* height ); + virtual S32 getItemHeight() const; virtual S32 getLabelXPos(); S32 getIconPad(); S32 getTextPad(); - // If 'selection' is 'this' then note that otherwise ignore. - // Returns TRUE if this item ends up being selected. - virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus); + // If 'selection' is 'this' then note that otherwise ignore. + // Returns TRUE if this item ends up being selected. + virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus); - // This method is used to set the selection state of an item. - // If 'selection' is 'this' then note selection. - // Returns TRUE if the selection state of this item was changed. - virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); + // This method is used to set the selection state of an item. + // If 'selection' is 'this' then note selection. + // Returns TRUE if the selection state of this item was changed. + virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - // this method is used to deselect this element - void deselectItem(); + // this method is used to deselect this element + void deselectItem(); - // this method is used to select this element - virtual void selectItem(); + // this method is used to select this element + virtual void selectItem(); - // gets multiple-element selection - virtual std::set<LLFolderViewItem*> getSelectionList() const; + // gets multiple-element selection + virtual std::set<LLFolderViewItem*> getSelectionList() const; - // Returns true is this object and all of its children can be removed (deleted by user) - virtual BOOL isRemovable(); + // Returns true is this object and all of its children can be removed (deleted by user) + virtual BOOL isRemovable(); - // Returns true is this object and all of its children can be moved - virtual BOOL isMovable(); + // Returns true is this object and all of its children can be moved + virtual BOOL isMovable(); - // destroys this item recursively - virtual void destroyView(); + // destroys this item recursively + virtual void destroyView(); - BOOL isSelected() const { return mIsSelected; } - bool isInSelection() const; + BOOL isSelected() const { return mIsSelected; } + bool isInSelection() const; - void setUnselected() { mIsSelected = FALSE; } + void setUnselected() { mIsSelected = FALSE; } - void setIsCurSelection(BOOL select) { mIsCurSelection = select; } + void setIsCurSelection(BOOL select) { mIsCurSelection = select; } - BOOL getIsCurSelection() const { return mIsCurSelection; } + BOOL getIsCurSelection() const { return mIsCurSelection; } - BOOL hasVisibleChildren() const { return mHasVisibleChildren; } + BOOL hasVisibleChildren() const { return mHasVisibleChildren; } - // true if object can't have children - virtual bool isFolderComplete() { return true; } + // true if object can't have children + virtual bool isFolderComplete() { return true; } // true if object can't have children virtual bool areChildrenInited() { return true; } virtual void setChildrenInited(bool inited) { } - // Call through to the viewed object and return true if it can be - // removed. Returns true if it's removed. - //virtual BOOL removeRecursively(BOOL single_item); - BOOL remove(); + // Call through to the viewed object and return true if it can be + // removed. Returns true if it's removed. + //virtual BOOL removeRecursively(BOOL single_item); + BOOL remove(); - // Build an appropriate context menu for the item. Flags unused. - void buildContextMenu(class LLMenuGL& menu, U32 flags); + // Build an appropriate context menu for the item. Flags unused. + void buildContextMenu(class LLMenuGL& menu, U32 flags); - // This method returns the actual name of the thing being - // viewed. This method will ask the viewed object itself. - const std::string& getName( void ) const; + // This method returns the actual name of the thing being + // viewed. This method will ask the viewed object itself. + const std::string& getName( void ) const; - // This method returns the label displayed on the view. This - // method was primarily added to allow sorting on the folder - // contents possible before the entire view has been constructed. - const std::string& getLabel() const { return mLabel; } + // This method returns the label displayed on the view. This + // method was primarily added to allow sorting on the folder + // contents possible before the entire view has been constructed. + const std::string& getLabel() const { return mLabel; } - LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; } - const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; } + LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; } + const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; } - void setParentFolder(LLFolderViewFolder* parent) { mParentFolder = parent; } + void setParentFolder(LLFolderViewFolder* parent) { mParentFolder = parent; } - LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE ); - LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE ); + LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE ); + LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE ); - const LLFolderViewModelItem* getViewModelItem( void ) const { return mViewModelItem; } - LLFolderViewModelItem* getViewModelItem( void ) { return mViewModelItem; } + const LLFolderViewModelItem* getViewModelItem( void ) const { return mViewModelItem; } + LLFolderViewModelItem* getViewModelItem( void ) { return mViewModelItem; } - const LLFolderViewModelInterface* getFolderViewModel( void ) const; - LLFolderViewModelInterface* getFolderViewModel( void ); + const LLFolderViewModelInterface* getFolderViewModel( void ) const; + LLFolderViewModelInterface* getFolderViewModel( void ); - // just rename the object. - void rename(const std::string& new_name); + // just rename the object. + void rename(const std::string& new_name); - // Show children - virtual void setOpen(BOOL open = TRUE) {}; - virtual BOOL isOpen() const { return FALSE; } + // Show children + virtual void setOpen(BOOL open = TRUE) {}; + virtual BOOL isOpen() const { return FALSE; } - virtual LLFolderView* getRoot(); - virtual const LLFolderView* getRoot() const; - BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); - S32 getIndentation() const { return mIndentation; } + virtual LLFolderView* getRoot(); + virtual const LLFolderView* getRoot() const; + BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); + S32 getIndentation() const { return mIndentation; } - virtual BOOL passedFilter(S32 filter_generation = -1); - virtual BOOL isPotentiallyVisible(S32 filter_generation = -1); + virtual BOOL passedFilter(S32 filter_generation = -1); + virtual BOOL isPotentiallyVisible(S32 filter_generation = -1); // refresh information from the object being viewed. // refreshes label, suffixes and sets icons. Expensive! @@ -279,34 +279,34 @@ public: virtual void refresh(); // refreshes suffixes and sets icons. Expensive! // Does not need filter update - virtual void refreshSuffix(); + virtual void refreshSuffix(); bool isSingleFolderMode() { return mSingleFolderMode; } - // LLView functionality - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); - //virtual LLView* findChildView(const std::string& name, BOOL recurse) const { return LLView::findChildView(name, recurse); } + //virtual LLView* findChildView(const std::string& name, BOOL recurse) const { return LLView::findChildView(name, recurse); } - // virtual void handleDropped(); - virtual void draw(); - void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color); + // virtual void handleDropped(); + virtual void draw(); + void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color); void drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor); void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); private: - static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts + static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -320,79 +320,79 @@ private: class LLFolderViewFolder : public LLFolderViewItem { protected: - LLFolderViewFolder( const LLFolderViewItem::Params& ); - friend class LLUICtrlFactory; + LLFolderViewFolder( const LLFolderViewItem::Params& ); + friend class LLUICtrlFactory; - void updateLabelRotation(); - virtual bool isCollapsed() { return FALSE; } + void updateLabelRotation(); + virtual bool isCollapsed() { return FALSE; } public: - typedef std::list<LLFolderViewItem*> items_t; - typedef std::list<LLFolderViewFolder*> folders_t; + typedef std::list<LLFolderViewItem*> items_t; + typedef std::list<LLFolderViewFolder*> folders_t; protected: - items_t mItems; - folders_t mFolders; - - BOOL mIsOpen; - BOOL mExpanderHighlighted; - F32 mCurHeight; - F32 mTargetHeight; - F32 mAutoOpenCountdown; - S32 mLastArrangeGeneration; - S32 mLastCalculatedWidth; - bool mIsFolderComplete; // indicates that some children were not loaded/added yet - bool mAreChildrenInited; // indicates that no children were initialized + items_t mItems; + folders_t mFolders; + + BOOL mIsOpen; + BOOL mExpanderHighlighted; + F32 mCurHeight; + F32 mTargetHeight; + F32 mAutoOpenCountdown; + S32 mLastArrangeGeneration; + S32 mLastCalculatedWidth; + bool mIsFolderComplete; // indicates that some children were not loaded/added yet + bool mAreChildrenInited; // indicates that no children were initialized public: - typedef enum e_recurse_type - { - RECURSE_NO, - RECURSE_UP, - RECURSE_DOWN, - RECURSE_UP_DOWN - } ERecurseType; + typedef enum e_recurse_type + { + RECURSE_NO, + RECURSE_UP, + RECURSE_DOWN, + RECURSE_UP_DOWN + } ERecurseType; - virtual ~LLFolderViewFolder( void ); + virtual ~LLFolderViewFolder( void ); - LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); - LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); + LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); + LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); - // addToFolder() returns TRUE if it succeeds. FALSE otherwise - virtual void addToFolder(LLFolderViewFolder* folder); + // addToFolder() returns TRUE if it succeeds. FALSE otherwise + virtual void addToFolder(LLFolderViewFolder* folder); - // Finds width and height of this object and it's children. Also - // makes sure that this view and it's children are the right size. - virtual S32 arrange( S32* width, S32* height ); + // Finds width and height of this object and it's children. Also + // makes sure that this view and it's children are the right size. + virtual S32 arrange( S32* width, S32* height ); - BOOL needsArrange(); + BOOL needsArrange(); - bool descendantsPassedFilter(S32 filter_generation = -1); + bool descendantsPassedFilter(S32 filter_generation = -1); - // Passes selection information on to children and record - // selection information if necessary. - // Returns TRUE if this object (or a child) ends up being selected. - // If 'openitem' is TRUE then folders are opened up along the way to the selection. - virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus = TRUE); + // Passes selection information on to children and record + // selection information if necessary. + // Returns TRUE if this object (or a child) ends up being selected. + // If 'openitem' is TRUE then folders are opened up along the way to the selection. + virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus = TRUE); - // This method is used to change the selection of an item. - // Recursively traverse all children; if 'selection' is 'this' then change - // the select status if necessary. - // Returns TRUE if the selection state of this folder, or of a child, was changed. - virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); + // This method is used to change the selection of an item. + // Recursively traverse all children; if 'selection' is 'this' then change + // the select status if necessary. + // Returns TRUE if the selection state of this folder, or of a child, was changed. + virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - // this method is used to group select items - void extendSelectionTo(LLFolderViewItem* selection); + // this method is used to group select items + void extendSelectionTo(LLFolderViewItem* selection); - // Returns true is this object and all of its children can be removed. - virtual BOOL isRemovable(); + // Returns true is this object and all of its children can be removed. + virtual BOOL isRemovable(); - // Returns true is this object and all of its children can be moved - virtual BOOL isMovable(); + // Returns true is this object and all of its children can be moved + virtual BOOL isMovable(); - // destroys this folder, and all children - virtual void destroyView(); + // destroys this folder, and all children + virtual void destroyView(); void destroyRoot(); // whether known children are fully loaded (arrange sets to true) @@ -402,89 +402,89 @@ public: virtual bool areChildrenInited() { return mAreChildrenInited; } virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; } - // extractItem() removes the specified item from the folder, but - // doesn't delete it. - virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); - - // This function is called by a child that needs to be resorted. - void resort(LLFolderViewItem* item); - - void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; } - - // folders can be opened. This will usually be called by internal - // methods. - virtual void toggleOpen(); - - // Force a folder open or closed - virtual void setOpen(BOOL openitem = TRUE); - - // Called when a child is refreshed. - virtual void requestArrange(); - - // internal method which doesn't update the entire view. This - // method was written because the list iterators destroy the state - // of other iterations, thus, we can't arrange while iterating - // through the children (such as when setting which is selected. - virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO); - - // Get the current state of the folder. - virtual BOOL isOpen() const { return mIsOpen; } - - // special case if an object is dropped on the child. - BOOL handleDragAndDropFromChild(MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - - // Just apply this functor to the folder's immediate children. - void applyFunctorToChildren(LLFolderViewFunctor& functor); - // apply this functor to the folder's descendants. - void applyFunctorRecursively(LLFolderViewFunctor& functor); - - virtual void openItem( void ); - - // LLView functionality - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - BOOL handleDragAndDropToThisFolder(MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - virtual void draw(); - - folders_t::iterator getFoldersBegin() { return mFolders.begin(); } - folders_t::iterator getFoldersEnd() { return mFolders.end(); } - folders_t::size_type getFoldersCount() const { return mFolders.size(); } - - items_t::const_iterator getItemsBegin() const { return mItems.begin(); } - items_t::const_iterator getItemsEnd() const { return mItems.end(); } - items_t::size_type getItemsCount() const { return mItems.size(); } - - LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse); - void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector<LLFolderViewItem*>& items); - - // internal functions for tracking folders and items separately - // use addToFolder() virtual method to ensure folders are always added to mFolders - // and not mItems - void addItem(LLFolderViewItem* item); - void addFolder( LLFolderViewFolder* folder); - - //WARNING: do not call directly...use the appropriate LLFolderViewModel-derived class instead - template<typename SORT_FUNC> void sortFolders(const SORT_FUNC& func) { mFolders.sort(func); } - template<typename SORT_FUNC> void sortItems(const SORT_FUNC& func) { mItems.sort(func); } + // extractItem() removes the specified item from the folder, but + // doesn't delete it. + virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); + + // This function is called by a child that needs to be resorted. + void resort(LLFolderViewItem* item); + + void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; } + + // folders can be opened. This will usually be called by internal + // methods. + virtual void toggleOpen(); + + // Force a folder open or closed + virtual void setOpen(BOOL openitem = TRUE); + + // Called when a child is refreshed. + virtual void requestArrange(); + + // internal method which doesn't update the entire view. This + // method was written because the list iterators destroy the state + // of other iterations, thus, we can't arrange while iterating + // through the children (such as when setting which is selected. + virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO); + + // Get the current state of the folder. + virtual BOOL isOpen() const { return mIsOpen; } + + // special case if an object is dropped on the child. + BOOL handleDragAndDropFromChild(MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + + // Just apply this functor to the folder's immediate children. + void applyFunctorToChildren(LLFolderViewFunctor& functor); + // apply this functor to the folder's descendants. + void applyFunctorRecursively(LLFolderViewFunctor& functor); + + virtual void openItem( void ); + + // LLView functionality + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + BOOL handleDragAndDropToThisFolder(MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + virtual void draw(); + + folders_t::iterator getFoldersBegin() { return mFolders.begin(); } + folders_t::iterator getFoldersEnd() { return mFolders.end(); } + folders_t::size_type getFoldersCount() const { return mFolders.size(); } + + items_t::const_iterator getItemsBegin() const { return mItems.begin(); } + items_t::const_iterator getItemsEnd() const { return mItems.end(); } + items_t::size_type getItemsCount() const { return mItems.size(); } + + LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse); + void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector<LLFolderViewItem*>& items); + + // internal functions for tracking folders and items separately + // use addToFolder() virtual method to ensure folders are always added to mFolders + // and not mItems + void addItem(LLFolderViewItem* item); + void addFolder( LLFolderViewFolder* folder); + + //WARNING: do not call directly...use the appropriate LLFolderViewModel-derived class instead + template<typename SORT_FUNC> void sortFolders(const SORT_FUNC& func) { mFolders.sort(func); } + template<typename SORT_FUNC> void sortItems(const SORT_FUNC& func) { mItems.sort(func); } }; typedef std::deque<LLFolderViewItem*> folder_view_item_deque; diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index f217b743a0..d9e6567cd6 100644 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfolderviewmodel.cpp * @brief Implementation of the view model collection of classes. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,39 +31,39 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item) { - return item->getSortVersion() < mTargetSortVersion; + return item->getSortVersion() < mTargetSortVersion; } std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder) { - if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration()) - { - return LLTrans::getString("Searching"); - } - else - { - return getFilter().getEmptyLookupMessage(is_empty_folder); - } + if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration()) + { + return LLTrans::getString("Searching"); + } + else + { + return getFilter().getEmptyLookupMessage(is_empty_folder); + } } void LLFolderViewModelCommon::filter() { - static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - getFilter().resetTime(llclamp(max_time(), 1, 100)); + const S32 MAX_FILTER_TIME = 10; + getFilter().resetTime(MAX_FILTER_TIME); mFolderView->getViewModelItem()->filter(getFilter()); } bool LLFolderViewModelItemCommon::hasFilterStringMatch() { - return mStringMatchOffsetFilter != std::string::npos; + return mStringMatchOffsetFilter != std::string::npos; } std::string::size_type LLFolderViewModelItemCommon::getFilterStringOffset() { - return mStringMatchOffsetFilter; + return mStringMatchOffsetFilter; } std::string::size_type LLFolderViewModelItemCommon::getFilterStringSize() { - return mRootViewModel.getFilter().getFilterStringSize(); + return mRootViewModel.getFilter().getFilterStringSize(); } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 551a60e097..f02c1e3883 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -1,41 +1,41 @@ -/** +/** * @file llfolderviewmodel.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLFOLDERVIEWMODEL_H #define LLFOLDERVIEWMODEL_H -#include "llfontgl.h" // just for StyleFlags enum +#include "llfontgl.h" // just for StyleFlags enum #include "llfolderview.h" // These are grouping of inventory types. // Order matters when sorting system folders to the top. enum EInventorySortGroup { - SG_SYSTEM_FOLDER, - SG_TRASH_FOLDER, - SG_NORMAL_FOLDER, - SG_ITEM + SG_SYSTEM_FOLDER, + SG_TRASH_FOLDER, + SG_NORMAL_FOLDER, + SG_ITEM }; class LLFontGL; @@ -49,85 +49,85 @@ class LLFolderViewFolder; class LLFolderViewFilter { public: - enum EFilterModified - { - FILTER_NONE, // nothing to do, already filtered - FILTER_RESTART, // restart filtering from scratch - FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter - FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one - }; + enum EFilterModified + { + FILTER_NONE, // nothing to do, already filtered + FILTER_RESTART, // restart filtering from scratch + FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter + FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one + }; public: - LLFolderViewFilter() {} - virtual ~LLFolderViewFilter() {} - - // +-------------------------------------------------------------------+ - // + Execution And Results - // +-------------------------------------------------------------------+ - virtual bool check(const LLFolderViewModelItem* item) = 0; - virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0; - - virtual void setEmptyLookupMessage(const std::string& message) = 0; - virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0; - - virtual bool showAllResults() const = 0; - - virtual std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const = 0; - virtual std::string::size_type getFilterStringSize() const = 0; - // +-------------------------------------------------------------------+ - // + Status - // +-------------------------------------------------------------------+ - virtual bool isActive() const = 0; - virtual bool isModified() const = 0; - virtual void clearModified() = 0; - virtual const std::string& getName() const = 0; - virtual const std::string& getFilterText() = 0; - //RN: this is public to allow system to externally force a global refilter - virtual void setModified(EFilterModified behavior = FILTER_RESTART) = 0; - - // +-------------------------------------------------------------------+ - // + Time - // +-------------------------------------------------------------------+ - virtual void resetTime(S32 timeout) = 0; + LLFolderViewFilter() {} + virtual ~LLFolderViewFilter() {} + + // +-------------------------------------------------------------------+ + // + Execution And Results + // +-------------------------------------------------------------------+ + virtual bool check(const LLFolderViewModelItem* item) = 0; + virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0; + + virtual void setEmptyLookupMessage(const std::string& message) = 0; + virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0; + + virtual bool showAllResults() const = 0; + + virtual std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const = 0; + virtual std::string::size_type getFilterStringSize() const = 0; + // +-------------------------------------------------------------------+ + // + Status + // +-------------------------------------------------------------------+ + virtual bool isActive() const = 0; + virtual bool isModified() const = 0; + virtual void clearModified() = 0; + virtual const std::string& getName() const = 0; + virtual const std::string& getFilterText() = 0; + //RN: this is public to allow system to externally force a global refilter + virtual void setModified(EFilterModified behavior = FILTER_RESTART) = 0; + + // +-------------------------------------------------------------------+ + // + Time + // +-------------------------------------------------------------------+ + virtual void resetTime(S32 timeout) = 0; virtual bool isTimedOut() = 0; - - // +-------------------------------------------------------------------+ - // + Default - // +-------------------------------------------------------------------+ - virtual bool isDefault() const = 0; - virtual bool isNotDefault() const = 0; - virtual void markDefault() = 0; - virtual void resetDefault() = 0; - - // +-------------------------------------------------------------------+ - // + Generation - // +-------------------------------------------------------------------+ - virtual S32 getCurrentGeneration() const = 0; - virtual S32 getFirstSuccessGeneration() const = 0; - virtual S32 getFirstRequiredGeneration() const = 0; + + // +-------------------------------------------------------------------+ + // + Default + // +-------------------------------------------------------------------+ + virtual bool isDefault() const = 0; + virtual bool isNotDefault() const = 0; + virtual void markDefault() = 0; + virtual void resetDefault() = 0; + + // +-------------------------------------------------------------------+ + // + Generation + // +-------------------------------------------------------------------+ + virtual S32 getCurrentGeneration() const = 0; + virtual S32 getFirstSuccessGeneration() const = 0; + virtual S32 getFirstRequiredGeneration() const = 0; }; class LLFolderViewModelInterface { public: - LLFolderViewModelInterface() - {} + LLFolderViewModelInterface() + {} - virtual ~LLFolderViewModelInterface() {} - virtual void requestSortAll() = 0; + virtual ~LLFolderViewModelInterface() {} + virtual void requestSortAll() = 0; - virtual void sort(class LLFolderViewFolder*) = 0; - virtual void filter() = 0; + virtual void sort(class LLFolderViewFolder*) = 0; + virtual void filter() = 0; - virtual bool contentsReady() = 0; - virtual bool isFolderComplete(class LLFolderViewFolder*) = 0; - virtual void setFolderView(LLFolderView* folder_view) = 0; - virtual LLFolderViewFilter& getFilter() = 0; - virtual const LLFolderViewFilter& getFilter() const = 0; - virtual std::string getStatusText(bool is_empty_folder = false) = 0; + virtual bool contentsReady() = 0; + virtual bool isFolderComplete(class LLFolderViewFolder*) = 0; + virtual void setFolderView(LLFolderView* folder_view) = 0; + virtual LLFolderViewFilter& getFilter() = 0; + virtual const LLFolderViewFilter& getFilter() const = 0; + virtual std::string getStatusText(bool is_empty_folder = false) = 0; - virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0; + virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0; }; // This is an abstract base class that users of the folderview classes @@ -135,96 +135,96 @@ public: class LLFolderViewModelItem : public LLRefCount { public: - LLFolderViewModelItem() - {} + LLFolderViewModelItem() + {} - virtual ~LLFolderViewModelItem() { } + virtual ~LLFolderViewModelItem() { } - virtual void update() {} //called when drawing - virtual const std::string& getName() const = 0; - virtual const std::string& getDisplayName() const = 0; - virtual const std::string& getSearchableName() const = 0; + virtual void update() {} //called when drawing + virtual const std::string& getName() const = 0; + virtual const std::string& getDisplayName() const = 0; + virtual const std::string& getSearchableName() const = 0; - virtual std::string getSearchableDescription() const = 0; - virtual std::string getSearchableCreatorName()const = 0; - virtual std::string getSearchableUUIDString() const = 0; + virtual std::string getSearchableDescription() const = 0; + virtual std::string getSearchableCreatorName()const = 0; + virtual std::string getSearchableUUIDString() const = 0; - virtual LLPointer<LLUIImage> getIcon() const = 0; - virtual LLPointer<LLUIImage> getIconOpen() const { return getIcon(); } - virtual LLPointer<LLUIImage> getIconOverlay() const { return NULL; } + virtual LLPointer<LLUIImage> getIcon() const = 0; + virtual LLPointer<LLUIImage> getIconOpen() const { return getIcon(); } + virtual LLPointer<LLUIImage> getIconOverlay() const { return NULL; } - virtual LLFontGL::StyleFlags getLabelStyle() const = 0; - virtual std::string getLabelSuffix() const = 0; + virtual LLFontGL::StyleFlags getLabelStyle() const = 0; + virtual std::string getLabelSuffix() const = 0; - virtual void openItem( void ) = 0; - virtual void closeItem( void ) = 0; - virtual void selectItem(void) = 0; + virtual void openItem( void ) = 0; + virtual void closeItem( void ) = 0; + virtual void selectItem(void) = 0; virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0; - + virtual BOOL isItemWearable() const { return FALSE; } - virtual BOOL isItemRenameable() const = 0; - virtual BOOL renameItem(const std::string& new_name) = 0; - - virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder - virtual void move( LLFolderViewModelItem* parent_listener ) = 0; - - virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed - virtual BOOL removeItem() = 0; - virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0; - - virtual bool isItemCopyable(bool can_copy_as_link = true) const = 0; - virtual BOOL copyToClipboard() const = 0; - virtual BOOL cutToClipboard() = 0; - virtual bool isCutToClipboard() { return false; }; - - virtual BOOL isClipboardPasteable() const = 0; - virtual void pasteFromClipboard() = 0; - virtual void pasteLinkFromClipboard() = 0; - - virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; - - virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet? - - virtual bool filter( LLFolderViewFilter& filter) = 0; - virtual bool passedFilter(S32 filter_generation = -1) = 0; - virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0; - virtual void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) = 0; - virtual void setPassedFolderFilter(bool passed, S32 filter_generation) = 0; - virtual void dirtyFilter() = 0; - virtual void dirtyDescendantsFilter() = 0; - virtual bool hasFilterStringMatch() = 0; - virtual std::string::size_type getFilterStringOffset() = 0; - virtual std::string::size_type getFilterStringSize() = 0; - - virtual S32 getLastFilterGeneration() const = 0; - virtual S32 getMarkedDirtyGeneration() const = 0; - - virtual bool hasChildren() const = 0; - virtual void addChild(LLFolderViewModelItem* child) = 0; - virtual void removeChild(LLFolderViewModelItem* child) = 0; - virtual void clearChildren() = 0; - - // This method will be called to determine if a drop can be - // performed, and will set drop to TRUE if a drop is - // requested. Returns TRUE if a drop is possible/happened, - // otherwise FALSE. - virtual BOOL dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - std::string& tooltip_msg) = 0; - - virtual void requestSort() = 0; - virtual S32 getSortVersion() = 0; - virtual void setSortVersion(S32 version) = 0; - virtual void setParent(LLFolderViewModelItem* parent) = 0; - virtual bool hasParent() = 0; + virtual BOOL isItemRenameable() const = 0; + virtual BOOL renameItem(const std::string& new_name) = 0; + + virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder + virtual void move( LLFolderViewModelItem* parent_listener ) = 0; + + virtual BOOL isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed + virtual BOOL removeItem() = 0; + virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0; + + virtual bool isItemCopyable(bool can_copy_as_link = true) const = 0; + virtual BOOL copyToClipboard() const = 0; + virtual BOOL cutToClipboard() = 0; + virtual bool isCutToClipboard() { return false; }; + + virtual BOOL isClipboardPasteable() const = 0; + virtual void pasteFromClipboard() = 0; + virtual void pasteLinkFromClipboard() = 0; + + virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; + + virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet? + + virtual bool filter( LLFolderViewFilter& filter) = 0; + virtual bool passedFilter(S32 filter_generation = -1) = 0; + virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0; + virtual void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) = 0; + virtual void setPassedFolderFilter(bool passed, S32 filter_generation) = 0; + virtual void dirtyFilter() = 0; + virtual void dirtyDescendantsFilter() = 0; + virtual bool hasFilterStringMatch() = 0; + virtual std::string::size_type getFilterStringOffset() = 0; + virtual std::string::size_type getFilterStringSize() = 0; + + virtual S32 getLastFilterGeneration() const = 0; + virtual S32 getMarkedDirtyGeneration() const = 0; + + virtual bool hasChildren() const = 0; + virtual void addChild(LLFolderViewModelItem* child) = 0; + virtual void removeChild(LLFolderViewModelItem* child) = 0; + virtual void clearChildren() = 0; + + // This method will be called to determine if a drop can be + // performed, and will set drop to TRUE if a drop is + // requested. Returns TRUE if a drop is possible/happened, + // otherwise FALSE. + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + std::string& tooltip_msg) = 0; + + virtual void requestSort() = 0; + virtual S32 getSortVersion() = 0; + virtual void setSortVersion(S32 version) = 0; + virtual void setParent(LLFolderViewModelItem* parent) = 0; + virtual bool hasParent() = 0; protected: - friend class LLFolderViewItem; - virtual void setFolderViewItem(LLFolderViewItem* folder_view_item) = 0; + friend class LLFolderViewItem; + virtual void setFolderViewItem(LLFolderViewItem* folder_view_item) = 0; }; @@ -232,151 +232,151 @@ protected: class LLFolderViewModelItemCommon : public LLFolderViewModelItem { public: - LLFolderViewModelItemCommon(LLFolderViewModelInterface& root_view_model) - : mSortVersion(-1), - mPassedFilter(true), - mPassedFolderFilter(true), - mStringMatchOffsetFilter(std::string::npos), - mStringFilterSize(0), - mFolderViewItem(NULL), - mLastFilterGeneration(-1), - mLastFolderFilterGeneration(-1), - mMarkedDirtyGeneration(-1), - mMostFilteredDescendantGeneration(-1), - mParent(NULL), - mRootViewModel(root_view_model) - { - mChildren.clear(); - } - - void requestSort() { mSortVersion = -1; } - S32 getSortVersion() { return mSortVersion; } - void setSortVersion(S32 version) { mSortVersion = version;} - - S32 getLastFilterGeneration() const { return mLastFilterGeneration; } - S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; } - S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; } - void dirtyFilter() - { - if(mMarkedDirtyGeneration < 0) - { - mMarkedDirtyGeneration = mLastFilterGeneration; - } - mLastFilterGeneration = -1; - mLastFolderFilterGeneration = -1; - - // bubble up dirty flag all the way to root - if (mParent) - { - mParent->dirtyFilter(); - } - } - void dirtyDescendantsFilter() - { - mMostFilteredDescendantGeneration = -1; - if (mParent) - { - mParent->dirtyDescendantsFilter(); - } - } - bool hasFilterStringMatch(); - std::string::size_type getFilterStringOffset(); - std::string::size_type getFilterStringSize(); - - typedef std::list<LLFolderViewModelItem*> child_list_t; - - virtual void addChild(LLFolderViewModelItem* child) - { - mChildren.push_back(child); - child->setParent(this); - dirtyFilter(); - requestSort(); - } - virtual void removeChild(LLFolderViewModelItem* child) - { - mChildren.remove(child); - child->setParent(NULL); - dirtyDescendantsFilter(); - dirtyFilter(); - } - - virtual void clearChildren() - { - // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest - std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); - mChildren.clear(); - dirtyDescendantsFilter(); - dirtyFilter(); - } - - child_list_t::const_iterator getChildrenBegin() const { return mChildren.begin(); } - child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); } - child_list_t::size_type getChildrenCount() const { return mChildren.size(); } - - void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) - { - mPassedFilter = passed; - mLastFilterGeneration = filter_generation; - mStringMatchOffsetFilter = string_offset; - mStringFilterSize = string_size; - mMarkedDirtyGeneration = -1; - } - - void setPassedFolderFilter(bool passed, S32 filter_generation) - { - mPassedFolderFilter = passed; - mLastFolderFilterGeneration = filter_generation; - } - - virtual bool potentiallyVisible() - { - return passedFilter() // we've passed the filter - || (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet - || descendantsPassedFilter(); - } - - virtual bool passedFilter(S32 filter_generation = -1) - { - if (filter_generation < 0) + LLFolderViewModelItemCommon(LLFolderViewModelInterface& root_view_model) + : mSortVersion(-1), + mPassedFilter(true), + mPassedFolderFilter(true), + mStringMatchOffsetFilter(std::string::npos), + mStringFilterSize(0), + mFolderViewItem(NULL), + mLastFilterGeneration(-1), + mLastFolderFilterGeneration(-1), + mMarkedDirtyGeneration(-1), + mMostFilteredDescendantGeneration(-1), + mParent(NULL), + mRootViewModel(root_view_model) + { + mChildren.clear(); + } + + void requestSort() { mSortVersion = -1; } + S32 getSortVersion() { return mSortVersion; } + void setSortVersion(S32 version) { mSortVersion = version;} + + S32 getLastFilterGeneration() const { return mLastFilterGeneration; } + S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; } + S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; } + void dirtyFilter() + { + if(mMarkedDirtyGeneration < 0) { - filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); + mMarkedDirtyGeneration = mLastFilterGeneration; } - bool passed_folder_filter = mPassedFolderFilter && (mLastFolderFilterGeneration >= filter_generation); - bool passed_filter = mPassedFilter && (mLastFilterGeneration >= filter_generation); - return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation)); - } - - virtual bool descendantsPassedFilter(S32 filter_generation = -1) - { - if (filter_generation < 0) + mLastFilterGeneration = -1; + mLastFolderFilterGeneration = -1; + + // bubble up dirty flag all the way to root + if (mParent) + { + mParent->dirtyFilter(); + } + } + void dirtyDescendantsFilter() + { + mMostFilteredDescendantGeneration = -1; + if (mParent) + { + mParent->dirtyDescendantsFilter(); + } + } + bool hasFilterStringMatch(); + std::string::size_type getFilterStringOffset(); + std::string::size_type getFilterStringSize(); + + typedef std::list<LLFolderViewModelItem*> child_list_t; + + virtual void addChild(LLFolderViewModelItem* child) + { + mChildren.push_back(child); + child->setParent(this); + dirtyFilter(); + requestSort(); + } + virtual void removeChild(LLFolderViewModelItem* child) + { + mChildren.remove(child); + child->setParent(NULL); + dirtyDescendantsFilter(); + dirtyFilter(); + } + + virtual void clearChildren() + { + // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest + std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); + mChildren.clear(); + dirtyDescendantsFilter(); + dirtyFilter(); + } + + child_list_t::const_iterator getChildrenBegin() const { return mChildren.begin(); } + child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); } + child_list_t::size_type getChildrenCount() const { return mChildren.size(); } + + void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) + { + mPassedFilter = passed; + mLastFilterGeneration = filter_generation; + mStringMatchOffsetFilter = string_offset; + mStringFilterSize = string_size; + mMarkedDirtyGeneration = -1; + } + + void setPassedFolderFilter(bool passed, S32 filter_generation) + { + mPassedFolderFilter = passed; + mLastFolderFilterGeneration = filter_generation; + } + + virtual bool potentiallyVisible() + { + return passedFilter() // we've passed the filter + || (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet + || descendantsPassedFilter(); + } + + virtual bool passedFilter(S32 filter_generation = -1) + { + if (filter_generation < 0) { filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); } - return mMostFilteredDescendantGeneration >= filter_generation; - } + bool passed_folder_filter = mPassedFolderFilter && (mLastFolderFilterGeneration >= filter_generation); + bool passed_filter = mPassedFilter && (mLastFilterGeneration >= filter_generation); + return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation)); + } + + virtual bool descendantsPassedFilter(S32 filter_generation = -1) + { + if (filter_generation < 0) + { + filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); + } + return mMostFilteredDescendantGeneration >= filter_generation; + } protected: - virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } - virtual bool hasParent() { return mParent != NULL; } - - S32 mSortVersion; - bool mPassedFilter; - bool mPassedFolderFilter; - std::string::size_type mStringMatchOffsetFilter; - std::string::size_type mStringFilterSize; - - S32 mLastFilterGeneration, - mLastFolderFilterGeneration, - mMostFilteredDescendantGeneration, - mMarkedDirtyGeneration; - - child_list_t mChildren; - LLFolderViewModelItem* mParent; - LLFolderViewModelInterface& mRootViewModel; - - void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} - LLFolderViewItem* mFolderViewItem; + virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } + virtual bool hasParent() { return mParent != NULL; } + + S32 mSortVersion; + bool mPassedFilter; + bool mPassedFolderFilter; + std::string::size_type mStringMatchOffsetFilter; + std::string::size_type mStringFilterSize; + + S32 mLastFilterGeneration, + mLastFolderFilterGeneration, + mMostFilteredDescendantGeneration, + mMarkedDirtyGeneration; + + child_list_t mChildren; + LLFolderViewModelItem* mParent; + LLFolderViewModelInterface& mRootViewModel; + + void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} + LLFolderViewItem* mFolderViewItem; }; @@ -384,26 +384,26 @@ protected: class LLFolderViewModelCommon : public LLFolderViewModelInterface { public: - LLFolderViewModelCommon() - : mTargetSortVersion(0), - mFolderView(NULL) - {} + LLFolderViewModelCommon() + : mTargetSortVersion(0), + mFolderView(NULL) + {} - virtual void requestSortAll() - { - // sort everything - mTargetSortVersion++; - } - virtual std::string getStatusText(bool is_empty_folder = false); - virtual void filter(); + virtual void requestSortAll() + { + // sort everything + mTargetSortVersion++; + } + virtual std::string getStatusText(bool is_empty_folder = false); + virtual void filter(); - void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;} + void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;} protected: - bool needsSort(class LLFolderViewModelItem* item); + bool needsSort(class LLFolderViewModelItem* item); - S32 mTargetSortVersion; - LLFolderView* mFolderView; + S32 mTargetSortVersion; + LLFolderView* mFolderView; }; @@ -411,64 +411,64 @@ template <typename SORT_TYPE, typename ITEM_TYPE, typename FOLDER_TYPE, typename class LLFolderViewModel : public LLFolderViewModelCommon { public: - typedef SORT_TYPE SortType; - typedef ITEM_TYPE ItemType; - typedef FOLDER_TYPE FolderType; - typedef FILTER_TYPE FilterType; - - LLFolderViewModel(SortType* sorter, FilterType* filter) - : mSorter(sorter), - mFilter(filter) - {} - - virtual ~LLFolderViewModel() {} - - virtual SortType& getSorter() { return *mSorter; } - virtual const SortType& getSorter() const { return *mSorter; } - virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); } - - virtual FilterType& getFilter() { return *mFilter; } - virtual const FilterType& getFilter() const { return *mFilter; } - virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); } - - // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, - // this method needs to be overloaded and return the relevant fetch status. - virtual bool contentsReady() { return true; } - virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } - - struct ViewModelCompare - { - ViewModelCompare(const SortType& sorter) - : mSorter(sorter) - {} - - bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const - { - return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem())); - } - - bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const - { - return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem())); - } - - const SortType& mSorter; - }; - - void sort(LLFolderViewFolder* folder) - { - if (needsSort(folder->getViewModelItem())) - { - folder->sortFolders(ViewModelCompare(getSorter())); - folder->sortItems(ViewModelCompare(getSorter())); - folder->getViewModelItem()->setSortVersion(mTargetSortVersion); - folder->requestArrange(); - } - } + typedef SORT_TYPE SortType; + typedef ITEM_TYPE ItemType; + typedef FOLDER_TYPE FolderType; + typedef FILTER_TYPE FilterType; + + LLFolderViewModel(SortType* sorter, FilterType* filter) + : mSorter(sorter), + mFilter(filter) + {} + + virtual ~LLFolderViewModel() {} + + virtual SortType& getSorter() { return *mSorter; } + virtual const SortType& getSorter() const { return *mSorter; } + virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); } + + virtual FilterType& getFilter() { return *mFilter; } + virtual const FilterType& getFilter() const { return *mFilter; } + virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); } + + // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, + // this method needs to be overloaded and return the relevant fetch status. + virtual bool contentsReady() { return true; } + virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } + + struct ViewModelCompare + { + ViewModelCompare(const SortType& sorter) + : mSorter(sorter) + {} + + bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const + { + return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem())); + } + + bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const + { + return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem())); + } + + const SortType& mSorter; + }; + + void sort(LLFolderViewFolder* folder) + { + if (needsSort(folder->getViewModelItem())) + { + folder->sortFolders(ViewModelCompare(getSorter())); + folder->sortItems(ViewModelCompare(getSorter())); + folder->getViewModelItem()->setSortVersion(mTargetSortVersion); + folder->requestArrange(); + } + } protected: - std::unique_ptr<SortType> mSorter; - std::unique_ptr<FilterType> mFilter; + std::unique_ptr<SortType> mSorter; + std::unique_ptr<FilterType> mFilter; }; #endif // LLFOLDERVIEWMODEL_H diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index e43974bc52..da5570d922 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,93 +47,93 @@ * across restarts of the viewer; we couldn't store functors that way. * Using this registry, systems that require a functor to be maintained * long term can register it at system startup, and then pass in the - * functor by name. + * functor by name. */ template <typename FUNCTOR_TYPE> class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> > { - LLSINGLETON(LLFunctorRegistry); - LOG_CLASS(LLFunctorRegistry); + LLSINGLETON(LLFunctorRegistry); + LOG_CLASS(LLFunctorRegistry); public: - typedef FUNCTOR_TYPE ResponseFunctor; - typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap; - - bool registerFunctor(const std::string& name, ResponseFunctor f) - { - bool retval = true; - if (mMap.count(name) == 0) - { - mMap[name] = f; - } - else - { - LL_ERRS() << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << LL_ENDL; - retval = false; - } - - return retval; - } - - bool unregisterFunctor(const std::string& name) - { - if (mMap.count(name) == 0) - { - LL_WARNS() << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << LL_ENDL; - return false; - } - mMap.erase(name); - return true; - } - - FUNCTOR_TYPE getFunctor(const std::string& name) - { - if (mMap.count(name) != 0) - { - return mMap[name]; - } - else - { - LL_DEBUGS() << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << LL_ENDL; - return mMap[LOGFUNCTOR]; - } - } - - const std::string LOGFUNCTOR; - const std::string DONOTHING; - + typedef FUNCTOR_TYPE ResponseFunctor; + typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap; + + bool registerFunctor(const std::string& name, ResponseFunctor f) + { + bool retval = true; + if (mMap.count(name) == 0) + { + mMap[name] = f; + } + else + { + LL_ERRS() << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << LL_ENDL; + retval = false; + } + + return retval; + } + + bool unregisterFunctor(const std::string& name) + { + if (mMap.count(name) == 0) + { + LL_WARNS() << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << LL_ENDL; + return false; + } + mMap.erase(name); + return true; + } + + FUNCTOR_TYPE getFunctor(const std::string& name) + { + if (mMap.count(name) != 0) + { + return mMap[name]; + } + else + { + LL_DEBUGS() << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << LL_ENDL; + return mMap[LOGFUNCTOR]; + } + } + + const std::string LOGFUNCTOR; + const std::string DONOTHING; + private: - static void log_functor(const LLSD& notification, const LLSD& payload) - { - LL_DEBUGS() << "log_functor called with payload: " << payload << LL_ENDL; - } + static void log_functor(const LLSD& notification, const LLSD& payload) + { + LL_DEBUGS() << "log_functor called with payload: " << payload << LL_ENDL; + } - static void do_nothing(const LLSD& notification, const LLSD& payload) - { - // what the sign sez - } + static void do_nothing(const LLSD& notification, const LLSD& payload) + { + // what the sign sez + } - FunctorMap mMap; + FunctorMap mMap; }; template <typename FUNCTOR_TYPE> LLFunctorRegistry<FUNCTOR_TYPE>::LLFunctorRegistry() : - LOGFUNCTOR("LogFunctor"), DONOTHING("DoNothing") + LOGFUNCTOR("LogFunctor"), DONOTHING("DoNothing") { - mMap[LOGFUNCTOR] = log_functor; - mMap[DONOTHING] = do_nothing; + mMap[LOGFUNCTOR] = log_functor; + mMap[DONOTHING] = do_nothing; } template <typename FUNCTOR_TYPE> class LLFunctorRegistration { public: - LLFunctorRegistration(const std::string& name, FUNCTOR_TYPE functor) - { - LLFunctorRegistry<FUNCTOR_TYPE>::instance().registerFunctor(name, functor); - } + LLFunctorRegistration(const std::string& name, FUNCTOR_TYPE functor) + { + LLFunctorRegistry<FUNCTOR_TYPE>::instance().registerFunctor(name, functor); + } }; #endif//LL_LLFUNCTORREGISTRY_H diff --git a/indra/llui/llhelp.h b/indra/llui/llhelp.h index 1726347a78..829a080655 100644 --- a/indra/llui/llhelp.h +++ b/indra/llui/llhelp.h @@ -1,4 +1,4 @@ -/** +/** * @file llhelp.h * @brief Abstract interface to the Help system * @author Tofu Linden @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,14 +31,14 @@ class LLHelp { public: - virtual void showTopic(const std::string &topic) = 0; - virtual std::string getURL(const std::string &topic) = 0; - // return default (fallback) topic name suitable for showTopic() - virtual std::string defaultTopic() = 0; - // return topic to use before the user logs in - virtual std::string preLoginTopic() = 0; - // return topic to use for the top-level help, invoked by F1 - virtual std::string f1HelpTopic() = 0; + virtual void showTopic(const std::string &topic) = 0; + virtual std::string getURL(const std::string &topic) = 0; + // return default (fallback) topic name suitable for showTopic() + virtual std::string defaultTopic() = 0; + // return topic to use before the user logs in + virtual std::string preLoginTopic() = 0; + // return topic to use for the top-level help, invoked by F1 + virtual std::string f1HelpTopic() = 0; }; #endif // headerguard diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 2791377a5e..38c869cd59 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lliconctrl.cpp * @brief LLIconCtrl base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #include "lliconctrl.h" -// Linden library includes +// Linden library includes // Project includes #include "llcontrol.h" @@ -42,48 +42,48 @@ static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon"); LLIconCtrl::Params::Params() -: image("image_name"), - color("color"), - use_draw_context_alpha("use_draw_context_alpha", true), +: image("image_name"), + color("color"), + use_draw_context_alpha("use_draw_context_alpha", true), interactable("interactable", false), - scale_image("scale_image"), - min_width("min_width", 0), - min_height("min_height", 0) + scale_image("scale_image"), + min_width("min_width", 0), + min_height("min_height", 0) {} LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) -: LLUICtrl(p), - mColor(p.color()), - mImagep(p.image), - mUseDrawContextAlpha(p.use_draw_context_alpha), +: LLUICtrl(p), + mColor(p.color()), + mImagep(p.image), + mUseDrawContextAlpha(p.use_draw_context_alpha), mInteractable(p.interactable), - mPriority(0), - mMinWidth(p.min_width), - mMinHeight(p.min_height), - mMaxWidth(0), - mMaxHeight(0) + mPriority(0), + mMinWidth(p.min_width), + mMinHeight(p.min_height), + mMaxWidth(0), + mMaxHeight(0) { - if (mImagep.notNull()) - { - LLUICtrl::setValue(mImagep->getName()); - } + if (mImagep.notNull()) + { + LLUICtrl::setValue(mImagep->getName()); + } } LLIconCtrl::~LLIconCtrl() { - mImagep = NULL; + mImagep = NULL; } void LLIconCtrl::draw() { - if( mImagep.notNull() ) - { - const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); - mImagep->draw(getLocalRect(), mColor.get() % alpha ); - } + if( mImagep.notNull() ) + { + const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); + mImagep->draw(getLocalRect(), mColor.get() % alpha ); + } - LLUICtrl::draw(); + LLUICtrl::draw(); } BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask) @@ -98,18 +98,18 @@ BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask) void LLIconCtrl::onVisibilityChange(BOOL new_visibility) { - LLUICtrl::onVisibilityChange(new_visibility); - if (mPriority == LLGLTexture::BOOST_ICON) - { - if (new_visibility) - { - loadImage(getValue(), mPriority); - } - else - { - mImagep = nullptr; - } - } + LLUICtrl::onVisibilityChange(new_visibility); + if (mPriority == LLGLTexture::BOOST_ICON) + { + if (new_visibility) + { + loadImage(getValue(), mPriority); + } + else + { + mImagep = nullptr; + } + } } // virtual @@ -121,35 +121,35 @@ void LLIconCtrl::setValue(const LLSD& value) void LLIconCtrl::setValue(const LLSD& value, S32 priority) { - LLSD tvalue(value); - if (value.isString() && LLUUID::validate(value.asString())) - { - //RN: support UUIDs masquerading as strings - tvalue = LLSD(LLUUID(value.asString())); - } - LLUICtrl::setValue(tvalue); - - loadImage(tvalue, priority); + LLSD tvalue(value); + if (value.isString() && LLUUID::validate(value.asString())) + { + //RN: support UUIDs masquerading as strings + tvalue = LLSD(LLUUID(value.asString())); + } + LLUICtrl::setValue(tvalue); + + loadImage(tvalue, priority); } void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority) { - if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return; + if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return; - if (tvalue.isUUID()) - { + if (tvalue.isUUID()) + { mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority); - } - else - { + } + else + { mImagep = LLUI::getUIImage(tvalue.asString(), priority); - } + } - if(mImagep.notNull() - && mImagep->getImage().notNull() - && mMinWidth - && mMinHeight) - { + if(mImagep.notNull() + && mImagep->getImage().notNull() + && mMinWidth + && mMinHeight) + { S32 desired_draw_width = llmax(mMinWidth, mImagep->getWidth()); S32 desired_draw_height = llmax(mMinHeight, mImagep->getHeight()); if (mMaxWidth && mMaxHeight) @@ -159,15 +159,15 @@ void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority) } mImagep->getImage()->setKnownDrawSize(desired_draw_width, desired_draw_height); - } + } } std::string LLIconCtrl::getImageName() const { - if (getValue().isString()) - return getValue().asString(); - else - return std::string(); + if (getValue().isString()) + return getValue().asString(); + else + return std::string(); } diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index e983d63a01..240fe3a74c 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file lliconctrl.h * @brief LLIconCtrl base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,62 +46,62 @@ class LLIconCtrl : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<LLUIImage*> image; - Optional<LLUIColor> color; - Optional<bool> use_draw_context_alpha, + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLUIImage*> image; + Optional<LLUIColor> color; + Optional<bool> use_draw_context_alpha, interactable; - Optional<S32> min_width, - min_height; - Ignored scale_image; + Optional<S32> min_width, + min_height; + Ignored scale_image; - Params(); - }; + Params(); + }; protected: - LLIconCtrl(const Params&); - friend class LLUICtrlFactory; + LLIconCtrl(const Params&); + friend class LLUICtrlFactory; - void setValue(const LLSD& value, S32 priority); + void setValue(const LLSD& value, S32 priority); public: - virtual ~LLIconCtrl(); + virtual ~LLIconCtrl(); - // llview overrides - virtual void draw(); + // llview overrides + virtual void draw(); // llview overrides virtual BOOL handleHover(S32 x, S32 y, MASK mask); - // lluictrl overrides - void onVisibilityChange(BOOL new_visibility); - virtual void setValue(const LLSD& value ); + // lluictrl overrides + void onVisibilityChange(BOOL new_visibility); + virtual void setValue(const LLSD& value ); + + std::string getImageName() const; - std::string getImageName() const; + void setColor(const LLColor4& color) { mColor = color; } + void setImage(LLPointer<LLUIImage> image) { mImagep = image; } + const LLPointer<LLUIImage> getImage() { return mImagep; } - void setColor(const LLColor4& color) { mColor = color; } - void setImage(LLPointer<LLUIImage> image) { mImagep = image; } - const LLPointer<LLUIImage> getImage() { return mImagep; } - protected: - S32 mPriority; + S32 mPriority; - //the output size of the icon image if set. - S32 mMinWidth, - mMinHeight, - mMaxWidth, - mMaxHeight; + //the output size of the icon image if set. + S32 mMinWidth, + mMinHeight, + mMaxWidth, + mMaxHeight; - // If set to true (default), use the draw context transparency. - // If false, will use transparency returned by getCurrentTransparency(). See STORM-698. - bool mUseDrawContextAlpha; + // If set to true (default), use the draw context transparency. + // If false, will use transparency returned by getCurrentTransparency(). See STORM-698. + bool mUseDrawContextAlpha; bool mInteractable; private: - void loadImage(const LLSD& value, S32 priority); + void loadImage(const LLSD& value, S32 priority); - LLUIColor mColor; - LLPointer<LLUIImage> mImagep; + LLUIColor mColor; + LLPointer<LLUIImage> mImagep; }; #endif diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 341ddb83f3..1ac1e41727 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -36,443 +36,443 @@ inline bool LLKeywordToken::isHead(const llwchar* s) const { - // strncmp is much faster than string compare - bool res = true; - const llwchar* t = mToken.c_str(); - S32 len = mToken.size(); - for (S32 i=0; i<len; i++) - { - if (s[i] != t[i]) - { - res = false; - break; - } - } - return res; + // strncmp is much faster than string compare + bool res = true; + const llwchar* t = mToken.c_str(); + S32 len = mToken.size(); + for (S32 i=0; i<len; i++) + { + if (s[i] != t[i]) + { + res = false; + break; + } + } + return res; } inline bool LLKeywordToken::isTail(const llwchar* s) const { - bool res = true; - const llwchar* t = mDelimiter.c_str(); - S32 len = mDelimiter.size(); - for (S32 i=0; i<len; i++) - { - if (s[i] != t[i]) - { - res = false; - break; - } - } - return res; + bool res = true; + const llwchar* t = mDelimiter.c_str(); + S32 len = mDelimiter.size(); + for (S32 i=0; i<len; i++) + { + if (s[i] != t[i]) + { + res = false; + break; + } + } + return res; } LLKeywords::LLKeywords() -: mLoaded(false) +: mLoaded(false) { } LLKeywords::~LLKeywords() { - std::for_each(mWordTokenMap.begin(), mWordTokenMap.end(), DeletePairedPointer()); - mWordTokenMap.clear(); - std::for_each(mLineTokenList.begin(), mLineTokenList.end(), DeletePointer()); - mLineTokenList.clear(); - std::for_each(mDelimiterTokenList.begin(), mDelimiterTokenList.end(), DeletePointer()); - mDelimiterTokenList.clear(); + std::for_each(mWordTokenMap.begin(), mWordTokenMap.end(), DeletePairedPointer()); + mWordTokenMap.clear(); + std::for_each(mLineTokenList.begin(), mLineTokenList.end(), DeletePointer()); + mLineTokenList.clear(); + std::for_each(mDelimiterTokenList.begin(), mDelimiterTokenList.end(), DeletePointer()); + mDelimiterTokenList.clear(); } // Add the token as described void LLKeywords::addToken(LLKeywordToken::ETokenType type, - const std::string& key_in, - const LLColor4& color, - const std::string& tool_tip_in, - const std::string& delimiter_in) + const std::string& key_in, + const LLColor4& color, + const std::string& tool_tip_in, + const std::string& delimiter_in) { - std::string tip_text = tool_tip_in; - LLStringUtil::replaceString(tip_text, "\\n", "\n" ); - LLStringUtil::replaceString(tip_text, "\t", " " ); - if (tip_text.empty()) - { - tip_text = "[no info]"; - } - LLWString tool_tip = utf8str_to_wstring(tip_text); - - LLWString key = utf8str_to_wstring(key_in); - LLWString delimiter = utf8str_to_wstring(delimiter_in); - switch(type) - { - case LLKeywordToken::TT_CONSTANT: - case LLKeywordToken::TT_CONTROL: - case LLKeywordToken::TT_EVENT: - case LLKeywordToken::TT_FUNCTION: - case LLKeywordToken::TT_LABEL: - case LLKeywordToken::TT_SECTION: - case LLKeywordToken::TT_TYPE: - case LLKeywordToken::TT_WORD: - mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null); - break; - - case LLKeywordToken::TT_LINE: - mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null)); - break; - - case LLKeywordToken::TT_TWO_SIDED_DELIMITER: - case LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS: - case LLKeywordToken::TT_ONE_SIDED_DELIMITER: - mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, delimiter)); - break; - - default: - llassert(0); - } + std::string tip_text = tool_tip_in; + LLStringUtil::replaceString(tip_text, "\\n", "\n" ); + LLStringUtil::replaceString(tip_text, "\t", " " ); + if (tip_text.empty()) + { + tip_text = "[no info]"; + } + LLWString tool_tip = utf8str_to_wstring(tip_text); + + LLWString key = utf8str_to_wstring(key_in); + LLWString delimiter = utf8str_to_wstring(delimiter_in); + switch(type) + { + case LLKeywordToken::TT_CONSTANT: + case LLKeywordToken::TT_CONTROL: + case LLKeywordToken::TT_EVENT: + case LLKeywordToken::TT_FUNCTION: + case LLKeywordToken::TT_LABEL: + case LLKeywordToken::TT_SECTION: + case LLKeywordToken::TT_TYPE: + case LLKeywordToken::TT_WORD: + mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null); + break; + + case LLKeywordToken::TT_LINE: + mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null)); + break; + + case LLKeywordToken::TT_TWO_SIDED_DELIMITER: + case LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS: + case LLKeywordToken::TT_ONE_SIDED_DELIMITER: + mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, delimiter)); + break; + + default: + llassert(0); + } } std::string LLKeywords::getArguments(LLSD& arguments) { - std::string argString = ""; - - if (arguments.isArray()) - { - U32 argsCount = arguments.size(); - LLSD::array_iterator arrayIt = arguments.beginArray(); - for ( ; arrayIt != arguments.endArray(); ++arrayIt) - { - LLSD& args = (*arrayIt); - if (args.isMap()) - { - LLSD::map_iterator argsIt = args.beginMap(); - for ( ; argsIt != args.endMap(); ++argsIt) - { - argString += argsIt->second.get("type").asString() + " " + argsIt->first; - if (argsCount-- > 1) - { - argString += ", "; - } - } - } - else - { - LL_WARNS("SyntaxLSL") << "Argument array comtains a non-map element!" << LL_ENDL; - } - } - } - else if (!arguments.isUndefined()) - { - LL_WARNS("SyntaxLSL") << "Not an array! Invalid arguments LLSD passed to function." << arguments << LL_ENDL; - } - return argString; + std::string argString = ""; + + if (arguments.isArray()) + { + U32 argsCount = arguments.size(); + LLSD::array_iterator arrayIt = arguments.beginArray(); + for ( ; arrayIt != arguments.endArray(); ++arrayIt) + { + LLSD& args = (*arrayIt); + if (args.isMap()) + { + LLSD::map_iterator argsIt = args.beginMap(); + for ( ; argsIt != args.endMap(); ++argsIt) + { + argString += argsIt->second.get("type").asString() + " " + argsIt->first; + if (argsCount-- > 1) + { + argString += ", "; + } + } + } + else + { + LL_WARNS("SyntaxLSL") << "Argument array comtains a non-map element!" << LL_ENDL; + } + } + } + else if (!arguments.isUndefined()) + { + LL_WARNS("SyntaxLSL") << "Not an array! Invalid arguments LLSD passed to function." << arguments << LL_ENDL; + } + return argString; } std::string LLKeywords::getAttribute(const std::string& key) { - attribute_iterator_t it = mAttributes.find(key); - return (it != mAttributes.end()) ? it->second : ""; + attribute_iterator_t it = mAttributes.find(key); + return (it != mAttributes.end()) ? it->second : ""; } LLColor4 LLKeywords::getColorGroup(const std::string& key_in) { - std::string color_group = "ScriptText"; - if (key_in == "functions") - { - color_group = "SyntaxLslFunction"; - } - else if (key_in == "controls") - { - color_group = "SyntaxLslControlFlow"; - } - else if (key_in == "events") - { - color_group = "SyntaxLslEvent"; - } - else if (key_in == "types") - { - color_group = "SyntaxLslDataType"; - } - else if (key_in == "misc-flow-label") - { - color_group = "SyntaxLslControlFlow"; - } - else if (key_in =="deprecated") - { - color_group = "SyntaxLslDeprecated"; - } - else if (key_in =="god-mode") - { - color_group = "SyntaxLslGodMode"; - } - else if (key_in == "constants" - || key_in == "constants-integer" - || key_in == "constants-float" - || key_in == "constants-string" - || key_in == "constants-key" - || key_in == "constants-rotation" - || key_in == "constants-vector") - { - color_group = "SyntaxLslConstant"; - } - else - { - LL_WARNS("SyntaxLSL") << "Color key '" << key_in << "' not recognized." << LL_ENDL; - } - - return LLUIColorTable::instance().getColor(color_group); + std::string color_group = "ScriptText"; + if (key_in == "functions") + { + color_group = "SyntaxLslFunction"; + } + else if (key_in == "controls") + { + color_group = "SyntaxLslControlFlow"; + } + else if (key_in == "events") + { + color_group = "SyntaxLslEvent"; + } + else if (key_in == "types") + { + color_group = "SyntaxLslDataType"; + } + else if (key_in == "misc-flow-label") + { + color_group = "SyntaxLslControlFlow"; + } + else if (key_in =="deprecated") + { + color_group = "SyntaxLslDeprecated"; + } + else if (key_in =="god-mode") + { + color_group = "SyntaxLslGodMode"; + } + else if (key_in == "constants" + || key_in == "constants-integer" + || key_in == "constants-float" + || key_in == "constants-string" + || key_in == "constants-key" + || key_in == "constants-rotation" + || key_in == "constants-vector") + { + color_group = "SyntaxLslConstant"; + } + else + { + LL_WARNS("SyntaxLSL") << "Color key '" << key_in << "' not recognized." << LL_ENDL; + } + + return LLUIColorTable::instance().getColor(color_group); } void LLKeywords::initialize(LLSD SyntaxXML) { - mSyntax = SyntaxXML; - mLoaded = true; + mSyntax = SyntaxXML; + mLoaded = true; } void LLKeywords::processTokens() { - if (!mLoaded) - { - return; - } - - // Add 'standard' stuff: Quotes, Comments, Strings, Labels, etc. before processing the LLSD - std::string delimiter; - addToken(LLKeywordToken::TT_LABEL, "@", getColorGroup("misc-flow-label"), "Label\nTarget for jump statement", delimiter ); - addToken(LLKeywordToken::TT_ONE_SIDED_DELIMITER, "//", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (single-line)\nNon-functional commentary or disabled code", delimiter ); - addToken(LLKeywordToken::TT_TWO_SIDED_DELIMITER, "/*", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (multi-line)\nNon-functional commentary or disabled code", "*/" ); - addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\"", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\"" ); - - LLSD::map_iterator itr = mSyntax.beginMap(); - for ( ; itr != mSyntax.endMap(); ++itr) - { - if (itr->first == "llsd-lsl-syntax-version") - { - // Skip over version key. - } - else - { - if (itr->second.isMap()) - { - processTokensGroup(itr->second, itr->first); - } - else - { - LL_WARNS("LSL-Tokens-Processing") << "Map for " + itr->first + " entries is missing! Ignoring." << LL_ENDL; - } - } - } - LL_INFOS("SyntaxLSL") << "Finished processing tokens." << LL_ENDL; + if (!mLoaded) + { + return; + } + + // Add 'standard' stuff: Quotes, Comments, Strings, Labels, etc. before processing the LLSD + std::string delimiter; + addToken(LLKeywordToken::TT_LABEL, "@", getColorGroup("misc-flow-label"), "Label\nTarget for jump statement", delimiter ); + addToken(LLKeywordToken::TT_ONE_SIDED_DELIMITER, "//", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (single-line)\nNon-functional commentary or disabled code", delimiter ); + addToken(LLKeywordToken::TT_TWO_SIDED_DELIMITER, "/*", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (multi-line)\nNon-functional commentary or disabled code", "*/" ); + addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\"", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\"" ); + + LLSD::map_iterator itr = mSyntax.beginMap(); + for ( ; itr != mSyntax.endMap(); ++itr) + { + if (itr->first == "llsd-lsl-syntax-version") + { + // Skip over version key. + } + else + { + if (itr->second.isMap()) + { + processTokensGroup(itr->second, itr->first); + } + else + { + LL_WARNS("LSL-Tokens-Processing") << "Map for " + itr->first + " entries is missing! Ignoring." << LL_ENDL; + } + } + } + LL_INFOS("SyntaxLSL") << "Finished processing tokens." << LL_ENDL; } void LLKeywords::processTokensGroup(const LLSD& tokens, const std::string& group) { - LLColor4 color; - LLColor4 color_group; - LLColor4 color_deprecated = getColorGroup("deprecated"); - LLColor4 color_god_mode = getColorGroup("god-mode"); - - LLKeywordToken::ETokenType token_type = LLKeywordToken::TT_UNKNOWN; - // If a new token type is added here, it must also be added to the 'addToken' method - if (group == "constants") - { - token_type = LLKeywordToken::TT_CONSTANT; - } - else if (group == "controls") - { - token_type = LLKeywordToken::TT_CONTROL; - } - else if (group == "events") - { - token_type = LLKeywordToken::TT_EVENT; - } - else if (group == "functions") - { - token_type = LLKeywordToken::TT_FUNCTION; - } - else if (group == "label") - { - token_type = LLKeywordToken::TT_LABEL; - } - else if (group == "types") - { - token_type = LLKeywordToken::TT_TYPE; - } - - color_group = getColorGroup(group); - LL_DEBUGS("SyntaxLSL") << "Group: '" << group << "', using color: '" << color_group << "'" << LL_ENDL; - - if (tokens.isMap()) - { - LLSD::map_const_iterator outer_itr = tokens.beginMap(); - for ( ; outer_itr != tokens.endMap(); ++outer_itr ) - { - if (outer_itr->second.isMap()) - { - mAttributes.clear(); - LLSD arguments = LLSD(); - LLSD::map_const_iterator inner_itr = outer_itr->second.beginMap(); - for ( ; inner_itr != outer_itr->second.endMap(); ++inner_itr ) - { - if (inner_itr->first == "arguments") - { - if (inner_itr->second.isArray()) - { - arguments = inner_itr->second; - } - } - else if (!inner_itr->second.isMap() && !inner_itr->second.isArray()) - { - mAttributes[inner_itr->first] = inner_itr->second.asString(); - } - else - { - LL_WARNS("SyntaxLSL") << "Not a valid attribute: " << inner_itr->first << LL_ENDL; - } - } - - std::string tooltip = ""; - switch (token_type) - { - case LLKeywordToken::TT_CONSTANT: - if (getAttribute("type").length() > 0) - { - color_group = getColorGroup(group + "-" + getAttribute("type")); - } - else - { - color_group = getColorGroup(group); - } - tooltip = "Type: " + getAttribute("type") + ", Value: " + getAttribute("value"); - break; - case LLKeywordToken::TT_EVENT: - tooltip = outer_itr->first + "(" + getArguments(arguments) + ")"; - break; - case LLKeywordToken::TT_FUNCTION: - tooltip = getAttribute("return") + " " + outer_itr->first + "(" + getArguments(arguments) + ");"; - tooltip.append("\nEnergy: "); - tooltip.append(getAttribute("energy").empty() ? "0.0" : getAttribute("energy")); - if (!getAttribute("sleep").empty()) - { - tooltip += ", Sleep: " + getAttribute("sleep"); - } - default: - break; - } - - if (!getAttribute("tooltip").empty()) - { - if (!tooltip.empty()) - { - tooltip.append("\n"); - } - tooltip.append(getAttribute("tooltip")); - } - - color = getAttribute("deprecated") == "true" ? color_deprecated : color_group; - - if (getAttribute("god-mode") == "true") - { - color = color_god_mode; - } - - addToken(token_type, outer_itr->first, color, tooltip); - } - } - } - else if (tokens.isArray()) // Currently nothing should need this, but it's here for completeness - { - LL_INFOS("SyntaxLSL") << "Curious, shouldn't be an array here; adding all using color " << color << LL_ENDL; - for (S32 count = 0; count < tokens.size(); ++count) - { - addToken(token_type, tokens[count], color, ""); - } - } - else - { - LL_WARNS("SyntaxLSL") << "Invalid map/array passed: '" << tokens << "'" << LL_ENDL; - } + LLColor4 color; + LLColor4 color_group; + LLColor4 color_deprecated = getColorGroup("deprecated"); + LLColor4 color_god_mode = getColorGroup("god-mode"); + + LLKeywordToken::ETokenType token_type = LLKeywordToken::TT_UNKNOWN; + // If a new token type is added here, it must also be added to the 'addToken' method + if (group == "constants") + { + token_type = LLKeywordToken::TT_CONSTANT; + } + else if (group == "controls") + { + token_type = LLKeywordToken::TT_CONTROL; + } + else if (group == "events") + { + token_type = LLKeywordToken::TT_EVENT; + } + else if (group == "functions") + { + token_type = LLKeywordToken::TT_FUNCTION; + } + else if (group == "label") + { + token_type = LLKeywordToken::TT_LABEL; + } + else if (group == "types") + { + token_type = LLKeywordToken::TT_TYPE; + } + + color_group = getColorGroup(group); + LL_DEBUGS("SyntaxLSL") << "Group: '" << group << "', using color: '" << color_group << "'" << LL_ENDL; + + if (tokens.isMap()) + { + LLSD::map_const_iterator outer_itr = tokens.beginMap(); + for ( ; outer_itr != tokens.endMap(); ++outer_itr ) + { + if (outer_itr->second.isMap()) + { + mAttributes.clear(); + LLSD arguments = LLSD(); + LLSD::map_const_iterator inner_itr = outer_itr->second.beginMap(); + for ( ; inner_itr != outer_itr->second.endMap(); ++inner_itr ) + { + if (inner_itr->first == "arguments") + { + if (inner_itr->second.isArray()) + { + arguments = inner_itr->second; + } + } + else if (!inner_itr->second.isMap() && !inner_itr->second.isArray()) + { + mAttributes[inner_itr->first] = inner_itr->second.asString(); + } + else + { + LL_WARNS("SyntaxLSL") << "Not a valid attribute: " << inner_itr->first << LL_ENDL; + } + } + + std::string tooltip = ""; + switch (token_type) + { + case LLKeywordToken::TT_CONSTANT: + if (getAttribute("type").length() > 0) + { + color_group = getColorGroup(group + "-" + getAttribute("type")); + } + else + { + color_group = getColorGroup(group); + } + tooltip = "Type: " + getAttribute("type") + ", Value: " + getAttribute("value"); + break; + case LLKeywordToken::TT_EVENT: + tooltip = outer_itr->first + "(" + getArguments(arguments) + ")"; + break; + case LLKeywordToken::TT_FUNCTION: + tooltip = getAttribute("return") + " " + outer_itr->first + "(" + getArguments(arguments) + ");"; + tooltip.append("\nEnergy: "); + tooltip.append(getAttribute("energy").empty() ? "0.0" : getAttribute("energy")); + if (!getAttribute("sleep").empty()) + { + tooltip += ", Sleep: " + getAttribute("sleep"); + } + default: + break; + } + + if (!getAttribute("tooltip").empty()) + { + if (!tooltip.empty()) + { + tooltip.append("\n"); + } + tooltip.append(getAttribute("tooltip")); + } + + color = getAttribute("deprecated") == "true" ? color_deprecated : color_group; + + if (getAttribute("god-mode") == "true") + { + color = color_god_mode; + } + + addToken(token_type, outer_itr->first, color, tooltip); + } + } + } + else if (tokens.isArray()) // Currently nothing should need this, but it's here for completeness + { + LL_INFOS("SyntaxLSL") << "Curious, shouldn't be an array here; adding all using color " << color << LL_ENDL; + for (S32 count = 0; count < tokens.size(); ++count) + { + addToken(token_type, tokens[count], color, ""); + } + } + else + { + LL_WARNS("SyntaxLSL") << "Invalid map/array passed: '" << tokens << "'" << LL_ENDL; + } } LLKeywords::WStringMapIndex::WStringMapIndex(const WStringMapIndex& other) { - if(other.mOwner) - { - copyData(other.mData, other.mLength); - } - else - { - mOwner = false; - mLength = other.mLength; - mData = other.mData; - } + if(other.mOwner) + { + copyData(other.mData, other.mLength); + } + else + { + mOwner = false; + mLength = other.mLength; + mData = other.mData; + } } LLKeywords::WStringMapIndex::WStringMapIndex(const LLWString& str) { - copyData(str.data(), str.size()); + copyData(str.data(), str.size()); } LLKeywords::WStringMapIndex::WStringMapIndex(const llwchar *start, size_t length) -: mData(start) -, mLength(length) -, mOwner(false) +: mData(start) +, mLength(length) +, mOwner(false) { } LLKeywords::WStringMapIndex::~WStringMapIndex() { - if (mOwner) - { - delete[] mData; - } + if (mOwner) + { + delete[] mData; + } } void LLKeywords::WStringMapIndex::copyData(const llwchar *start, size_t length) { - llwchar *data = new llwchar[length]; - memcpy((void*)data, (const void*)start, length * sizeof(llwchar)); + llwchar *data = new llwchar[length]; + memcpy((void*)data, (const void*)start, length * sizeof(llwchar)); - mOwner = true; - mLength = length; - mData = data; + mOwner = true; + mLength = length; + mData = data; } bool LLKeywords::WStringMapIndex::operator<(const LLKeywords::WStringMapIndex &other) const { - // NOTE: Since this is only used to organize a std::map, it doesn't matter if it uses correct collate order or not. - // The comparison only needs to strictly order all possible strings, and be stable. - - bool result = false; - const llwchar* self_iter = mData; - const llwchar* self_end = mData + mLength; - const llwchar* other_iter = other.mData; - const llwchar* other_end = other.mData + other.mLength; - - while(true) - { - if(other_iter >= other_end) - { - // We've hit the end of other. - // This covers two cases: other being shorter than self, or the strings being equal. - // In either case, we want to return false. - result = false; - break; - } - else if(self_iter >= self_end) - { - // self is shorter than other. - result = true; - break; - } - else if(*self_iter != *other_iter) - { - // The current character differs. The strings are not equal. - result = *self_iter < *other_iter; - break; - } - - self_iter++; - other_iter++; - } - - return result; + // NOTE: Since this is only used to organize a std::map, it doesn't matter if it uses correct collate order or not. + // The comparison only needs to strictly order all possible strings, and be stable. + + bool result = false; + const llwchar* self_iter = mData; + const llwchar* self_end = mData + mLength; + const llwchar* other_iter = other.mData; + const llwchar* other_end = other.mData + other.mLength; + + while(true) + { + if(other_iter >= other_end) + { + // We've hit the end of other. + // This covers two cases: other being shorter than self, or the strings being equal. + // In either case, we want to return false. + result = false; + break; + } + else if(self_iter >= self_end) + { + // self is shorter than other. + result = true; + break; + } + else if(*self_iter != *other_iter) + { + // The current character differs. The strings are not equal. + result = *self_iter < *other_iter; + break; + } + + self_iter++; + other_iter++; + } + + return result; } LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring"); @@ -481,333 +481,333 @@ LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring"); // create a list of color segments. void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style) { - LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING); - seg_list->clear(); - - if( wtext.empty() ) - { - return; - } - - S32 text_len = wtext.size() + 1; - - seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); - - const llwchar* base = wtext.c_str(); - const llwchar* cur = base; - while( *cur ) - { - if( *cur == '\n' || cur == base ) - { - if( *cur == '\n' ) - { - LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, cur-base); - text_segment->setToken( 0 ); - insertSegment( *seg_list, text_segment, text_len, style, editor); - cur++; - if( !*cur || *cur == '\n' ) - { - continue; - } - } - - // Skip white space - while( *cur && iswspace(*cur) && (*cur != '\n') ) - { - cur++; - } - if( !*cur || *cur == '\n' ) - { - continue; - } - - // cur is now at the first non-whitespace character of a new line - - // Line start tokens - { - BOOL line_done = FALSE; - for (token_list_t::iterator iter = mLineTokenList.begin(); - iter != mLineTokenList.end(); ++iter) - { - LLKeywordToken* cur_token = *iter; - if( cur_token->isHead( cur ) ) - { - S32 seg_start = cur - base; - while( *cur && *cur != '\n' ) - { - // skip the rest of the line - cur++; - } - S32 seg_end = cur - base; - - //create segments from seg_start to seg_end - insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); - line_done = TRUE; // to break out of second loop. - break; - } - } - - if( line_done ) - { - continue; - } - } - } - - // Skip white space - while( *cur && iswspace(*cur) && (*cur != '\n') ) - { - cur++; - } - - while( *cur && *cur != '\n' ) - { - // Check against delimiters - { - S32 seg_start = 0; - LLKeywordToken* cur_delimiter = NULL; - for (token_list_t::iterator iter = mDelimiterTokenList.begin(); - iter != mDelimiterTokenList.end(); ++iter) - { - LLKeywordToken* delimiter = *iter; - if( delimiter->isHead( cur ) ) - { - cur_delimiter = delimiter; - break; - } - } - - if( cur_delimiter ) - { - S32 between_delimiters = 0; - S32 seg_end = 0; - - seg_start = cur - base; - cur += cur_delimiter->getLengthHead(); - - LLKeywordToken::ETokenType type = cur_delimiter->getType(); - if( type == LLKeywordToken::TT_TWO_SIDED_DELIMITER || type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS ) - { - while( *cur && !cur_delimiter->isTail(cur)) - { - // Check for an escape sequence. - if (type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS && *cur == '\\') - { - // Count the number of backslashes. - S32 num_backslashes = 0; - while (*cur == '\\') - { - num_backslashes++; - between_delimiters++; - cur++; - } - // If the next character is the end delimiter? - if (cur_delimiter->isTail(cur)) - { - // If there was an odd number of backslashes, then this delimiter - // does not end the sequence. - if (num_backslashes % 2 == 1) - { - between_delimiters++; - cur++; - } - else - { - // This is an end delimiter. - break; - } - } - } - else - { - between_delimiters++; - cur++; - } - } - - if( *cur ) - { - cur += cur_delimiter->getLengthHead(); - seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead() + cur_delimiter->getLengthTail(); - } - else - { - // eof - seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead(); - } - } - else - { - llassert( cur_delimiter->getType() == LLKeywordToken::TT_ONE_SIDED_DELIMITER ); - // Left side is the delimiter. Right side is eol or eof. - while( *cur && ('\n' != *cur) ) - { - between_delimiters++; - cur++; - } - seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead(); - } - - insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, style, editor); - /* - LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor ); - text_segment->setToken( cur_delimiter ); - insertSegment( seg_list, text_segment, text_len, defaultColor, editor); - */ - // Note: we don't increment cur, since the end of one delimited seg may be immediately - // followed by the start of another one. - continue; - } - } - - // check against words - llwchar prev = cur > base ? *(cur-1) : 0; - if( !iswalnum( prev ) && (prev != '_') ) - { - const llwchar* p = cur; - while( iswalnum( *p ) || (*p == '_') ) - { - p++; - } - S32 seg_len = p - cur; - if( seg_len > 0 ) - { - WStringMapIndex word( cur, seg_len ); - word_token_map_t::iterator map_iter = mWordTokenMap.find(word); - if( map_iter != mWordTokenMap.end() ) - { - LLKeywordToken* cur_token = map_iter->second; - S32 seg_start = cur - base; - S32 seg_end = seg_start + seg_len; - - // LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL; - - insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); - } - cur += seg_len; - continue; - } - } - - if( *cur && *cur != '\n' ) - { - cur++; - } - } - } + LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING); + seg_list->clear(); + + if( wtext.empty() ) + { + return; + } + + S32 text_len = wtext.size() + 1; + + seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); + + const llwchar* base = wtext.c_str(); + const llwchar* cur = base; + while( *cur ) + { + if( *cur == '\n' || cur == base ) + { + if( *cur == '\n' ) + { + LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, cur-base); + text_segment->setToken( 0 ); + insertSegment( *seg_list, text_segment, text_len, style, editor); + cur++; + if( !*cur || *cur == '\n' ) + { + continue; + } + } + + // Skip white space + while( *cur && iswspace(*cur) && (*cur != '\n') ) + { + cur++; + } + if( !*cur || *cur == '\n' ) + { + continue; + } + + // cur is now at the first non-whitespace character of a new line + + // Line start tokens + { + BOOL line_done = FALSE; + for (token_list_t::iterator iter = mLineTokenList.begin(); + iter != mLineTokenList.end(); ++iter) + { + LLKeywordToken* cur_token = *iter; + if( cur_token->isHead( cur ) ) + { + S32 seg_start = cur - base; + while( *cur && *cur != '\n' ) + { + // skip the rest of the line + cur++; + } + S32 seg_end = cur - base; + + //create segments from seg_start to seg_end + insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); + line_done = TRUE; // to break out of second loop. + break; + } + } + + if( line_done ) + { + continue; + } + } + } + + // Skip white space + while( *cur && iswspace(*cur) && (*cur != '\n') ) + { + cur++; + } + + while( *cur && *cur != '\n' ) + { + // Check against delimiters + { + S32 seg_start = 0; + LLKeywordToken* cur_delimiter = NULL; + for (token_list_t::iterator iter = mDelimiterTokenList.begin(); + iter != mDelimiterTokenList.end(); ++iter) + { + LLKeywordToken* delimiter = *iter; + if( delimiter->isHead( cur ) ) + { + cur_delimiter = delimiter; + break; + } + } + + if( cur_delimiter ) + { + S32 between_delimiters = 0; + S32 seg_end = 0; + + seg_start = cur - base; + cur += cur_delimiter->getLengthHead(); + + LLKeywordToken::ETokenType type = cur_delimiter->getType(); + if( type == LLKeywordToken::TT_TWO_SIDED_DELIMITER || type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS ) + { + while( *cur && !cur_delimiter->isTail(cur)) + { + // Check for an escape sequence. + if (type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS && *cur == '\\') + { + // Count the number of backslashes. + S32 num_backslashes = 0; + while (*cur == '\\') + { + num_backslashes++; + between_delimiters++; + cur++; + } + // If the next character is the end delimiter? + if (cur_delimiter->isTail(cur)) + { + // If there was an odd number of backslashes, then this delimiter + // does not end the sequence. + if (num_backslashes % 2 == 1) + { + between_delimiters++; + cur++; + } + else + { + // This is an end delimiter. + break; + } + } + } + else + { + between_delimiters++; + cur++; + } + } + + if( *cur ) + { + cur += cur_delimiter->getLengthHead(); + seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead() + cur_delimiter->getLengthTail(); + } + else + { + // eof + seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead(); + } + } + else + { + llassert( cur_delimiter->getType() == LLKeywordToken::TT_ONE_SIDED_DELIMITER ); + // Left side is the delimiter. Right side is eol or eof. + while( *cur && ('\n' != *cur) ) + { + between_delimiters++; + cur++; + } + seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead(); + } + + insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, style, editor); + /* + LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor ); + text_segment->setToken( cur_delimiter ); + insertSegment( seg_list, text_segment, text_len, defaultColor, editor); + */ + // Note: we don't increment cur, since the end of one delimited seg may be immediately + // followed by the start of another one. + continue; + } + } + + // check against words + llwchar prev = cur > base ? *(cur-1) : 0; + if( !iswalnum( prev ) && (prev != '_') ) + { + const llwchar* p = cur; + while( iswalnum( *p ) || (*p == '_') ) + { + p++; + } + S32 seg_len = p - cur; + if( seg_len > 0 ) + { + WStringMapIndex word( cur, seg_len ); + word_token_map_t::iterator map_iter = mWordTokenMap.find(word); + if( map_iter != mWordTokenMap.end() ) + { + LLKeywordToken* cur_token = map_iter->second; + S32 seg_start = cur - base; + S32 seg_end = seg_start + seg_len; + + // LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL; + + insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor); + } + cur += seg_len; + continue; + } + } + + if( *cur && *cur != '\n' ) + { + cur++; + } + } + } } void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, LLStyleConstSP style, LLTextEditor& editor ) { - std::string::size_type pos = wtext.find('\n',seg_start); - + std::string::size_type pos = wtext.find('\n',seg_start); + LLStyleConstSP cur_token_style = new LLStyle(LLStyle::Params().font(style->getFont()).color(cur_token->getColor())); - while (pos!=-1 && pos < (std::string::size_type)seg_end) - { - if (pos!=seg_start) - { + while (pos!=-1 && pos < (std::string::size_type)seg_end) + { + if (pos!=seg_start) + { LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, pos, editor); - text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, style, editor); - } + text_segment->setToken( cur_token ); + insertSegment( seg_list, text_segment, text_len, style, editor); + } - LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, pos); - text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, style, editor); + LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, pos); + text_segment->setToken( cur_token ); + insertSegment( seg_list, text_segment, text_len, style, editor); - seg_start = pos+1; - pos = wtext.find('\n',seg_start); - } + seg_start = pos+1; + pos = wtext.find('\n',seg_start); + } - LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, seg_end, editor); - text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, style, editor); + LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, seg_end, editor); + text_segment->setToken( cur_token ); + insertSegment( seg_list, text_segment, text_len, style, editor); } void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor ) { - LLTextSegmentPtr last = seg_list.back(); - S32 new_seg_end = new_segment->getEnd(); - - if( new_segment->getStart() == last->getStart() ) - { - seg_list.pop_back(); - } - else - { - last->setEnd( new_segment->getStart() ); - } - seg_list.push_back( new_segment ); - - if( new_seg_end < text_len ) - { - seg_list.push_back( new LLNormalTextSegment( defaultColor, new_seg_end, text_len, editor ) ); - } + LLTextSegmentPtr last = seg_list.back(); + S32 new_seg_end = new_segment->getEnd(); + + if( new_segment->getStart() == last->getStart() ) + { + seg_list.pop_back(); + } + else + { + last->setEnd( new_segment->getStart() ); + } + seg_list.push_back( new_segment ); + + if( new_seg_end < text_len ) + { + seg_list.push_back( new LLNormalTextSegment( defaultColor, new_seg_end, text_len, editor ) ); + } } void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor ) { - LLTextSegmentPtr last = seg_list.back(); - S32 new_seg_end = new_segment->getEnd(); - - if( new_segment->getStart() == last->getStart() ) - { - seg_list.pop_back(); - } - else - { - last->setEnd( new_segment->getStart() ); - } - seg_list.push_back( new_segment ); - - if( new_seg_end < text_len ) - { - seg_list.push_back( new LLNormalTextSegment( style, new_seg_end, text_len, editor ) ); - } + LLTextSegmentPtr last = seg_list.back(); + S32 new_seg_end = new_segment->getEnd(); + + if( new_segment->getStart() == last->getStart() ) + { + seg_list.pop_back(); + } + else + { + last->setEnd( new_segment->getStart() ); + } + seg_list.push_back( new_segment ); + + if( new_seg_end < text_len ) + { + seg_list.push_back( new LLNormalTextSegment( style, new_seg_end, text_len, editor ) ); + } } #ifdef _DEBUG void LLKeywords::dump() { - LL_INFOS() << "LLKeywords" << LL_ENDL; - - - LL_INFOS() << "LLKeywords::sWordTokenMap" << LL_ENDL; - word_token_map_t::iterator word_token_iter = mWordTokenMap.begin(); - while( word_token_iter != mWordTokenMap.end() ) - { - LLKeywordToken* word_token = word_token_iter->second; - word_token->dump(); - ++word_token_iter; - } - - LL_INFOS() << "LLKeywords::sLineTokenList" << LL_ENDL; - for (token_list_t::iterator iter = mLineTokenList.begin(); - iter != mLineTokenList.end(); ++iter) - { - LLKeywordToken* line_token = *iter; - line_token->dump(); - } - - - LL_INFOS() << "LLKeywords::sDelimiterTokenList" << LL_ENDL; - for (token_list_t::iterator iter = mDelimiterTokenList.begin(); - iter != mDelimiterTokenList.end(); ++iter) - { - LLKeywordToken* delimiter_token = *iter; - delimiter_token->dump(); - } + LL_INFOS() << "LLKeywords" << LL_ENDL; + + + LL_INFOS() << "LLKeywords::sWordTokenMap" << LL_ENDL; + word_token_map_t::iterator word_token_iter = mWordTokenMap.begin(); + while( word_token_iter != mWordTokenMap.end() ) + { + LLKeywordToken* word_token = word_token_iter->second; + word_token->dump(); + ++word_token_iter; + } + + LL_INFOS() << "LLKeywords::sLineTokenList" << LL_ENDL; + for (token_list_t::iterator iter = mLineTokenList.begin(); + iter != mLineTokenList.end(); ++iter) + { + LLKeywordToken* line_token = *iter; + line_token->dump(); + } + + + LL_INFOS() << "LLKeywords::sDelimiterTokenList" << LL_ENDL; + for (token_list_t::iterator iter = mDelimiterTokenList.begin(); + iter != mDelimiterTokenList.end(); ++iter) + { + LLKeywordToken* delimiter_token = *iter; + delimiter_token->dump(); + } } void LLKeywordToken::dump() { - LL_INFOS() << "[" << - mColor.mV[VX] << ", " << - mColor.mV[VY] << ", " << - mColor.mV[VZ] << "] [" << - wstring_to_utf8str(mToken) << "]" << - LL_ENDL; + LL_INFOS() << "[" << + mColor.mV[VX] << ", " << + mColor.mV[VY] << ", " << + mColor.mV[VZ] << "] [" << + wstring_to_utf8str(mToken) << "]" << + LL_ENDL; } #endif // DEBUG diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 2410fe7d5a..9dcdea121b 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -44,162 +44,162 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr; class LLKeywordToken { public: - /** - * @brief Types of tokens/delimters being parsed. - * - * @desc Tokens/delimiters that need to be identified/highlighted. All are terminated if an EOF is encountered. - * - TT_WORD are keywords in the normal sense, i.e. constants, events, etc. - * - TT_LINE are for entire lines (currently only flow control labels use this). - * - TT_ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL. - * - TT_TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with. - * - TT_DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close. - */ - typedef enum e_token_type - { - TT_UNKNOWN, - TT_WORD, - TT_LINE, - TT_TWO_SIDED_DELIMITER, - TT_ONE_SIDED_DELIMITER, - TT_DOUBLE_QUOTATION_MARKS, - // Following constants are more specific versions of the preceding ones - TT_CONSTANT, // WORD - TT_CONTROL, // WORD - TT_EVENT, // WORD - TT_FUNCTION, // WORD - TT_LABEL, // LINE - TT_SECTION, // WORD - TT_TYPE // WORD - } ETokenType; - - LLKeywordToken( ETokenType type, const LLColor4& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter ) - : - mType( type ), - mToken( token ), - mColor( color ), - mToolTip( tool_tip ), - mDelimiter( delimiter ) // right delimiter - { - } - - S32 getLengthHead() const { return mToken.size(); } - S32 getLengthTail() const { return mDelimiter.size(); } - bool isHead(const llwchar* s) const; - bool isTail(const llwchar* s) const; - const LLWString& getToken() const { return mToken; } - const LLColor4& getColor() const { return mColor; } - ETokenType getType() const { return mType; } - const LLWString& getToolTip() const { return mToolTip; } - const LLWString& getDelimiter() const { return mDelimiter; } + /** + * @brief Types of tokens/delimters being parsed. + * + * @desc Tokens/delimiters that need to be identified/highlighted. All are terminated if an EOF is encountered. + * - TT_WORD are keywords in the normal sense, i.e. constants, events, etc. + * - TT_LINE are for entire lines (currently only flow control labels use this). + * - TT_ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL. + * - TT_TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with. + * - TT_DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close. + */ + typedef enum e_token_type + { + TT_UNKNOWN, + TT_WORD, + TT_LINE, + TT_TWO_SIDED_DELIMITER, + TT_ONE_SIDED_DELIMITER, + TT_DOUBLE_QUOTATION_MARKS, + // Following constants are more specific versions of the preceding ones + TT_CONSTANT, // WORD + TT_CONTROL, // WORD + TT_EVENT, // WORD + TT_FUNCTION, // WORD + TT_LABEL, // LINE + TT_SECTION, // WORD + TT_TYPE // WORD + } ETokenType; + + LLKeywordToken( ETokenType type, const LLColor4& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter ) + : + mType( type ), + mToken( token ), + mColor( color ), + mToolTip( tool_tip ), + mDelimiter( delimiter ) // right delimiter + { + } + + S32 getLengthHead() const { return mToken.size(); } + S32 getLengthTail() const { return mDelimiter.size(); } + bool isHead(const llwchar* s) const; + bool isTail(const llwchar* s) const; + const LLWString& getToken() const { return mToken; } + const LLColor4& getColor() const { return mColor; } + ETokenType getType() const { return mType; } + const LLWString& getToolTip() const { return mToolTip; } + const LLWString& getDelimiter() const { return mDelimiter; } #ifdef _DEBUG - void dump(); + void dump(); #endif private: - ETokenType mType; - LLWString mToken; - LLColor4 mColor; - LLWString mToolTip; - LLWString mDelimiter; + ETokenType mType; + LLWString mToken; + LLColor4 mColor; + LLWString mToolTip; + LLWString mDelimiter; }; class LLKeywords { public: - LLKeywords(); - ~LLKeywords(); + LLKeywords(); + ~LLKeywords(); - void clearLoaded() { mLoaded = false; } - LLColor4 getColorGroup(const std::string& key_in); - bool isLoaded() const { return mLoaded; } + void clearLoaded() { mLoaded = false; } + LLColor4 getColorGroup(const std::string& key_in); + bool isLoaded() const { return mLoaded; } - void findSegments(std::vector<LLTextSegmentPtr> *seg_list, - const LLWString& text, - class LLTextEditor& editor, + void findSegments(std::vector<LLTextSegmentPtr> *seg_list, + const LLWString& text, + class LLTextEditor& editor, LLStyleConstSP style); - void initialize(LLSD SyntaxXML); - void processTokens(); - - // Add the token as described - void addToken(LLKeywordToken::ETokenType type, - const std::string& key, - const LLColor4& color, - const std::string& tool_tip = LLStringUtil::null, - const std::string& delimiter = LLStringUtil::null); - - // This class is here as a performance optimization. - // The word token map used to be defined as std::map<LLWString, LLKeywordToken*>. - // This worked, but caused a performance bottleneck due to memory allocation and string copies - // because it's not possible to search such a map without creating an LLWString. - // Using this class as the map index instead allows us to search using segments of an existing - // text run without copying them first, which greatly reduces overhead in LLKeywords::findSegments(). - class WStringMapIndex - { - public: - // copy constructor - WStringMapIndex(const WStringMapIndex& other); - // constructor from a string (copies the string's data into the new object) - WStringMapIndex(const LLWString& str); - // constructor from pointer and length - // NOTE: does NOT copy data, caller must ensure that the lifetime of the pointer exceeds that of the new object! - WStringMapIndex(const llwchar *start, size_t length); - ~WStringMapIndex(); - bool operator<(const WStringMapIndex &other) const; - private: - void copyData(const llwchar *start, size_t length); - const llwchar *mData; - size_t mLength; - bool mOwner; - - - LLColor4 mColor; - }; - - typedef std::map<WStringMapIndex, LLKeywordToken*> word_token_map_t; - typedef word_token_map_t::const_iterator keyword_iterator_t; - keyword_iterator_t begin() const { return mWordTokenMap.begin(); } - keyword_iterator_t end() const { return mWordTokenMap.end(); } - - typedef std::map<WStringMapIndex, LLColor4> group_color_map_t; - typedef group_color_map_t::const_iterator color_iterator_t; - group_color_map_t mColorGroupMap; + void initialize(LLSD SyntaxXML); + void processTokens(); + + // Add the token as described + void addToken(LLKeywordToken::ETokenType type, + const std::string& key, + const LLColor4& color, + const std::string& tool_tip = LLStringUtil::null, + const std::string& delimiter = LLStringUtil::null); + + // This class is here as a performance optimization. + // The word token map used to be defined as std::map<LLWString, LLKeywordToken*>. + // This worked, but caused a performance bottleneck due to memory allocation and string copies + // because it's not possible to search such a map without creating an LLWString. + // Using this class as the map index instead allows us to search using segments of an existing + // text run without copying them first, which greatly reduces overhead in LLKeywords::findSegments(). + class WStringMapIndex + { + public: + // copy constructor + WStringMapIndex(const WStringMapIndex& other); + // constructor from a string (copies the string's data into the new object) + WStringMapIndex(const LLWString& str); + // constructor from pointer and length + // NOTE: does NOT copy data, caller must ensure that the lifetime of the pointer exceeds that of the new object! + WStringMapIndex(const llwchar *start, size_t length); + ~WStringMapIndex(); + bool operator<(const WStringMapIndex &other) const; + private: + void copyData(const llwchar *start, size_t length); + const llwchar *mData; + size_t mLength; + bool mOwner; + + + LLColor4 mColor; + }; + + typedef std::map<WStringMapIndex, LLKeywordToken*> word_token_map_t; + typedef word_token_map_t::const_iterator keyword_iterator_t; + keyword_iterator_t begin() const { return mWordTokenMap.begin(); } + keyword_iterator_t end() const { return mWordTokenMap.end(); } + + typedef std::map<WStringMapIndex, LLColor4> group_color_map_t; + typedef group_color_map_t::const_iterator color_iterator_t; + group_color_map_t mColorGroupMap; #ifdef _DEBUG - void dump(); + void dump(); #endif protected: - void processTokensGroup(const LLSD& Tokens, const std::string& Group); - void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, - LLTextSegmentPtr new_segment, - S32 text_len, - const LLColor4 &defaultColor, - class LLTextEditor& editor); - void insertSegments(const LLWString& wtext, - std::vector<LLTextSegmentPtr>& seg_list, - LLKeywordToken* token, - S32 text_len, - S32 seg_start, - S32 seg_end, - LLStyleConstSP style, - LLTextEditor& editor); + void processTokensGroup(const LLSD& Tokens, const std::string& Group); + void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, + LLTextSegmentPtr new_segment, + S32 text_len, + const LLColor4 &defaultColor, + class LLTextEditor& editor); + void insertSegments(const LLWString& wtext, + std::vector<LLTextSegmentPtr>& seg_list, + LLKeywordToken* token, + S32 text_len, + S32 seg_start, + S32 seg_end, + LLStyleConstSP style, + LLTextEditor& editor); void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor ); - bool mLoaded; - LLSD mSyntax; - word_token_map_t mWordTokenMap; - typedef std::deque<LLKeywordToken*> token_list_t; - token_list_t mLineTokenList; - token_list_t mDelimiterTokenList; + bool mLoaded; + LLSD mSyntax; + word_token_map_t mWordTokenMap; + typedef std::deque<LLKeywordToken*> token_list_t; + token_list_t mLineTokenList; + token_list_t mDelimiterTokenList; - typedef std::map<std::string, std::string> element_attributes_t; - typedef element_attributes_t::const_iterator attribute_iterator_t; - element_attributes_t mAttributes; - std::string getAttribute(const std::string& key); + typedef std::map<std::string, std::string> element_attributes_t; + typedef element_attributes_t::const_iterator attribute_iterator_t; + element_attributes_t mAttributes; + std::string getAttribute(const std::string& key); - std::string getArguments(LLSD& arguments); + std::string getArguments(LLSD& arguments); }; #endif // LL_LLKEYWORDS_H diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 2769a96875..13d6faa673 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lllayoutstack.cpp * @brief LLLayout class - dynamic stacking of UI elements * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,159 +45,159 @@ static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layo // // LLLayoutPanel // -LLLayoutPanel::Params::Params() -: expanded_min_dim("expanded_min_dim", 0), - min_dim("min_dim", -1), - user_resize("user_resize", false), - auto_resize("auto_resize", true) +LLLayoutPanel::Params::Params() +: expanded_min_dim("expanded_min_dim", 0), + min_dim("min_dim", -1), + user_resize("user_resize", false), + auto_resize("auto_resize", true) { - addSynonym(min_dim, "min_width"); - addSynonym(min_dim, "min_height"); + addSynonym(min_dim, "min_width"); + addSynonym(min_dim, "min_height"); } -LLLayoutPanel::LLLayoutPanel(const Params& p) -: LLPanel(p), - mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim), - mMinDim(p.min_dim), - mAutoResize(p.auto_resize), - mUserResize(p.user_resize), - mCollapsed(FALSE), - mCollapseAmt(0.f), - mVisibleAmt(1.f), // default to fully visible - mResizeBar(NULL), - mFractionalSize(0.f), - mTargetDim(0), - mIgnoreReshape(false), - mOrientation(LLLayoutStack::HORIZONTAL) +LLLayoutPanel::LLLayoutPanel(const Params& p) +: LLPanel(p), + mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim), + mMinDim(p.min_dim), + mAutoResize(p.auto_resize), + mUserResize(p.user_resize), + mCollapsed(FALSE), + mCollapseAmt(0.f), + mVisibleAmt(1.f), // default to fully visible + mResizeBar(NULL), + mFractionalSize(0.f), + mTargetDim(0), + mIgnoreReshape(false), + mOrientation(LLLayoutStack::HORIZONTAL) { - // panels initialized as hidden should not start out partially visible - if (!getVisible()) - { - mVisibleAmt = 0.f; - } + // panels initialized as hidden should not start out partially visible + if (!getVisible()) + { + mVisibleAmt = 0.f; + } } void LLLayoutPanel::initFromParams(const Params& p) { - LLPanel::initFromParams(p); - setFollowsNone(); + LLPanel::initFromParams(p); + setFollowsNone(); } LLLayoutPanel::~LLLayoutPanel() { - // probably not necessary, but... - delete mResizeBar; - mResizeBar = NULL; + // probably not necessary, but... + delete mResizeBar; + mResizeBar = NULL; gFocusMgr.removeKeyboardFocusWithoutCallback(this); } F32 LLLayoutPanel::getAutoResizeFactor() const { - return mVisibleAmt * (1.f - mCollapseAmt); + return mVisibleAmt * (1.f - mCollapseAmt); } - + F32 LLLayoutPanel::getVisibleAmount() const { - return mVisibleAmt; + return mVisibleAmt; } S32 LLLayoutPanel::getLayoutDim() const { - return ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) - ? getRect().getWidth() - : getRect().getHeight())); + return ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight())); } S32 LLLayoutPanel::getTargetDim() const { - return mTargetDim; + return mTargetDim; } void LLLayoutPanel::setTargetDim(S32 value) { - LLRect new_rect(getRect()); - if (mOrientation == LLLayoutStack::HORIZONTAL) - { - new_rect.mRight = new_rect.mLeft + value; - } - else - { - new_rect.mTop = new_rect.mBottom + value; - } - setShape(new_rect, true); + LLRect new_rect(getRect()); + if (mOrientation == LLLayoutStack::HORIZONTAL) + { + new_rect.mRight = new_rect.mLeft + value; + } + else + { + new_rect.mTop = new_rect.mBottom + value; + } + setShape(new_rect, true); } S32 LLLayoutPanel::getVisibleDim() const { - F32 min_dim = getRelevantMinDim(); - return ll_round(mVisibleAmt - * (min_dim - + (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt)))); + F32 min_dim = getRelevantMinDim(); + return ll_round(mVisibleAmt + * (min_dim + + (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt)))); } - + void LLLayoutPanel::setOrientation( LLView::EOrientation orientation ) { - mOrientation = orientation; - S32 layout_dim = ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) - ? getRect().getWidth() - : getRect().getHeight())); - - if (mAutoResize == FALSE - && mUserResize == TRUE - && mMinDim == -1 ) - { - setMinDim(layout_dim); - } - mTargetDim = llmax(layout_dim, getMinDim()); + mOrientation = orientation; + S32 layout_dim = ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight())); + + if (mAutoResize == FALSE + && mUserResize == TRUE + && mMinDim == -1 ) + { + setMinDim(layout_dim); + } + mTargetDim = llmax(layout_dim, getMinDim()); } - + void LLLayoutPanel::setVisible( BOOL visible ) { - if (visible != getVisible()) - { - LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); - if (stackp) - { - stackp->mNeedsLayout = true; - } - } - LLPanel::setVisible(visible); + if (visible != getVisible()) + { + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) + { + stackp->mNeedsLayout = true; + } + } + LLPanel::setVisible(visible); } void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ ) { - if (width == getRect().getWidth() && height == getRect().getHeight() && !LLView::sForceReshape) return; - - if (!mIgnoreReshape && mAutoResize == false) - { - mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height; - LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); - if (stackp) - { - stackp->mNeedsLayout = true; - } - } - LLPanel::reshape(width, height, called_from_parent); + if (width == getRect().getWidth() && height == getRect().getHeight() && !LLView::sForceReshape) return; + + if (!mIgnoreReshape && mAutoResize == false) + { + mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height; + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) + { + stackp->mNeedsLayout = true; + } + } + LLPanel::reshape(width, height, called_from_parent); } void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user) { - LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); - if (stackp) - { - if (by_user) - { // tell layout stack to account for new shape - - // make sure that panels have already been auto resized - stackp->updateLayout(); - // now apply requested size to panel - stackp->updatePanelRect(this, new_rect); - } - stackp->mNeedsLayout = true; - } - LLPanel::handleReshape(new_rect, by_user); + LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent()); + if (stackp) + { + if (by_user) + { // tell layout stack to account for new shape + + // make sure that panels have already been auto resized + stackp->updateLayout(); + // now apply requested size to panel + stackp->updatePanelRect(this, new_rect); + } + stackp->mNeedsLayout = true; + } + LLPanel::handleReshape(new_rect, by_user); } // @@ -205,85 +205,85 @@ void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user) // LLLayoutStack::Params::Params() -: orientation("orientation"), - animate("animate", true), - clip("clip", true), - open_time_constant("open_time_constant", 0.02f), - close_time_constant("close_time_constant", 0.03f), - resize_bar_overlap("resize_bar_overlap", 1), - border_size("border_size", LLCachedControl<S32>(*LLUI::getInstance()->mSettingGroups["config"], "UIResizeBarHeight", 0)), - show_drag_handle("show_drag_handle", false), - drag_handle_first_indent("drag_handle_first_indent", 0), - drag_handle_second_indent("drag_handle_second_indent", 0), - drag_handle_thickness("drag_handle_thickness", 5), - drag_handle_shift("drag_handle_shift", 2), +: orientation("orientation"), + animate("animate", true), + clip("clip", true), + open_time_constant("open_time_constant", 0.02f), + close_time_constant("close_time_constant", 0.03f), + resize_bar_overlap("resize_bar_overlap", 1), + border_size("border_size", LLCachedControl<S32>(*LLUI::getInstance()->mSettingGroups["config"], "UIResizeBarHeight", 0)), + show_drag_handle("show_drag_handle", false), + drag_handle_first_indent("drag_handle_first_indent", 0), + drag_handle_second_indent("drag_handle_second_indent", 0), + drag_handle_thickness("drag_handle_thickness", 5), + drag_handle_shift("drag_handle_shift", 2), drag_handle_color("drag_handle_color", LLUIColorTable::instance().getColor("ResizebarBody")) { - addSynonym(border_size, "drag_handle_gap"); + addSynonym(border_size, "drag_handle_gap"); } -LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) -: LLView(p), - mPanelSpacing(p.border_size), - mOrientation(p.orientation), - mAnimate(p.animate), - mAnimatedThisFrame(false), - mNeedsLayout(true), - mClip(p.clip), - mOpenTimeConstant(p.open_time_constant), - mCloseTimeConstant(p.close_time_constant), - mResizeBarOverlap(p.resize_bar_overlap), - mShowDragHandle(p.show_drag_handle), - mDragHandleFirstIndent(p.drag_handle_first_indent), - mDragHandleSecondIndent(p.drag_handle_second_indent), - mDragHandleThickness(p.drag_handle_thickness), - mDragHandleShift(p.drag_handle_shift), +LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) +: LLView(p), + mPanelSpacing(p.border_size), + mOrientation(p.orientation), + mAnimate(p.animate), + mAnimatedThisFrame(false), + mNeedsLayout(true), + mClip(p.clip), + mOpenTimeConstant(p.open_time_constant), + mCloseTimeConstant(p.close_time_constant), + mResizeBarOverlap(p.resize_bar_overlap), + mShowDragHandle(p.show_drag_handle), + mDragHandleFirstIndent(p.drag_handle_first_indent), + mDragHandleSecondIndent(p.drag_handle_second_indent), + mDragHandleThickness(p.drag_handle_thickness), + mDragHandleShift(p.drag_handle_shift), mDragHandleColor(p.drag_handle_color()) { } LLLayoutStack::~LLLayoutStack() { - e_panel_list_t panels = mPanels; // copy list of panel pointers - mPanels.clear(); // clear so that removeChild() calls don't cause trouble - std::for_each(panels.begin(), panels.end(), DeletePointer()); + e_panel_list_t panels = mPanels; // copy list of panel pointers + mPanels.clear(); // clear so that removeChild() calls don't cause trouble + std::for_each(panels.begin(), panels.end(), DeletePointer()); } void LLLayoutStack::draw() { - updateLayout(); - - // always clip to stack itself - LLLocalClipRect clip(getLocalRect()); - for (LLLayoutPanel* panelp : mPanels) - { - if ((!panelp->getVisible() || panelp->mCollapsed) - && (panelp->mVisibleAmt < 0.001f || !mAnimate)) - { - // essentially invisible - continue; - } - // clip to layout rectangle, not bounding rectangle - LLRect clip_rect = panelp->getRect(); - // scale clipping rectangle by visible amount - if (mOrientation == HORIZONTAL) - { - clip_rect.mRight = clip_rect.mLeft + panelp->getVisibleDim(); - } - else - { - clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim(); - } - - {LLLocalClipRect clip(clip_rect, mClip); - // only force drawing invisible children if visible amount is non-zero - drawChild(panelp, 0, 0, !clip_rect.isEmpty()); - } - if (panelp->getResizeBar()->getVisible()) - { - drawChild(panelp->getResizeBar()); - } - } + updateLayout(); + + // always clip to stack itself + LLLocalClipRect clip(getLocalRect()); + for (LLLayoutPanel* panelp : mPanels) + { + if ((!panelp->getVisible() || panelp->mCollapsed) + && (panelp->mVisibleAmt < 0.001f || !mAnimate)) + { + // essentially invisible + continue; + } + // clip to layout rectangle, not bounding rectangle + LLRect clip_rect = panelp->getRect(); + // scale clipping rectangle by visible amount + if (mOrientation == HORIZONTAL) + { + clip_rect.mRight = clip_rect.mLeft + panelp->getVisibleDim(); + } + else + { + clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim(); + } + + {LLLocalClipRect clip(clip_rect, mClip); + // only force drawing invisible children if visible amount is non-zero + drawChild(panelp, 0, 0, !clip_rect.isEmpty()); + } + if (panelp->getResizeBar()->getVisible()) + { + drawChild(panelp->getResizeBar()); + } + } } void LLLayoutStack::deleteAllChildren() @@ -299,15 +299,15 @@ void LLLayoutStack::deleteAllChildren() void LLLayoutStack::removeChild(LLView* view) { - LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view)); + LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view)); - if (embedded_panelp) - { - mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); + if (embedded_panelp) + { + mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); LLView::removeChild(view); - updateFractionalSizes(); - mNeedsLayout = true; - } + updateFractionalSizes(); + mNeedsLayout = true; + } else { LLView::removeChild(view); @@ -316,215 +316,215 @@ void LLLayoutStack::removeChild(LLView* view) BOOL LLLayoutStack::postBuild() { - updateLayout(); - return TRUE; + updateLayout(); + return TRUE; } bool LLLayoutStack::addChild(LLView* child, S32 tab_group) { - LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child); - if (panelp) - { - panelp->setOrientation(mOrientation); - mPanels.push_back(panelp); - createResizeBar(panelp); - mNeedsLayout = true; - } - BOOL result = LLView::addChild(child, tab_group); - - updateFractionalSizes(); - return result; + LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child); + if (panelp) + { + panelp->setOrientation(mOrientation); + mPanels.push_back(panelp); + createResizeBar(panelp); + mNeedsLayout = true; + } + BOOL result = LLView::addChild(child, tab_group); + + updateFractionalSizes(); + return result; } void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate) { - addChild(panel); - - // panel starts off invisible (collapsed) - if (animate == ANIMATE) - { - panel->mVisibleAmt = 0.f; - panel->setVisible(TRUE); - } + addChild(panel); + + // panel starts off invisible (collapsed) + if (animate == ANIMATE) + { + panel->mVisibleAmt = 0.f; + panel->setVisible(TRUE); + } } void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed) { - LLLayoutPanel* panel_container = findEmbeddedPanel(panel); - if (!panel_container) return; + LLLayoutPanel* panel_container = findEmbeddedPanel(panel); + if (!panel_container) return; - panel_container->mCollapsed = collapsed; - mNeedsLayout = true; + panel_container->mCollapsed = collapsed; + mNeedsLayout = true; } class LLImagePanel : public LLPanel { public: - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<bool> horizontal; - Params() : horizontal("horizontal", false) {} - }; - LLImagePanel(const Params& p) : LLPanel(p), mHorizontal(p.horizontal) {} - virtual ~LLImagePanel() {} - - void draw() - { - const LLRect& parent_rect = getParent()->getRect(); - const LLRect& rect = getRect(); - LLRect clip_rect( -rect.mLeft, parent_rect.getHeight() - rect.mBottom - 2 - , parent_rect.getWidth() - rect.mLeft - (mHorizontal ? 2 : 0), -rect.mBottom); - LLLocalClipRect clip(clip_rect); - LLPanel::draw(); - } + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<bool> horizontal; + Params() : horizontal("horizontal", false) {} + }; + LLImagePanel(const Params& p) : LLPanel(p), mHorizontal(p.horizontal) {} + virtual ~LLImagePanel() {} + + void draw() + { + const LLRect& parent_rect = getParent()->getRect(); + const LLRect& rect = getRect(); + LLRect clip_rect( -rect.mLeft, parent_rect.getHeight() - rect.mBottom - 2 + , parent_rect.getWidth() - rect.mLeft - (mHorizontal ? 2 : 0), -rect.mBottom); + LLLocalClipRect clip(clip_rect); + LLPanel::draw(); + } private: - bool mHorizontal; + bool mHorizontal; }; void LLLayoutStack::updateLayout() -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if (!mNeedsLayout) return; - - bool continue_animating = animatePanels(); - F32 total_visible_fraction = 0.f; - S32 space_to_distribute = (mOrientation == HORIZONTAL) - ? getRect().getWidth() - : getRect().getHeight(); - - // first, assign minimum dimensions - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - panelp->mTargetDim = panelp->getRelevantMinDim(); - } - space_to_distribute -= panelp->getVisibleDim() + ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()); - total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); - } - - llassert(total_visible_fraction < 1.05f); - - // don't need spacing after last panel - if (!mPanels.empty()) - { - space_to_distribute += ll_round(F32(mPanelSpacing) * mPanels.back()->getVisibleAmount()); - } - - S32 remaining_space = space_to_distribute; - if (space_to_distribute > 0 && total_visible_fraction > 0.f) - { // give space proportionally to visible auto resize panels - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction); - S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute); - panelp->mTargetDim += delta; - remaining_space -= delta; - } - } - } - - // distribute any left over pixels to non-collapsed, visible panels - for (LLLayoutPanel* panelp : mPanels) - { - if (remaining_space == 0) break; - - if (panelp->mAutoResize - && !panelp->mCollapsed - && panelp->getVisible()) - { - S32 space_for_panel = remaining_space > 0 ? 1 : -1; - panelp->mTargetDim += space_for_panel; - remaining_space -= space_for_panel; - } - } - - F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight(); - - for (LLLayoutPanel* panelp : mPanels) - { - F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); - - LLRect panel_rect; - if (mOrientation == HORIZONTAL) - { - panel_rect.setLeftTopAndSize(ll_round(cur_pos), - getRect().getHeight(), - ll_round(panel_dim), - getRect().getHeight()); - } - else - { - panel_rect.setLeftTopAndSize(0, - ll_round(cur_pos), - getRect().getWidth(), - ll_round(panel_dim)); - } - - LLRect resize_bar_rect(panel_rect); - F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount(); - F32 panel_visible_dim = panelp->getVisibleDim(); - S32 panel_spacing_round = (S32)(ll_round(panel_spacing)); - - if (mOrientation == HORIZONTAL) - { - cur_pos += panel_visible_dim + panel_spacing; - - if (mShowDragHandle && panel_spacing_round > mDragHandleThickness) - { - resize_bar_rect.mLeft = panel_rect.mRight + mDragHandleShift; - resize_bar_rect.mRight = resize_bar_rect.mLeft + mDragHandleThickness; - } - else - { - resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; - resize_bar_rect.mRight = panel_rect.mRight + panel_spacing_round + mResizeBarOverlap; - } - - if (mShowDragHandle) - { - resize_bar_rect.mBottom += mDragHandleSecondIndent; - resize_bar_rect.mTop -= mDragHandleFirstIndent; - } - - } - else //VERTICAL - { - cur_pos -= panel_visible_dim + panel_spacing; - - if (mShowDragHandle && panel_spacing_round > mDragHandleThickness) - { - resize_bar_rect.mTop = panel_rect.mBottom - mDragHandleShift; - resize_bar_rect.mBottom = resize_bar_rect.mTop - mDragHandleThickness; - } - else - { - resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; - resize_bar_rect.mBottom = panel_rect.mBottom - panel_spacing_round - mResizeBarOverlap; - } - - if (mShowDragHandle) - { - resize_bar_rect.mLeft += mDragHandleFirstIndent; - resize_bar_rect.mRight -= mDragHandleSecondIndent; - } - } - - panelp->setIgnoreReshape(true); - panelp->setShape(panel_rect); - panelp->setIgnoreReshape(false); - panelp->mResizeBar->setShape(resize_bar_rect); - } - - updateResizeBarLimits(); - - // clear animation flag at end, since panel resizes will set it - // and leave it set if there is any animation in progress - mNeedsLayout = continue_animating; + if (!mNeedsLayout) return; + + bool continue_animating = animatePanels(); + F32 total_visible_fraction = 0.f; + S32 space_to_distribute = (mOrientation == HORIZONTAL) + ? getRect().getWidth() + : getRect().getHeight(); + + // first, assign minimum dimensions + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + panelp->mTargetDim = panelp->getRelevantMinDim(); + } + space_to_distribute -= panelp->getVisibleDim() + ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()); + total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); + } + + llassert(total_visible_fraction < 1.05f); + + // don't need spacing after last panel + if (!mPanels.empty()) + { + space_to_distribute += ll_round(F32(mPanelSpacing) * mPanels.back()->getVisibleAmount()); + } + + S32 remaining_space = space_to_distribute; + if (space_to_distribute > 0 && total_visible_fraction > 0.f) + { // give space proportionally to visible auto resize panels + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction); + S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute); + panelp->mTargetDim += delta; + remaining_space -= delta; + } + } + } + + // distribute any left over pixels to non-collapsed, visible panels + for (LLLayoutPanel* panelp : mPanels) + { + if (remaining_space == 0) break; + + if (panelp->mAutoResize + && !panelp->mCollapsed + && panelp->getVisible()) + { + S32 space_for_panel = remaining_space > 0 ? 1 : -1; + panelp->mTargetDim += space_for_panel; + remaining_space -= space_for_panel; + } + } + + F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight(); + + for (LLLayoutPanel* panelp : mPanels) + { + F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); + + LLRect panel_rect; + if (mOrientation == HORIZONTAL) + { + panel_rect.setLeftTopAndSize(ll_round(cur_pos), + getRect().getHeight(), + ll_round(panel_dim), + getRect().getHeight()); + } + else + { + panel_rect.setLeftTopAndSize(0, + ll_round(cur_pos), + getRect().getWidth(), + ll_round(panel_dim)); + } + + LLRect resize_bar_rect(panel_rect); + F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount(); + F32 panel_visible_dim = panelp->getVisibleDim(); + S32 panel_spacing_round = (S32)(ll_round(panel_spacing)); + + if (mOrientation == HORIZONTAL) + { + cur_pos += panel_visible_dim + panel_spacing; + + if (mShowDragHandle && panel_spacing_round > mDragHandleThickness) + { + resize_bar_rect.mLeft = panel_rect.mRight + mDragHandleShift; + resize_bar_rect.mRight = resize_bar_rect.mLeft + mDragHandleThickness; + } + else + { + resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; + resize_bar_rect.mRight = panel_rect.mRight + panel_spacing_round + mResizeBarOverlap; + } + + if (mShowDragHandle) + { + resize_bar_rect.mBottom += mDragHandleSecondIndent; + resize_bar_rect.mTop -= mDragHandleFirstIndent; + } + + } + else //VERTICAL + { + cur_pos -= panel_visible_dim + panel_spacing; + + if (mShowDragHandle && panel_spacing_round > mDragHandleThickness) + { + resize_bar_rect.mTop = panel_rect.mBottom - mDragHandleShift; + resize_bar_rect.mBottom = resize_bar_rect.mTop - mDragHandleThickness; + } + else + { + resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; + resize_bar_rect.mBottom = panel_rect.mBottom - panel_spacing_round - mResizeBarOverlap; + } + + if (mShowDragHandle) + { + resize_bar_rect.mLeft += mDragHandleFirstIndent; + resize_bar_rect.mRight -= mDragHandleSecondIndent; + } + } + + panelp->setIgnoreReshape(true); + panelp->setShape(panel_rect); + panelp->setIgnoreReshape(false); + panelp->mResizeBar->setShape(resize_bar_rect); + } + + updateResizeBarLimits(); + + // clear animation flag at end, since panel resizes will set it + // and leave it set if there is any animation in progress + mNeedsLayout = continue_animating; } // end LLLayoutStack::updateLayout void LLLayoutStack::setPanelSpacing(S32 val) @@ -538,487 +538,487 @@ void LLLayoutStack::setPanelSpacing(S32 val) LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const { - if (!panelp) return NULL; - - for (LLLayoutPanel* p : mPanels) - { - if (p == panelp) - { - return p; - } - } - return NULL; + if (!panelp) return NULL; + + for (LLLayoutPanel* p : mPanels) + { + if (p == panelp) + { + return p; + } + } + return NULL; } LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const { - LLLayoutPanel* result = NULL; - - for (LLLayoutPanel* p : mPanels) - { - if (p->getName() == name) - { - result = p; - break; - } - } - - return result; + LLLayoutPanel* result = NULL; + + for (LLLayoutPanel* p : mPanels) + { + if (p->getName() == name) + { + result = p; + break; + } + } + + return result; } void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) { - for (LLLayoutPanel* lp : mPanels) - { - if (lp->mResizeBar == NULL) - { - LLResizeBar::Params resize_params; - resize_params.name("resize"); - resize_params.resizing_view(lp); - resize_params.min_size(lp->getRelevantMinDim()); - resize_params.side((mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM); - resize_params.snapping_enabled(false); - LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); - lp->mResizeBar = resize_bar; - - if (mShowDragHandle) - { - LLPanel::Params resize_bar_bg_panel_p; - resize_bar_bg_panel_p.name = "resize_handle_bg_panel"; - resize_bar_bg_panel_p.rect = lp->mResizeBar->getLocalRect(); - resize_bar_bg_panel_p.follows.flags = FOLLOWS_ALL; - resize_bar_bg_panel_p.tab_stop = false; - resize_bar_bg_panel_p.background_visible = true; - resize_bar_bg_panel_p.bg_alpha_color = mDragHandleColor; - resize_bar_bg_panel_p.has_border = true; - resize_bar_bg_panel_p.border.border_thickness = 1; - resize_bar_bg_panel_p.border.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight"); - resize_bar_bg_panel_p.border.shadow_dark_color = LLUIColorTable::instance().getColor("ResizebarBorderDark"); - - LLPanel* resize_bar_bg_panel = LLUICtrlFactory::create<LLPanel>(resize_bar_bg_panel_p); - - LLIconCtrl::Params icon_p; - icon_p.name = "resize_handle_image"; - icon_p.rect = lp->mResizeBar->getLocalRect(); - icon_p.follows.flags = FOLLOWS_ALL; - icon_p.image = LLUI::getUIImage(mOrientation == HORIZONTAL ? "Vertical Drag Handle" : "Horizontal Drag Handle"); - resize_bar_bg_panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); - - lp->mResizeBar->addChild(resize_bar_bg_panel); - } - - /*if (mShowDragHandle) - { - LLViewBorder::Params border_params; - border_params.border_thickness = 1; - border_params.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight"); - border_params.shadow_dark_color = LLUIColorTable::instance().getColor("ResizebarBorderDark"); - - addBorder(border_params); - setBorderVisible(TRUE); - - LLImagePanel::Params image_panel; - mDragHandleImage = LLUI::getUIImage(LLResizeBar::RIGHT == mSide ? "Vertical Drag Handle" : "Horizontal Drag Handle"); - image_panel.bg_alpha_image = mDragHandleImage; - image_panel.background_visible = true; - image_panel.horizontal = (LLResizeBar::BOTTOM == mSide); - mImagePanel = LLUICtrlFactory::create<LLImagePanel>(image_panel); - setImagePanel(mImagePanel); - }*/ - - //if (mShowDragHandle) - //{ - // setBackgroundVisible(TRUE); - // setTransparentColor(LLUIColorTable::instance().getColor("ResizebarBody")); - //} - - /*if (mShowDragHandle) - { - S32 image_width = mDragHandleImage->getTextureWidth(); - S32 image_height = mDragHandleImage->getTextureHeight(); - const LLRect& panel_rect = getRect(); - S32 image_left = (panel_rect.getWidth() - image_width) / 2 - 1; - S32 image_bottom = (panel_rect.getHeight() - image_height) / 2; - mImagePanel->setRect(LLRect(image_left, image_bottom + image_height, image_left + image_width, image_bottom)); - }*/ - LLView::addChild(resize_bar, 0); - } - } - // bring all resize bars to the front so that they are clickable even over the panels - // with a bit of overlap - for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) - { - LLResizeBar* resize_barp = (*panel_it)->mResizeBar; - sendChildToFront(resize_barp); - } + for (LLLayoutPanel* lp : mPanels) + { + if (lp->mResizeBar == NULL) + { + LLResizeBar::Params resize_params; + resize_params.name("resize"); + resize_params.resizing_view(lp); + resize_params.min_size(lp->getRelevantMinDim()); + resize_params.side((mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM); + resize_params.snapping_enabled(false); + LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params); + lp->mResizeBar = resize_bar; + + if (mShowDragHandle) + { + LLPanel::Params resize_bar_bg_panel_p; + resize_bar_bg_panel_p.name = "resize_handle_bg_panel"; + resize_bar_bg_panel_p.rect = lp->mResizeBar->getLocalRect(); + resize_bar_bg_panel_p.follows.flags = FOLLOWS_ALL; + resize_bar_bg_panel_p.tab_stop = false; + resize_bar_bg_panel_p.background_visible = true; + resize_bar_bg_panel_p.bg_alpha_color = mDragHandleColor; + resize_bar_bg_panel_p.has_border = true; + resize_bar_bg_panel_p.border.border_thickness = 1; + resize_bar_bg_panel_p.border.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight"); + resize_bar_bg_panel_p.border.shadow_dark_color = LLUIColorTable::instance().getColor("ResizebarBorderDark"); + + LLPanel* resize_bar_bg_panel = LLUICtrlFactory::create<LLPanel>(resize_bar_bg_panel_p); + + LLIconCtrl::Params icon_p; + icon_p.name = "resize_handle_image"; + icon_p.rect = lp->mResizeBar->getLocalRect(); + icon_p.follows.flags = FOLLOWS_ALL; + icon_p.image = LLUI::getUIImage(mOrientation == HORIZONTAL ? "Vertical Drag Handle" : "Horizontal Drag Handle"); + resize_bar_bg_panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); + + lp->mResizeBar->addChild(resize_bar_bg_panel); + } + + /*if (mShowDragHandle) + { + LLViewBorder::Params border_params; + border_params.border_thickness = 1; + border_params.highlight_light_color = LLUIColorTable::instance().getColor("ResizebarBorderLight"); + border_params.shadow_dark_color = LLUIColorTable::instance().getColor("ResizebarBorderDark"); + + addBorder(border_params); + setBorderVisible(TRUE); + + LLImagePanel::Params image_panel; + mDragHandleImage = LLUI::getUIImage(LLResizeBar::RIGHT == mSide ? "Vertical Drag Handle" : "Horizontal Drag Handle"); + image_panel.bg_alpha_image = mDragHandleImage; + image_panel.background_visible = true; + image_panel.horizontal = (LLResizeBar::BOTTOM == mSide); + mImagePanel = LLUICtrlFactory::create<LLImagePanel>(image_panel); + setImagePanel(mImagePanel); + }*/ + + //if (mShowDragHandle) + //{ + // setBackgroundVisible(TRUE); + // setTransparentColor(LLUIColorTable::instance().getColor("ResizebarBody")); + //} + + /*if (mShowDragHandle) + { + S32 image_width = mDragHandleImage->getTextureWidth(); + S32 image_height = mDragHandleImage->getTextureHeight(); + const LLRect& panel_rect = getRect(); + S32 image_left = (panel_rect.getWidth() - image_width) / 2 - 1; + S32 image_bottom = (panel_rect.getHeight() - image_height) / 2; + mImagePanel->setRect(LLRect(image_left, image_bottom + image_height, image_left + image_width, image_bottom)); + }*/ + LLView::addChild(resize_bar, 0); + } + } + // bring all resize bars to the front so that they are clickable even over the panels + // with a bit of overlap + for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + LLResizeBar* resize_barp = (*panel_it)->mResizeBar; + sendChildToFront(resize_barp); + } } // update layout stack animations, etc. once per frame // NOTE: we use this to size world view based on animating UI, *before* we draw the UI // we might still need to call updateLayout during UI draw phase, in case UI elements // are resizing themselves dynamically -//static +//static void LLLayoutStack::updateClass() { - for (auto& layout : instance_snapshot()) - { - layout.updateLayout(); - layout.mAnimatedThisFrame = false; - } + for (auto& layout : instance_snapshot()) + { + layout.updateLayout(); + layout.mAnimatedThisFrame = false; + } } void LLLayoutStack::updateFractionalSizes() { - F32 total_resizable_dim = 0.f; - - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - total_resizable_dim += llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); - } - } - - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); - panelp->mFractionalSize = panel_resizable_dim > 0.f - ? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) - : MIN_FRACTIONAL_SIZE; - llassert(!llisnan(panelp->mFractionalSize)); - } - } - - normalizeFractionalSizes(); + F32 total_resizable_dim = 0.f; + + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + total_resizable_dim += llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); + } + } + + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim())); + panelp->mFractionalSize = panel_resizable_dim > 0.f + ? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) + : MIN_FRACTIONAL_SIZE; + llassert(!llisnan(panelp->mFractionalSize)); + } + } + + normalizeFractionalSizes(); } void LLLayoutStack::normalizeFractionalSizes() { - S32 num_auto_resize_panels = 0; - F32 total_fractional_size = 0.f; - - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - total_fractional_size += panelp->mFractionalSize; - num_auto_resize_panels++; - } - } - - if (total_fractional_size == 0.f) - { // equal distribution - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels; - } - } - } - else - { // renormalize - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->mAutoResize) - { - panelp->mFractionalSize /= total_fractional_size; - } - } - } + S32 num_auto_resize_panels = 0; + F32 total_fractional_size = 0.f; + + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + total_fractional_size += panelp->mFractionalSize; + num_auto_resize_panels++; + } + } + + if (total_fractional_size == 0.f) + { // equal distribution + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels; + } + } + } + else + { // renormalize + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->mAutoResize) + { + panelp->mFractionalSize /= total_fractional_size; + } + } + } } bool LLLayoutStack::animatePanels() { - bool continue_animating = false; - - // - // animate visibility - // - for (LLLayoutPanel* panelp : mPanels) - { - if (panelp->getVisible()) - { - if (mAnimate && panelp->mVisibleAmt < 1.f) - { - if (!mAnimatedThisFrame) - { - panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLSmoothInterpolation::getInterpolant(mOpenTimeConstant)); - if (panelp->mVisibleAmt > 0.99f) - { - panelp->mVisibleAmt = 1.f; - } - } - - mAnimatedThisFrame = true; - continue_animating = true; - } - else - { - if (panelp->mVisibleAmt != 1.f) - { - panelp->mVisibleAmt = 1.f; - mAnimatedThisFrame = true; - } - } - } - else // not visible - { - if (mAnimate && panelp->mVisibleAmt > 0.f) - { - if (!mAnimatedThisFrame) - { - panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); - if (panelp->mVisibleAmt < 0.001f) - { - panelp->mVisibleAmt = 0.f; - } - } - - continue_animating = true; - mAnimatedThisFrame = true; - } - else - { - if (panelp->mVisibleAmt != 0.f) - { - panelp->mVisibleAmt = 0.f; - mAnimatedThisFrame = true; - } - } - } - - F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f; - if (panelp->mCollapseAmt != collapse_state) - { - if (mAnimate) - { - if (!mAnimatedThisFrame) - { - panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); - } - - if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) - { - panelp->mCollapseAmt = collapse_state; - } - - mAnimatedThisFrame = true; - continue_animating = true; - } - else - { - panelp->mCollapseAmt = collapse_state; - mAnimatedThisFrame = true; - } - } - } - - if (mAnimatedThisFrame) mNeedsLayout = true; - return continue_animating; + bool continue_animating = false; + + // + // animate visibility + // + for (LLLayoutPanel* panelp : mPanels) + { + if (panelp->getVisible()) + { + if (mAnimate && panelp->mVisibleAmt < 1.f) + { + if (!mAnimatedThisFrame) + { + panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLSmoothInterpolation::getInterpolant(mOpenTimeConstant)); + if (panelp->mVisibleAmt > 0.99f) + { + panelp->mVisibleAmt = 1.f; + } + } + + mAnimatedThisFrame = true; + continue_animating = true; + } + else + { + if (panelp->mVisibleAmt != 1.f) + { + panelp->mVisibleAmt = 1.f; + mAnimatedThisFrame = true; + } + } + } + else // not visible + { + if (mAnimate && panelp->mVisibleAmt > 0.f) + { + if (!mAnimatedThisFrame) + { + panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); + if (panelp->mVisibleAmt < 0.001f) + { + panelp->mVisibleAmt = 0.f; + } + } + + continue_animating = true; + mAnimatedThisFrame = true; + } + else + { + if (panelp->mVisibleAmt != 0.f) + { + panelp->mVisibleAmt = 0.f; + mAnimatedThisFrame = true; + } + } + } + + F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f; + if (panelp->mCollapseAmt != collapse_state) + { + if (mAnimate) + { + if (!mAnimatedThisFrame) + { + panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); + } + + if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) + { + panelp->mCollapseAmt = collapse_state; + } + + mAnimatedThisFrame = true; + continue_animating = true; + } + else + { + panelp->mCollapseAmt = collapse_state; + mAnimatedThisFrame = true; + } + } + } + + if (mAnimatedThisFrame) mNeedsLayout = true; + return continue_animating; } void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect ) { - S32 new_dim = (mOrientation == HORIZONTAL) - ? new_rect.getWidth() - : new_rect.getHeight(); - S32 delta_panel_dim = new_dim - resized_panel->getVisibleDim(); - if (delta_panel_dim == 0) return; - - F32 total_visible_fraction = 0.f; - F32 delta_auto_resize_headroom = 0.f; - F32 old_auto_resize_headroom = 0.f; - - LLLayoutPanel* other_resize_panel = NULL; - LLLayoutPanel* following_panel = NULL; - - BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... - { - if (panelp->mAutoResize) - { - old_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); - if (panelp->getVisible() && !panelp->mCollapsed) - { - total_visible_fraction += panelp->mFractionalSize; - } - } - - if (panelp == resized_panel) - { - other_resize_panel = following_panel; - } - - if (panelp->getVisible() && !panelp->mCollapsed) - { - following_panel = panelp; - } - } - - if (resized_panel->mAutoResize) - { - if (!other_resize_panel || !other_resize_panel->mAutoResize) - { - delta_auto_resize_headroom += delta_panel_dim; - } - } - else - { - if (!other_resize_panel || other_resize_panel->mAutoResize) - { - delta_auto_resize_headroom -= delta_panel_dim; - } - } - - F32 fraction_given_up = 0.f; - F32 fraction_remaining = 1.f; - F32 new_auto_resize_headroom = old_auto_resize_headroom + delta_auto_resize_headroom; - - enum - { - BEFORE_RESIZED_PANEL, - RESIZED_PANEL, - NEXT_PANEL, - AFTER_RESIZED_PANEL - } which_panel = BEFORE_RESIZED_PANEL; - - for (LLLayoutPanel* panelp : mPanels) - { - if (!panelp->getVisible() || panelp->mCollapsed) - { - if (panelp->mAutoResize) - { - fraction_remaining -= panelp->mFractionalSize; - } - continue; - } - - if (panelp == resized_panel) - { - which_panel = RESIZED_PANEL; - } - - switch(which_panel) - { - case BEFORE_RESIZED_PANEL: - if (panelp->mAutoResize) - { // freeze current size as fraction of overall auto_resize space - F32 fractional_adjustment_factor = new_auto_resize_headroom == 0.f - ? 1.f - : old_auto_resize_headroom / new_auto_resize_headroom; - F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor, - MIN_FRACTIONAL_SIZE, - MAX_FRACTIONAL_SIZE); - fraction_given_up -= new_fractional_size - panelp->mFractionalSize; - fraction_remaining -= panelp->mFractionalSize; - panelp->mFractionalSize = new_fractional_size; - llassert(!llisnan(panelp->mFractionalSize)); - } - else - { - // leave non auto-resize panels alone - } - break; - case RESIZED_PANEL: - if (panelp->mAutoResize) - { // freeze new size as fraction - F32 new_fractional_size = (new_auto_resize_headroom == 0.f) - ? MAX_FRACTIONAL_SIZE - : llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / new_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); - fraction_given_up -= new_fractional_size - panelp->mFractionalSize; - fraction_remaining -= panelp->mFractionalSize; - panelp->mFractionalSize = new_fractional_size; - llassert(!llisnan(panelp->mFractionalSize)); - } - else - { // freeze new size as original size - panelp->mTargetDim = new_dim; - } - which_panel = NEXT_PANEL; - break; - case NEXT_PANEL: - if (panelp->mAutoResize) - { - fraction_remaining -= panelp->mFractionalSize; - if (resized_panel->mAutoResize) - { - panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); - fraction_given_up = 0.f; - } - else - { - if (new_auto_resize_headroom < 1.f) - { - new_auto_resize_headroom = 1.f; - } - - F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom) - / new_auto_resize_headroom, - MIN_FRACTIONAL_SIZE, - MAX_FRACTIONAL_SIZE); - fraction_given_up -= new_fractional_size - panelp->mFractionalSize; - panelp->mFractionalSize = new_fractional_size; - } - } - else - { - panelp->mTargetDim -= delta_panel_dim; - } - which_panel = AFTER_RESIZED_PANEL; - break; - case AFTER_RESIZED_PANEL: - if (panelp->mAutoResize && fraction_given_up != 0.f) - { - panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up, - MIN_FRACTIONAL_SIZE, - MAX_FRACTIONAL_SIZE); - } - break; - default: - break; - } - } - updateLayout(); - //normalizeFractionalSizes(); + S32 new_dim = (mOrientation == HORIZONTAL) + ? new_rect.getWidth() + : new_rect.getHeight(); + S32 delta_panel_dim = new_dim - resized_panel->getVisibleDim(); + if (delta_panel_dim == 0) return; + + F32 total_visible_fraction = 0.f; + F32 delta_auto_resize_headroom = 0.f; + F32 old_auto_resize_headroom = 0.f; + + LLLayoutPanel* other_resize_panel = NULL; + LLLayoutPanel* following_panel = NULL; + + BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... + { + if (panelp->mAutoResize) + { + old_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim()); + if (panelp->getVisible() && !panelp->mCollapsed) + { + total_visible_fraction += panelp->mFractionalSize; + } + } + + if (panelp == resized_panel) + { + other_resize_panel = following_panel; + } + + if (panelp->getVisible() && !panelp->mCollapsed) + { + following_panel = panelp; + } + } + + if (resized_panel->mAutoResize) + { + if (!other_resize_panel || !other_resize_panel->mAutoResize) + { + delta_auto_resize_headroom += delta_panel_dim; + } + } + else + { + if (!other_resize_panel || other_resize_panel->mAutoResize) + { + delta_auto_resize_headroom -= delta_panel_dim; + } + } + + F32 fraction_given_up = 0.f; + F32 fraction_remaining = 1.f; + F32 new_auto_resize_headroom = old_auto_resize_headroom + delta_auto_resize_headroom; + + enum + { + BEFORE_RESIZED_PANEL, + RESIZED_PANEL, + NEXT_PANEL, + AFTER_RESIZED_PANEL + } which_panel = BEFORE_RESIZED_PANEL; + + for (LLLayoutPanel* panelp : mPanels) + { + if (!panelp->getVisible() || panelp->mCollapsed) + { + if (panelp->mAutoResize) + { + fraction_remaining -= panelp->mFractionalSize; + } + continue; + } + + if (panelp == resized_panel) + { + which_panel = RESIZED_PANEL; + } + + switch(which_panel) + { + case BEFORE_RESIZED_PANEL: + if (panelp->mAutoResize) + { // freeze current size as fraction of overall auto_resize space + F32 fractional_adjustment_factor = new_auto_resize_headroom == 0.f + ? 1.f + : old_auto_resize_headroom / new_auto_resize_headroom; + F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); + fraction_given_up -= new_fractional_size - panelp->mFractionalSize; + fraction_remaining -= panelp->mFractionalSize; + panelp->mFractionalSize = new_fractional_size; + llassert(!llisnan(panelp->mFractionalSize)); + } + else + { + // leave non auto-resize panels alone + } + break; + case RESIZED_PANEL: + if (panelp->mAutoResize) + { // freeze new size as fraction + F32 new_fractional_size = (new_auto_resize_headroom == 0.f) + ? MAX_FRACTIONAL_SIZE + : llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / new_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); + fraction_given_up -= new_fractional_size - panelp->mFractionalSize; + fraction_remaining -= panelp->mFractionalSize; + panelp->mFractionalSize = new_fractional_size; + llassert(!llisnan(panelp->mFractionalSize)); + } + else + { // freeze new size as original size + panelp->mTargetDim = new_dim; + } + which_panel = NEXT_PANEL; + break; + case NEXT_PANEL: + if (panelp->mAutoResize) + { + fraction_remaining -= panelp->mFractionalSize; + if (resized_panel->mAutoResize) + { + panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); + fraction_given_up = 0.f; + } + else + { + if (new_auto_resize_headroom < 1.f) + { + new_auto_resize_headroom = 1.f; + } + + F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom) + / new_auto_resize_headroom, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); + fraction_given_up -= new_fractional_size - panelp->mFractionalSize; + panelp->mFractionalSize = new_fractional_size; + } + } + else + { + panelp->mTargetDim -= delta_panel_dim; + } + which_panel = AFTER_RESIZED_PANEL; + break; + case AFTER_RESIZED_PANEL: + if (panelp->mAutoResize && fraction_given_up != 0.f) + { + panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up, + MIN_FRACTIONAL_SIZE, + MAX_FRACTIONAL_SIZE); + } + break; + default: + break; + } + } + updateLayout(); + //normalizeFractionalSizes(); } void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) { - mNeedsLayout = true; - LLView::reshape(width, height, called_from_parent); + mNeedsLayout = true; + LLView::reshape(width, height, called_from_parent); } void LLLayoutStack::updateResizeBarLimits() { - LLLayoutPanel* previous_visible_panelp{ nullptr }; - BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... - { - if (!visible_panelp->getVisible() || visible_panelp->mCollapsed) - { - visible_panelp->mResizeBar->setVisible(FALSE); - continue; - } - - // toggle resize bars based on panel visibility, resizability, etc - if (previous_visible_panelp - && (visible_panelp->mUserResize || previous_visible_panelp->mUserResize) // one of the pair is user resizable - && (visible_panelp->mAutoResize || visible_panelp->mUserResize) // current panel is resizable - && (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize)) // previous panel is resizable - { - visible_panelp->mResizeBar->setVisible(TRUE); - S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim(); - visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(), - visible_panelp->getVisibleDim() + previous_panel_headroom); - } - else - { - visible_panelp->mResizeBar->setVisible(FALSE); - } - - previous_visible_panelp = visible_panelp; - } + LLLayoutPanel* previous_visible_panelp{ nullptr }; + BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... + { + if (!visible_panelp->getVisible() || visible_panelp->mCollapsed) + { + visible_panelp->mResizeBar->setVisible(FALSE); + continue; + } + + // toggle resize bars based on panel visibility, resizability, etc + if (previous_visible_panelp + && (visible_panelp->mUserResize || previous_visible_panelp->mUserResize) // one of the pair is user resizable + && (visible_panelp->mAutoResize || visible_panelp->mUserResize) // current panel is resizable + && (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize)) // previous panel is resizable + { + visible_panelp->mResizeBar->setVisible(TRUE); + S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim(); + visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(), + visible_panelp->getVisibleDim() + previous_panel_headroom); + } + else + { + visible_panelp->mResizeBar->setVisible(FALSE); + } + + previous_visible_panelp = visible_panelp; + } } diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 000b919ae7..884850285a 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -1,4 +1,4 @@ -/** +/** * @file lllayoutstack.h * @author Richard Nelson * @brief LLLayout class - dynamic stacking of UI elements @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Reshasearch, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,98 +39,98 @@ class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack> { public: - struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry> - { - LLSINGLETON_EMPTY_CTOR(LayoutStackRegistry); - }; - - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Mandatory<EOrientation> orientation; - Optional<S32> border_size; - Optional<bool> animate, - clip; - Optional<F32> open_time_constant, - close_time_constant; - Optional<S32> resize_bar_overlap; - Optional<bool> show_drag_handle; - Optional<S32> drag_handle_first_indent; - Optional<S32> drag_handle_second_indent; - Optional<S32> drag_handle_thickness; - Optional<S32> drag_handle_shift; + struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry> + { + LLSINGLETON_EMPTY_CTOR(LayoutStackRegistry); + }; + + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Mandatory<EOrientation> orientation; + Optional<S32> border_size; + Optional<bool> animate, + clip; + Optional<F32> open_time_constant, + close_time_constant; + Optional<S32> resize_bar_overlap; + Optional<bool> show_drag_handle; + Optional<S32> drag_handle_first_indent; + Optional<S32> drag_handle_second_indent; + Optional<S32> drag_handle_thickness; + Optional<S32> drag_handle_shift; Optional<LLUIColor> drag_handle_color; - Params(); - }; + Params(); + }; - typedef LayoutStackRegistry child_registry_t; + typedef LayoutStackRegistry child_registry_t; - virtual ~LLLayoutStack(); + virtual ~LLLayoutStack(); - /*virtual*/ void draw(); + /*virtual*/ void draw(); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild(LLView*); - /*virtual*/ BOOL postBuild(); - /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void removeChild(LLView*); + /*virtual*/ BOOL postBuild(); + /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); - typedef enum e_animate - { - NO_ANIMATE, - ANIMATE - } EAnimate; + typedef enum e_animate + { + NO_ANIMATE, + ANIMATE + } EAnimate; - void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE); - void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE); - S32 getNumPanels() { return mPanels.size(); } + void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE); + void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE); + S32 getNumPanels() { return mPanels.size(); } - void updateLayout(); + void updateLayout(); - S32 getPanelSpacing() const { return mPanelSpacing; } + S32 getPanelSpacing() const { return mPanelSpacing; } void setPanelSpacing(S32 val); - - static void updateClass(); + + static void updateClass(); protected: - LLLayoutStack(const Params&); - friend class LLUICtrlFactory; - friend class LLLayoutPanel; + LLLayoutStack(const Params&); + friend class LLUICtrlFactory; + friend class LLLayoutPanel; private: - void updateResizeBarLimits(); - bool animatePanels(); - void createResizeBar(LLLayoutPanel* panel); - - const EOrientation mOrientation; - - typedef std::vector<LLLayoutPanel*> e_panel_list_t; - e_panel_list_t mPanels; - - LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const; - LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const; - void updateFractionalSizes(); - void normalizeFractionalSizes(); - void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect ); - - S32 mPanelSpacing; - - // true if we already applied animation this frame - bool mAnimatedThisFrame; - bool mAnimate; - bool mClip; - F32 mOpenTimeConstant; - F32 mCloseTimeConstant; - bool mNeedsLayout; - S32 mResizeBarOverlap; - bool mShowDragHandle; - S32 mDragHandleFirstIndent; - S32 mDragHandleSecondIndent; - S32 mDragHandleThickness; - S32 mDragHandleShift; + void updateResizeBarLimits(); + bool animatePanels(); + void createResizeBar(LLLayoutPanel* panel); + + const EOrientation mOrientation; + + typedef std::vector<LLLayoutPanel*> e_panel_list_t; + e_panel_list_t mPanels; + + LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const; + LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const; + void updateFractionalSizes(); + void normalizeFractionalSizes(); + void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect ); + + S32 mPanelSpacing; + + // true if we already applied animation this frame + bool mAnimatedThisFrame; + bool mAnimate; + bool mClip; + F32 mOpenTimeConstant; + F32 mCloseTimeConstant; + bool mNeedsLayout; + S32 mResizeBarOverlap; + bool mShowDragHandle; + S32 mDragHandleFirstIndent; + S32 mDragHandleSecondIndent; + S32 mDragHandleThickness; + S32 mDragHandleShift; LLUIColor mDragHandleColor; }; // end class LLLayoutStack @@ -140,76 +140,76 @@ class LLLayoutPanel : public LLPanel friend class LLLayoutStack; friend class LLUICtrlFactory; public: - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<S32> expanded_min_dim, - min_dim; - Optional<bool> user_resize, - auto_resize; + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<S32> expanded_min_dim, + min_dim; + Optional<bool> user_resize, + auto_resize; + + Params(); + }; + + ~LLLayoutPanel(); + + void initFromParams(const Params& p); + + void handleReshape(const LLRect& new_rect, bool by_user); - Params(); - }; + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - ~LLLayoutPanel(); - void initFromParams(const Params& p); + void setVisible(BOOL visible); - void handleReshape(const LLRect& new_rect, bool by_user); + S32 getLayoutDim() const; + S32 getTargetDim() const; + void setTargetDim(S32 value); + S32 getMinDim() const { return llmax(0, mMinDim); } + void setMinDim(S32 value) { mMinDim = value; } - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - + S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); } + void setExpandedMinDim(S32 value) { mExpandedMinDim = value; } - void setVisible(BOOL visible); + S32 getRelevantMinDim() const + { + S32 min_dim = mMinDim; - S32 getLayoutDim() const; - S32 getTargetDim() const; - void setTargetDim(S32 value); - S32 getMinDim() const { return llmax(0, mMinDim); } - void setMinDim(S32 value) { mMinDim = value; } + if (!mCollapsed) + { + min_dim = getExpandedMinDim(); + } - S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); } - void setExpandedMinDim(S32 value) { mExpandedMinDim = value; } - - S32 getRelevantMinDim() const - { - S32 min_dim = mMinDim; - - if (!mCollapsed) - { - min_dim = getExpandedMinDim(); - } - - return min_dim; - } + return min_dim; + } - F32 getAutoResizeFactor() const; - F32 getVisibleAmount() const; - S32 getVisibleDim() const; - LLResizeBar* getResizeBar() { return mResizeBar; } + F32 getAutoResizeFactor() const; + F32 getVisibleAmount() const; + S32 getVisibleDim() const; + LLResizeBar* getResizeBar() { return mResizeBar; } - bool isCollapsed() const { return mCollapsed;} + bool isCollapsed() const { return mCollapsed;} - void setOrientation(LLView::EOrientation orientation); - void storeOriginalDim(); + void setOrientation(LLView::EOrientation orientation); + void storeOriginalDim(); - void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; } + void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; } protected: - LLLayoutPanel(const Params& p); - - const bool mAutoResize; - const bool mUserResize; - - S32 mExpandedMinDim; - S32 mMinDim; - bool mCollapsed; - F32 mVisibleAmt; - F32 mCollapseAmt; - F32 mFractionalSize; - S32 mTargetDim; - bool mIgnoreReshape; - LLView::EOrientation mOrientation; - class LLResizeBar* mResizeBar; + LLLayoutPanel(const Params& p); + + const bool mAutoResize; + const bool mUserResize; + + S32 mExpandedMinDim; + S32 mMinDim; + bool mCollapsed; + F32 mVisibleAmt; + F32 mCollapseAmt; + F32 mFractionalSize; + S32 mTargetDim; + bool mIgnoreReshape; + LLView::EOrientation mOrientation; + class LLResizeBar* mResizeBar; }; diff --git a/indra/llui/lllazyvalue.h b/indra/llui/lllazyvalue.h index 0fc95d9efa..622e69ce95 100644 --- a/indra/llui/lllazyvalue.h +++ b/indra/llui/lllazyvalue.h @@ -1,4 +1,4 @@ -/** +/** * @file lllazyvalue.h * @brief generic functor/value abstraction for lazy evaluation of a value * parsing construction parameters from xml and LLSD @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,48 +35,48 @@ template<typename T> class LLLazyValue { public: - typedef typename boost::add_reference<typename boost::add_const<T>::type>::type T_const_ref; - typedef typename boost::function<T_const_ref (void)> function_type; + typedef typename boost::add_reference<typename boost::add_const<T>::type>::type T_const_ref; + typedef typename boost::function<T_const_ref (void)> function_type; public: - LLLazyValue(const function_type& value) - : mValueGetter(value) - {} - LLLazyValue(T_const_ref value) - : mValue(value) - {} - LLLazyValue() - : mValue() - {} + LLLazyValue(const function_type& value) + : mValueGetter(value) + {} + LLLazyValue(T_const_ref value) + : mValue(value) + {} + LLLazyValue() + : mValue() + {} - void set(const LLLazyValue& val) - { - mValueGetter = val.mValueGetter; - } + void set(const LLLazyValue& val) + { + mValueGetter = val.mValueGetter; + } - void set(T_const_ref val) - { - mValue = val; - mValueGetter = NULL; - } + void set(T_const_ref val) + { + mValue = val; + mValueGetter = NULL; + } - T_const_ref get() const - { - if (!mValueGetter.empty()) - { - return mValueGetter(); - } - return mValue; - } + T_const_ref get() const + { + if (!mValueGetter.empty()) + { + return mValueGetter(); + } + return mValue; + } - bool isUsingFunction() const - { - return mValueGetter != NULL; - } + bool isUsingFunction() const + { + return mValueGetter != NULL; + } private: - function_type mValueGetter; - T mValue; + function_type mValueGetter; + T mValue; }; #endif // LL_LAZY_VALUE_H diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 453fa29e7c..6dc68b4de2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lllineeditor.cpp * @brief LLLineEditor base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,7 +27,7 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #define LLLINEEDITOR_CPP #include "lllineeditor.h" @@ -61,12 +61,12 @@ // Constants // -const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds -const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing -const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing +const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds +const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing +const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing const F32 AUTO_SCROLL_TIME = 0.05f; -const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval? -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval? +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET @@ -74,109 +74,115 @@ static LLDefaultChildRegistry::Register<LLLineEditor> r1("line_editor"); // Compiler optimization, generate extern template template class LLLineEditor* LLView::getChild<class LLLineEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Member functions // LLLineEditor::Params::Params() -: max_length(""), +: max_length(""), keystroke_callback("keystroke_callback"), - prevalidate_callback("prevalidate_callback"), - prevalidate_input_callback("prevalidate_input_callback"), - background_image("background_image"), - background_image_disabled("background_image_disabled"), - background_image_focused("background_image_focused"), - bg_image_always_focused("bg_image_always_focused", false), - show_label_focused("show_label_focused", false), - select_on_focus("select_on_focus", false), - revert_on_esc("revert_on_esc", true), - spellcheck("spellcheck", false), - commit_on_focus_lost("commit_on_focus_lost", true), - ignore_tab("ignore_tab", true), - is_password("is_password", false), - cursor_color("cursor_color"), - use_bg_color("use_bg_color", false), - bg_color("bg_color"), - text_color("text_color"), - text_readonly_color("text_readonly_color"), - text_tentative_color("text_tentative_color"), - highlight_color("highlight_color"), - preedit_bg_color("preedit_bg_color"), - border(""), - bg_visible("bg_visible"), - text_pad_left("text_pad_left"), - text_pad_right("text_pad_right"), - default_text("default_text") -{ - changeDefault(mouse_opaque, true); - addSynonym(select_on_focus, "select_all_on_focus_received"); - addSynonym(border, "border"); - addSynonym(label, "watermark_text"); - addSynonym(max_length.chars, "max_length"); + prevalidator("prevalidator"), + input_prevalidator("input_prevalidator"), + background_image("background_image"), + background_image_disabled("background_image_disabled"), + background_image_focused("background_image_focused"), + bg_image_always_focused("bg_image_always_focused", false), + show_label_focused("show_label_focused", false), + select_on_focus("select_on_focus", false), + revert_on_esc("revert_on_esc", true), + spellcheck("spellcheck", false), + commit_on_focus_lost("commit_on_focus_lost", true), + ignore_tab("ignore_tab", true), + is_password("is_password", false), + allow_emoji("allow_emoji", true), + cursor_color("cursor_color"), + use_bg_color("use_bg_color", false), + bg_color("bg_color"), + text_color("text_color"), + text_readonly_color("text_readonly_color"), + text_tentative_color("text_tentative_color"), + highlight_color("highlight_color"), + preedit_bg_color("preedit_bg_color"), + border(""), + bg_visible("bg_visible"), + text_pad_left("text_pad_left"), + text_pad_right("text_pad_right"), + default_text("default_text") +{ + changeDefault(mouse_opaque, true); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(input_prevalidator, "prevalidate_input_callback"); + addSynonym(select_on_focus, "select_all_on_focus_received"); + addSynonym(border, "border"); + addSynonym(label, "watermark_text"); + addSynonym(max_length.chars, "max_length"); } LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) -: LLUICtrl(p), - mMaxLengthBytes(p.max_length.bytes), - mMaxLengthChars(p.max_length.chars), - mCursorPos( 0 ), - mScrollHPos( 0 ), - mTextPadLeft(p.text_pad_left), - mTextPadRight(p.text_pad_right), - mTextLeftEdge(0), // computed in updateTextPadding() below - mTextRightEdge(0), // computed in updateTextPadding() below - mCommitOnFocusLost( p.commit_on_focus_lost ), - mKeystrokeOnEsc(FALSE), - mRevertOnEsc( p.revert_on_esc ), - mKeystrokeCallback( p.keystroke_callback() ), - mIsSelecting( FALSE ), - mSelectionStart( 0 ), - mSelectionEnd( 0 ), - mLastSelectionX(-1), - mLastSelectionY(-1), - mLastSelectionStart(-1), - mLastSelectionEnd(-1), - mBorderThickness( 0 ), - mIgnoreArrowKeys( FALSE ), - mIgnoreTab( p.ignore_tab ), - mDrawAsterixes( p.is_password ), - mSpellCheck( p.spellcheck ), - mSpellCheckStart(-1), - mSpellCheckEnd(-1), - mSelectAllonFocusReceived( p.select_on_focus ), - mSelectAllonCommit( TRUE ), - mPassDelete(FALSE), - mReadOnly(FALSE), - mBgImage( p.background_image ), - mBgImageDisabled( p.background_image_disabled ), - mBgImageFocused( p.background_image_focused ), - mShowImageFocused( p.bg_image_always_focused ), - mShowLabelFocused( p.show_label_focused ), - mUseBgColor(p.use_bg_color), - mHaveHistory(FALSE), - mReplaceNewlinesWithSpaces( TRUE ), - mLabel(p.label), - mCursorColor(p.cursor_color()), - mBgColor(p.bg_color()), - mFgColor(p.text_color()), - mReadOnlyFgColor(p.text_readonly_color()), - mTentativeFgColor(p.text_tentative_color()), - mHighlightColor(p.highlight_color()), - mPreeditBgColor(p.preedit_bg_color()), - mGLFont(p.font), - mContextMenuHandle(), +: LLUICtrl(p), + mMaxLengthBytes(p.max_length.bytes), + mMaxLengthChars(p.max_length.chars), + mCursorPos( 0 ), + mScrollHPos( 0 ), + mTextPadLeft(p.text_pad_left), + mTextPadRight(p.text_pad_right), + mTextLeftEdge(0), // computed in updateTextPadding() below + mTextRightEdge(0), // computed in updateTextPadding() below + mCommitOnFocusLost( p.commit_on_focus_lost ), + mKeystrokeOnEsc(FALSE), + mRevertOnEsc( p.revert_on_esc ), + mKeystrokeCallback( p.keystroke_callback() ), + mIsSelecting( FALSE ), + mSelectionStart( 0 ), + mSelectionEnd( 0 ), + mLastSelectionX(-1), + mLastSelectionY(-1), + mLastSelectionStart(-1), + mLastSelectionEnd(-1), + mBorderThickness( 0 ), + mIgnoreArrowKeys( FALSE ), + mIgnoreTab( p.ignore_tab ), + mDrawAsterixes( p.is_password ), + mAllowEmoji( p.allow_emoji ), + mSpellCheck( p.spellcheck ), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), + mSelectAllonFocusReceived( p.select_on_focus ), + mSelectAllonCommit( TRUE ), + mPassDelete(FALSE), + mReadOnly(FALSE), + mBgImage( p.background_image ), + mBgImageDisabled( p.background_image_disabled ), + mBgImageFocused( p.background_image_focused ), + mShowImageFocused( p.bg_image_always_focused ), + mShowLabelFocused( p.show_label_focused ), + mUseBgColor(p.use_bg_color), + mHaveHistory(FALSE), + mReplaceNewlinesWithSpaces( TRUE ), + mPrevalidator(p.prevalidator()), + mInputPrevalidator(p.input_prevalidator()), + mLabel(p.label), + mCursorColor(p.cursor_color()), + mBgColor(p.bg_color()), + mFgColor(p.text_color()), + mReadOnlyFgColor(p.text_readonly_color()), + mTentativeFgColor(p.text_tentative_color()), + mHighlightColor(p.highlight_color()), + mPreeditBgColor(p.preedit_bg_color()), + mGLFont(p.font), + mContextMenuHandle(), mShowContextMenu(true) { - llassert( mMaxLengthBytes > 0 ); + llassert( mMaxLengthBytes > 0 ); - LLUICtrl::setEnabled(TRUE); - setEnabled(p.enabled); + LLUICtrl::setEnabled(TRUE); + setEnabled(p.enabled); - mScrollTimer.reset(); - mTripleClickTimer.reset(); - setText(p.default_text()); + mScrollTimer.reset(); + mTripleClickTimer.reset(); + setText(p.default_text()); if (p.initial_value.isProvided() && !p.control_name.isProvided()) @@ -186,209 +192,208 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) setText(p.initial_value.getValue().asString(), false); } - // Initialize current history line iterator - mCurrentHistoryLine = mLineHistory.begin(); - - LLRect border_rect(getLocalRect()); - // adjust for gl line drawing glitch - border_rect.mTop -= 1; - border_rect.mRight -=1; - LLViewBorder::Params border_p(p.border); - border_p.rect = border_rect; - border_p.follows.flags = FOLLOWS_ALL; - border_p.bevel_style = LLViewBorder::BEVEL_IN; - mBorder = LLUICtrlFactory::create<LLViewBorder>(border_p); - addChild( mBorder ); - - // clamp text padding to current editor size - updateTextPadding(); - setCursor(mText.length()); - - if (mSpellCheck) - { - LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLLineEditor::onSpellCheckSettingsChange, this)); - } - mSpellCheckTimer.reset(); + // Initialize current history line iterator + mCurrentHistoryLine = mLineHistory.begin(); + + LLRect border_rect(getLocalRect()); + // adjust for gl line drawing glitch + border_rect.mTop -= 1; + border_rect.mRight -=1; + LLViewBorder::Params border_p(p.border); + border_p.rect = border_rect; + border_p.follows.flags = FOLLOWS_ALL; + border_p.bevel_style = LLViewBorder::BEVEL_IN; + mBorder = LLUICtrlFactory::create<LLViewBorder>(border_p); + addChild( mBorder ); + + // clamp text padding to current editor size + updateTextPadding(); + setCursor(mText.length()); + + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLLineEditor::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); - setPrevalidateInput(p.prevalidate_input_callback()); - setPrevalidate(p.prevalidate_callback()); + updateAllowingLanguageInput(); } - + LLLineEditor::~LLLineEditor() { - mCommitOnFocusLost = FALSE; - + mCommitOnFocusLost = FALSE; + // Make sure no context menu linger around once the widget is deleted - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if (menu) - { + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if (menu) + { menu->hide(); } - setContextMenu(NULL); + setContextMenu(NULL); - // calls onCommit() while LLLineEditor still valid - gFocusMgr.releaseFocusIfNeeded( this ); + // calls onCommit() while LLLineEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); } void LLLineEditor::initFromParams(const LLLineEditor::Params& params) { - LLUICtrl::initFromParams(params); - LLUICtrl::setEnabled(TRUE); - setEnabled(params.enabled); + LLUICtrl::initFromParams(params); + LLUICtrl::setEnabled(TRUE); + setEnabled(params.enabled); } void LLLineEditor::onFocusReceived() { - gEditMenuHandler = this; - LLUICtrl::onFocusReceived(); - updateAllowingLanguageInput(); + gEditMenuHandler = this; + LLUICtrl::onFocusReceived(); + updateAllowingLanguageInput(); } void LLLineEditor::onFocusLost() { - // The call to updateAllowLanguageInput() - // when loosing the keyboard focus *may* - // indirectly invoke handleUnicodeCharHere(), - // so it must be called before onCommit. - updateAllowingLanguageInput(); + // The call to updateAllowLanguageInput() + // when loosing the keyboard focus *may* + // indirectly invoke handleUnicodeCharHere(), + // so it must be called before onCommit. + updateAllowingLanguageInput(); - if( mCommitOnFocusLost && mText.getString() != mPrevText) - { - onCommit(); - } + if( mCommitOnFocusLost && mText.getString() != mPrevText) + { + onCommit(); + } - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - getWindow()->showCursorFromMouseMove(); + getWindow()->showCursorFromMouseMove(); - LLUICtrl::onFocusLost(); + LLUICtrl::onFocusLost(); } // virtual void LLLineEditor::onCommit() { - // put current line into the line history - updateHistory(); + // put current line into the line history + updateHistory(); - setControlValue(getValue()); - LLUICtrl::onCommit(); - resetDirty(); + setControlValue(getValue()); + LLUICtrl::onCommit(); + resetDirty(); - // Selection on commit needs to be turned off when evaluating maths - // expressions, to allow indication of the error position - if (mSelectAllonCommit) selectAll(); + // Selection on commit needs to be turned off when evaluating maths + // expressions, to allow indication of the error position + if (mSelectAllonCommit) selectAll(); } // Returns TRUE if user changed value at all // virtual BOOL LLLineEditor::isDirty() const { - return mText.getString() != mPrevText; + return mText.getString() != mPrevText; } // Clear dirty state // virtual void LLLineEditor::resetDirty() { - mPrevText = mText.getString(); -} + mPrevText = mText.getString(); +} // assumes UTF8 text // virtual void LLLineEditor::setValue(const LLSD& value ) { - setText(value.asString()); + setText(value.asString()); } //virtual LLSD LLLineEditor::getValue() const { - return LLSD(getText()); + return LLSD(getText()); } // line history support void LLLineEditor::updateHistory() { - // On history enabled line editors, remember committed line and - // reset current history line number. - // Be sure only to remember lines that are not empty and that are - // different from the last on the list. - if( mHaveHistory && getLength() ) - { - if( !mLineHistory.empty() ) - { - // When not empty, last line of history should always be blank. - if( mLineHistory.back().empty() ) - { - // discard the empty line - mLineHistory.pop_back(); - } - else - { - LL_WARNS("") << "Last line of history was not blank." << LL_ENDL; - } - } - - // Add text to history, ignoring duplicates - if( mLineHistory.empty() || getText() != mLineHistory.back() ) - { - mLineHistory.push_back( getText() ); - } - - // Restore the blank line and set mCurrentHistoryLine to point at it - mLineHistory.push_back( "" ); - mCurrentHistoryLine = mLineHistory.end() - 1; - } + // On history enabled line editors, remember committed line and + // reset current history line number. + // Be sure only to remember lines that are not empty and that are + // different from the last on the list. + if( mHaveHistory && getLength() ) + { + if( !mLineHistory.empty() ) + { + // When not empty, last line of history should always be blank. + if( mLineHistory.back().empty() ) + { + // discard the empty line + mLineHistory.pop_back(); + } + else + { + LL_WARNS("") << "Last line of history was not blank." << LL_ENDL; + } + } + + // Add text to history, ignoring duplicates + if( mLineHistory.empty() || getText() != mLineHistory.back() ) + { + mLineHistory.push_back( getText() ); + } + + // Restore the blank line and set mCurrentHistoryLine to point at it + mLineHistory.push_back( "" ); + mCurrentHistoryLine = mLineHistory.end() - 1; + } } void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLUICtrl::reshape(width, height, called_from_parent); - updateTextPadding(); // For clamping side-effect. - setCursor(mCursorPos); // For clamping side-effect. + LLUICtrl::reshape(width, height, called_from_parent); + updateTextPadding(); // For clamping side-effect. + setCursor(mCursorPos); // For clamping side-effect. } void LLLineEditor::setEnabled(BOOL enabled) { - mReadOnly = !enabled; - setTabStop(!mReadOnly); - updateAllowingLanguageInput(); + mReadOnly = !enabled; + setTabStop(!mReadOnly); + updateAllowingLanguageInput(); } void LLLineEditor::setMaxTextLength(S32 max_text_length) { - S32 max_len = llmax(0, max_text_length); - mMaxLengthBytes = max_len; -} + S32 max_len = llmax(0, max_text_length); + mMaxLengthBytes = max_len; +} void LLLineEditor::setMaxTextChars(S32 max_text_chars) { - S32 max_chars = llmax(0, max_text_chars); - mMaxLengthChars = max_chars; -} + S32 max_chars = llmax(0, max_text_chars); + mMaxLengthChars = max_chars; +} void LLLineEditor::getTextPadding(S32 *left, S32 *right) { - *left = mTextPadLeft; - *right = mTextPadRight; + *left = mTextPadLeft; + *right = mTextPadRight; } void LLLineEditor::setTextPadding(S32 left, S32 right) { - mTextPadLeft = left; - mTextPadRight = right; - updateTextPadding(); + mTextPadLeft = left; + mTextPadRight = right; + updateTextPadding(); } void LLLineEditor::updateTextPadding() { - mTextLeftEdge = llclamp(mTextPadLeft, 0, getRect().getWidth()); - mTextRightEdge = getRect().getWidth() - llclamp(mTextPadRight, 0, getRect().getWidth()); + mTextLeftEdge = llclamp(mTextPadLeft, 0, getRect().getWidth()); + mTextRightEdge = getRect().getWidth() - llclamp(mTextPadRight, 0, getRect().getWidth()); } @@ -399,2303 +404,2314 @@ void LLLineEditor::setText(const LLStringExplicit &new_text) void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit) { - // If new text is identical, don't copy and don't move insertion point - if (mText.getString() == new_text) - { - return; - } - - // Check to see if entire field is selected. - S32 len = mText.length(); - BOOL all_selected = (len > 0) - && (( mSelectionStart == 0 && mSelectionEnd == len ) - || ( mSelectionStart == len && mSelectionEnd == 0 )); - - // Do safe truncation so we don't split multi-byte characters - // also consider entire string selected when mSelectAllonFocusReceived is set on an empty, focused line editor - all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived); - - std::string truncated_utf8 = new_text; - if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes) - { - truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes); - } - mText.assign(truncated_utf8); - - if (use_size_limit && mMaxLengthChars) - { - mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars)); - } - - if (all_selected) - { - // ...keep whole thing selected - selectAll(); - } - else - { - // try to preserve insertion point, but deselect text - deselect(); - } - setCursor(llmin((S32)mText.length(), getCursor())); - - // Set current history line to end of history. - if (mLineHistory.empty()) - { - mCurrentHistoryLine = mLineHistory.end(); - } - else - { - mCurrentHistoryLine = mLineHistory.end() - 1; - } - - mPrevText = mText; + // If new text is identical, don't copy and don't move insertion point + if (mText.getString() == new_text) + { + return; + } + + // Check to see if entire field is selected. + S32 len = mText.length(); + BOOL all_selected = (len > 0) + && (( mSelectionStart == 0 && mSelectionEnd == len ) + || ( mSelectionStart == len && mSelectionEnd == 0 )); + + // Do safe truncation so we don't split multi-byte characters + // also consider entire string selected when mSelectAllonFocusReceived is set on an empty, focused line editor + all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived); + + std::string truncated_utf8 = new_text; + if (!mAllowEmoji) + { + // Cut emoji symbols if exist + utf8str_remove_emojis(truncated_utf8); + } + if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes) + { + truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes); + } + mText.assign(truncated_utf8); + + if (use_size_limit && mMaxLengthChars) + { + mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars)); + } + + if (all_selected) + { + // ...keep whole thing selected + selectAll(); + } + else + { + // try to preserve insertion point, but deselect text + deselect(); + } + setCursor(llmin((S32)mText.length(), getCursor())); + + // Set current history line to end of history. + if (mLineHistory.empty()) + { + mCurrentHistoryLine = mLineHistory.end(); + } + else + { + mCurrentHistoryLine = mLineHistory.end() - 1; + } + + mPrevText = mText; } // Picks a new cursor position based on the actual screen size of text being drawn. void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x ) { - S32 cursor_pos = calcCursorPos(local_mouse_x); + S32 cursor_pos = calcCursorPos(local_mouse_x); - S32 left_pos = llmin( mSelectionStart, cursor_pos ); - S32 length = llabs( mSelectionStart - cursor_pos ); - const LLWString& substr = mText.getWString().substr(left_pos, length); + S32 left_pos = llmin( mSelectionStart, cursor_pos ); + S32 length = llabs( mSelectionStart - cursor_pos ); + const LLWString& substr = mText.getWString().substr(left_pos, length); - if (mIsSelecting && !prevalidateInput(substr)) - return; + if (mIsSelecting && !prevalidateInput(substr)) + return; - setCursor(cursor_pos); + setCursor(cursor_pos); } 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))); - // 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)); - } - else - { - mScrollHPos = min_scroll; - } - } - else if (getCursor() < mScrollHPos) - { - if (old_cursor_pos == mScrollHPos) - { - mScrollHPos = llmax(0, llmin(getCursor(), mScrollHPos - SCROLL_INCREMENT_DEL)); - } - else - { - mScrollHPos = getCursor(); - } - } + 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))); + // 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)); + } + else + { + mScrollHPos = min_scroll; + } + } + else if (getCursor() < mScrollHPos) + { + if (old_cursor_pos == mScrollHPos) + { + mScrollHPos = llmax(0, llmin(getCursor(), mScrollHPos - SCROLL_INCREMENT_DEL)); + } + else + { + mScrollHPos = getCursor(); + } + } } void LLLineEditor::setCursorToEnd() { - setCursor(mText.length()); - deselect(); + setCursor(mText.length()); + deselect(); } void LLLineEditor::resetScrollPosition() { - mScrollHPos = 0; - // make sure cursor says in visible range - setCursor(getCursor()); + mScrollHPos = 0; + // make sure cursor says in visible range + setCursor(getCursor()); } BOOL LLLineEditor::canDeselect() const { - return hasSelection(); + return hasSelection(); } void LLLineEditor::deselect() { - mSelectionStart = 0; - mSelectionEnd = 0; - mIsSelecting = FALSE; + mSelectionStart = 0; + mSelectionEnd = 0; + mIsSelecting = FALSE; } void LLLineEditor::startSelection() { - mIsSelecting = TRUE; - mSelectionStart = getCursor(); - mSelectionEnd = getCursor(); + mIsSelecting = TRUE; + mSelectionStart = getCursor(); + mSelectionEnd = getCursor(); } void LLLineEditor::endSelection() { - if( mIsSelecting ) - { - mIsSelecting = FALSE; - mSelectionEnd = getCursor(); - } + if( mIsSelecting ) + { + mIsSelecting = FALSE; + mSelectionEnd = getCursor(); + } } BOOL LLLineEditor::canSelectAll() const { - return TRUE; + return TRUE; } void LLLineEditor::selectAll() { - if (!prevalidateInput(mText.getWString())) - { - return; - } + if (!prevalidateInput(mText.getWString())) + { + return; + } - mSelectionStart = mText.length(); - mSelectionEnd = 0; - setCursor(mSelectionEnd); - //mScrollHPos = 0; - mIsSelecting = TRUE; - updatePrimary(); + mSelectionStart = mText.length(); + mSelectionEnd = 0; + setCursor(mSelectionEnd); + //mScrollHPos = 0; + mIsSelecting = TRUE; + updatePrimary(); } bool LLLineEditor::getSpellCheck() const { - return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); } const std::string& LLLineEditor::getSuggestion(U32 index) const { - return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; } U32 LLLineEditor::getSuggestionCount() const { - return mSuggestionList.size(); + return mSuggestionList.size(); } void LLLineEditor::replaceWithSuggestion(U32 index) { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) - { - deselect(); - - // Delete the misspelled word - mText.erase(it->first, it->second - it->first); - - // Insert the suggestion in its place - LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); - mText.insert(it->first, suggestion); - setCursor(it->first + (S32)suggestion.length()); - - break; - } - } - mSpellCheckStart = mSpellCheckEnd = -1; + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + if (!mAllowEmoji) + { + // Cut emoji symbols if exist + wstring_remove_emojis(suggestion); + } + if (suggestion.empty()) + return; + + deselect(); + + // Delete the misspelled word + mText.erase(it->first, it->second - it->first); + + // Insert the suggestion in its place + mText.insert(it->first, suggestion); + setCursor(it->first + (S32)suggestion.length()); + + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; } void LLLineEditor::addToDictionary() { - if (canAddToDictionary()) - { - LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); - } + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } } bool LLLineEditor::canAddToDictionary() const { - return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); } void LLLineEditor::addToIgnore() { - if (canAddToIgnore()) - { - LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); - } + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } } bool LLLineEditor::canAddToIgnore() const { - return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); } std::string LLLineEditor::getMisspelledWord(U32 pos) const { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= pos) && (it->second >= pos) ) - { - return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first)); - } - } - return LLStringUtil::null; + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first)); + } + } + return LLStringUtil::null; } bool LLLineEditor::isMisspelledWord(U32 pos) const { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= pos) && (it->second >= pos) ) - { - return true; - } - } - return false; + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return true; + } + } + return false; } void LLLineEditor::onSpellCheckSettingsChange() { - // Recheck the spelling on every change - mMisspellRanges.clear(); - mSpellCheckStart = mSpellCheckEnd = -1; + // Recheck the spelling on every change + mMisspellRanges.clear(); + mSpellCheckStart = mSpellCheckEnd = -1; } BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - setFocus( TRUE ); - mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); - - if (mSelectionEnd == 0 && mSelectionStart == mText.length()) - { - // if everything is selected, handle this as a normal click to change insertion point - handleMouseDown(x, y, mask); - } - else - { - const LLWString& wtext = mText.getWString(); - - BOOL doSelectAll = TRUE; - - // Select the word we're on - if( LLWStringUtil::isPartOfWord( wtext[mCursorPos] ) ) - { - S32 old_selection_start = mLastSelectionStart; - S32 old_selection_end = mLastSelectionEnd; - - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[mCursorPos-1] )) - { // Find the start of the word - mCursorPos--; - } - startSelection(); - - while ((mCursorPos < (S32)wtext.length()) && LLWStringUtil::isPartOfWord( wtext[mCursorPos] ) ) - { // Find the end of the word - mCursorPos++; - } - mSelectionEnd = mCursorPos; - - // If nothing changed, then the word was already selected. Select the whole line. - doSelectAll = (old_selection_start == mSelectionStart) && - (old_selection_end == mSelectionEnd); - } - - if ( doSelectAll ) - { // Select everything - selectAll(); - } - } - - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection - // here. - mIsSelecting = FALSE; - - // delay cursor flashing - mKeystrokeTimer.reset(); - - // take selection to 'primary' clipboard - updatePrimary(); - - return TRUE; + setFocus( TRUE ); + mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + + if (mSelectionEnd == 0 && mSelectionStart == mText.length()) + { + // if everything is selected, handle this as a normal click to change insertion point + handleMouseDown(x, y, mask); + } + else + { + const LLWString& wtext = mText.getWString(); + + BOOL doSelectAll = TRUE; + + // Select the word we're on + if( LLWStringUtil::isPartOfWord( wtext[mCursorPos] ) ) + { + S32 old_selection_start = mLastSelectionStart; + S32 old_selection_end = mLastSelectionEnd; + + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[mCursorPos-1] )) + { // Find the start of the word + mCursorPos--; + } + startSelection(); + + while ((mCursorPos < (S32)wtext.length()) && LLWStringUtil::isPartOfWord( wtext[mCursorPos] ) ) + { // Find the end of the word + mCursorPos++; + } + mSelectionEnd = mCursorPos; + + // If nothing changed, then the word was already selected. Select the whole line. + doSelectAll = (old_selection_start == mSelectionStart) && + (old_selection_end == mSelectionEnd); + } + + if ( doSelectAll ) + { // Select everything + selectAll(); + } + } + + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection + // here. + mIsSelecting = FALSE; + + // delay cursor flashing + mKeystrokeTimer.reset(); + + // take selection to 'primary' clipboard + updatePrimary(); + + return TRUE; } BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - // Check first whether the "clear search" button wants to deal with this. - if(childrenHandleMouseDown(x, y, mask) != NULL) - { - return TRUE; - } - - if (!mSelectAllonFocusReceived - || gFocusMgr.getKeyboardFocus() == this) - { - mLastSelectionStart = -1; - mLastSelectionStart = -1; - - if (mask & MASK_SHIFT) - { - // assume we're starting a drag select - mIsSelecting = TRUE; - - // Handle selection extension - S32 old_cursor_pos = getCursor(); - setCursorAtLocalPos(x); - - if (hasSelection()) - { - /* Mac-like behavior - extend selection towards the cursor - if (getCursor() < mSelectionStart - && getCursor() < mSelectionEnd) - { - // ...left of selection - mSelectionStart = llmax(mSelectionStart, mSelectionEnd); - mSelectionEnd = getCursor(); - } - else if (getCursor() > mSelectionStart - && getCursor() > mSelectionEnd) - { - // ...right of selection - mSelectionStart = llmin(mSelectionStart, mSelectionEnd); - mSelectionEnd = getCursor(); - } - else - { - mSelectionEnd = getCursor(); - } - */ - // Windows behavior - mSelectionEnd = getCursor(); - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = getCursor(); - } - } - else - { - if (mTripleClickTimer.hasExpired()) - { - // Save selection for word/line selecting on double-click - mLastSelectionStart = mSelectionStart; - mLastSelectionEnd = mSelectionEnd; - - // Move cursor and deselect for regular click - setCursorAtLocalPos( x ); - deselect(); - startSelection(); - } - else // handle triple click - { - selectAll(); - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection - // here. - mIsSelecting = FALSE; - } - } - - gFocusMgr.setMouseCapture( this ); - } - - setFocus(TRUE); - - // delay cursor flashing - mKeystrokeTimer.reset(); - - if (mMouseDownSignal) - (*mMouseDownSignal)(this,x,y,mask); - - return TRUE; + // Check first whether the "clear search" button wants to deal with this. + if(childrenHandleMouseDown(x, y, mask) != NULL) + { + return TRUE; + } + + if (!mSelectAllonFocusReceived + || gFocusMgr.getKeyboardFocus() == this) + { + mLastSelectionStart = -1; + mLastSelectionStart = -1; + + if (mask & MASK_SHIFT) + { + // assume we're starting a drag select + mIsSelecting = TRUE; + + // Handle selection extension + S32 old_cursor_pos = getCursor(); + setCursorAtLocalPos(x); + + if (hasSelection()) + { + /* Mac-like behavior - extend selection towards the cursor + if (getCursor() < mSelectionStart + && getCursor() < mSelectionEnd) + { + // ...left of selection + mSelectionStart = llmax(mSelectionStart, mSelectionEnd); + mSelectionEnd = getCursor(); + } + else if (getCursor() > mSelectionStart + && getCursor() > mSelectionEnd) + { + // ...right of selection + mSelectionStart = llmin(mSelectionStart, mSelectionEnd); + mSelectionEnd = getCursor(); + } + else + { + mSelectionEnd = getCursor(); + } + */ + // Windows behavior + mSelectionEnd = getCursor(); + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = getCursor(); + } + } + else + { + if (mTripleClickTimer.hasExpired()) + { + // Save selection for word/line selecting on double-click + mLastSelectionStart = mSelectionStart; + mLastSelectionEnd = mSelectionEnd; + + // Move cursor and deselect for regular click + setCursorAtLocalPos( x ); + deselect(); + startSelection(); + } + else // handle triple click + { + selectAll(); + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection + // here. + mIsSelecting = FALSE; + } + } + + gFocusMgr.setMouseCapture( this ); + } + + setFocus(TRUE); + + // delay cursor flashing + mKeystrokeTimer.reset(); + + if (mMouseDownSignal) + (*mMouseDownSignal)(this,x,y,mask); + + return TRUE; } BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { // LL_INFOS() << "MiddleMouseDown" << LL_ENDL; - setFocus( TRUE ); - if( canPastePrimary() ) - { - setCursorAtLocalPos(x); - pastePrimary(); - } - return TRUE; + setFocus( TRUE ); + if( canPastePrimary() ) + { + setCursorAtLocalPos(x); + pastePrimary(); + } + return TRUE; } BOOL LLLineEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - setFocus(TRUE); + setFocus(TRUE); if (!LLUICtrl::handleRightMouseDown(x, y, mask) && getShowContextMenu()) - { - showContextMenu(x, y); - } - return TRUE; + { + showContextMenu(x, y); + } + return TRUE; } BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - // Check first whether the "clear search" button wants to deal with this. - if(!hasMouseCapture()) - { - if(childrenHandleHover(x, y, mask) != NULL) - { - return TRUE; - } - } - - if( (hasMouseCapture()) && mIsSelecting ) - { - if (x != mLastSelectionX || y != mLastSelectionY) - { - mLastSelectionX = x; - mLastSelectionY = y; - } - // Scroll if mouse cursor outside of bounds - if (mScrollTimer.hasExpired()) - { - S32 increment = ll_round(mScrollTimer.getElapsedTimeF32() / AUTO_SCROLL_TIME); - mScrollTimer.reset(); - mScrollTimer.setTimerExpirySec(AUTO_SCROLL_TIME); - if( (x < mTextLeftEdge) && (mScrollHPos > 0 ) ) - { - // Scroll to the left - mScrollHPos = llclamp(mScrollHPos - increment, 0, mText.length()); - } - else - if( (x > mTextRightEdge) && (mCursorPos < (S32)mText.length()) ) - { - // If scrolling one pixel would make a difference... - S32 pixels_after_scrolling_one_char = findPixelNearestPos(1); - if( pixels_after_scrolling_one_char >= mTextRightEdge ) - { - // ...scroll to the right - mScrollHPos = llclamp(mScrollHPos + increment, 0, mText.length()); - } - } - } - - setCursorAtLocalPos( x ); - mSelectionEnd = getCursor(); - - // delay cursor flashing - mKeystrokeTimer.reset(); - - getWindow()->setCursor(UI_CURSOR_IBEAM); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - handled = TRUE; - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + // Check first whether the "clear search" button wants to deal with this. + if(!hasMouseCapture()) + { + if(childrenHandleHover(x, y, mask) != NULL) + { + return TRUE; + } + } + + if( (hasMouseCapture()) && mIsSelecting ) + { + if (x != mLastSelectionX || y != mLastSelectionY) + { + mLastSelectionX = x; + mLastSelectionY = y; + } + // Scroll if mouse cursor outside of bounds + if (mScrollTimer.hasExpired()) + { + S32 increment = ll_round(mScrollTimer.getElapsedTimeF32() / AUTO_SCROLL_TIME); + mScrollTimer.reset(); + mScrollTimer.setTimerExpirySec(AUTO_SCROLL_TIME); + if( (x < mTextLeftEdge) && (mScrollHPos > 0 ) ) + { + // Scroll to the left + mScrollHPos = llclamp(mScrollHPos - increment, 0, mText.length()); + } + else + if( (x > mTextRightEdge) && (mCursorPos < (S32)mText.length()) ) + { + // If scrolling one pixel would make a difference... + S32 pixels_after_scrolling_one_char = findPixelNearestPos(1); + if( pixels_after_scrolling_one_char >= mTextRightEdge ) + { + // ...scroll to the right + mScrollHPos = llclamp(mScrollHPos + increment, 0, mText.length()); + } + } + } + + setCursorAtLocalPos( x ); + mSelectionEnd = getCursor(); + + // delay cursor flashing + mKeystrokeTimer.reset(); + + getWindow()->setCursor(UI_CURSOR_IBEAM); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + handled = TRUE; + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + handled = TRUE; + } + + return handled; } BOOL LLLineEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - handled = TRUE; - } + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + handled = TRUE; + } - // Check first whether the "clear search" button wants to deal with this. - if(!handled && childrenHandleMouseUp(x, y, mask) != NULL) - { - return TRUE; - } + // Check first whether the "clear search" button wants to deal with this. + if(!handled && childrenHandleMouseUp(x, y, mask) != NULL) + { + return TRUE; + } - if( mIsSelecting ) - { - setCursorAtLocalPos( x ); - mSelectionEnd = getCursor(); + if( mIsSelecting ) + { + setCursorAtLocalPos( x ); + mSelectionEnd = getCursor(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - // delay cursor flashing - mKeystrokeTimer.reset(); + if( handled ) + { + // delay cursor flashing + mKeystrokeTimer.reset(); - // take selection to 'primary' clipboard - updatePrimary(); - } - - // We won't call LLUICtrl::handleMouseUp to avoid double calls of childrenHandleMouseUp().Just invoke the signal manually. - if (mMouseUpSignal) - (*mMouseUpSignal)(this,x,y, mask); - return handled; + // take selection to 'primary' clipboard + updatePrimary(); + } + + // We won't call LLUICtrl::handleMouseUp to avoid double calls of childrenHandleMouseUp().Just invoke the signal manually. + if (mMouseUpSignal) + (*mMouseUpSignal)(this,x,y, mask); + return handled; } // Remove a single character from the text void LLLineEditor::removeChar() { - if( getCursor() > 0 ) - { - if (!prevalidateInput(mText.getWString().substr(getCursor()-1, 1))) - return; + if( getCursor() > 0 ) + { + if (!prevalidateInput(mText.getWString().substr(getCursor()-1, 1))) + return; - mText.erase(getCursor() - 1, 1); + mText.erase(getCursor() - 1, 1); - setCursor(getCursor() - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + setCursor(getCursor() - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } - void LLLineEditor::addChar(const llwchar uni_char) { - llwchar new_c = uni_char; - if (hasSelection()) - { - deleteSelection(); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - if (!prevalidateInput(mText.getWString().substr(getCursor(), 1))) - return; - - mText.erase(getCursor(), 1); - } - - S32 cur_bytes = mText.getString().size(); - - S32 new_bytes = wchar_utf8_length(new_c); - - BOOL allow_char = TRUE; - - // Check byte length limit - if ((new_bytes + cur_bytes) > mMaxLengthBytes) - { - allow_char = FALSE; - } - else if (mMaxLengthChars) - { - S32 wide_chars = mText.getWString().size(); - if ((wide_chars + 1) > mMaxLengthChars) - { - allow_char = FALSE; - } - } - - if (allow_char) - { - // Will we need to scroll? - LLWString w_buf; - w_buf.assign(1, new_c); - - mText.insert(getCursor(), w_buf); - setCursor(getCursor() + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - - getWindow()->hideCursorUntilMouseMove(); + if (!mAllowEmoji && LLStringOps::isEmoji(uni_char)) + return; + + llwchar new_c = uni_char; + if (hasSelection()) + { + deleteSelection(); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + if (!prevalidateInput(mText.getWString().substr(getCursor(), 1))) + return; + + mText.erase(getCursor(), 1); + } + + S32 cur_bytes = mText.getString().size(); + + S32 new_bytes = wchar_utf8_length(new_c); + + BOOL allow_char = TRUE; + + // Check byte length limit + if ((new_bytes + cur_bytes) > mMaxLengthBytes) + { + allow_char = FALSE; + } + else if (mMaxLengthChars) + { + S32 wide_chars = mText.getWString().size(); + if ((wide_chars + 1) > mMaxLengthChars) + { + allow_char = FALSE; + } + } + + if (allow_char) + { + // Will we need to scroll? + LLWString w_buf; + w_buf.assign(1, new_c); + + mText.insert(getCursor(), w_buf); + setCursor(getCursor() + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + + getWindow()->hideCursorUntilMouseMove(); } // Extends the selection box to the new cursor position void LLLineEditor::extendSelection( S32 new_cursor_pos ) { - if( !mIsSelecting ) - { - startSelection(); - } - - S32 left_pos = llmin( mSelectionStart, new_cursor_pos ); - S32 selection_length = llabs( mSelectionStart - new_cursor_pos ); - const LLWString& selection = mText.getWString().substr(left_pos, selection_length); + if( !mIsSelecting ) + { + startSelection(); + } + + S32 left_pos = llmin( mSelectionStart, new_cursor_pos ); + S32 selection_length = llabs( mSelectionStart - new_cursor_pos ); + const LLWString& selection = mText.getWString().substr(left_pos, selection_length); - if (!prevalidateInput(selection)) - return; + if (!prevalidateInput(selection)) + return; - setCursor(new_cursor_pos); - mSelectionEnd = getCursor(); + setCursor(new_cursor_pos); + mSelectionEnd = getCursor(); } void LLLineEditor::setSelection(S32 start, S32 end) { - S32 len = mText.length(); + S32 len = mText.length(); - mIsSelecting = TRUE; + mIsSelecting = TRUE; - // JC, yes, this seems odd, but I think you have to presume a - // selection dragged from the end towards the start. - mSelectionStart = llclamp(end, 0, len); - mSelectionEnd = llclamp(start, 0, len); - setCursor(start); + // JC, yes, this seems odd, but I think you have to presume a + // selection dragged from the end towards the start. + mSelectionStart = llclamp(end, 0, len); + mSelectionEnd = llclamp(start, 0, len); + setCursor(start); } void LLLineEditor::setDrawAsterixes(BOOL b) { - mDrawAsterixes = b; - updateAllowingLanguageInput(); + mDrawAsterixes = b; + updateAllowingLanguageInput(); } S32 LLLineEditor::prevWordPos(S32 cursorPos) const { - const LLWString& wtext = mText.getWString(); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + const LLWString& wtext = mText.getWString(); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLLineEditor::nextWordPos(S32 cursorPos) const { - const LLWString& wtext = mText.getWString(); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + const LLWString& wtext = mText.getWString(); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < getCursor() ) - { - S32 cursorPos = getCursor() - 1; - if( mask & MASK_CONTROL ) - { - cursorPos = prevWordPos(cursorPos); - } - extendSelection( cursorPos ); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - case KEY_RIGHT: - if( getCursor() < mText.length()) - { - S32 cursorPos = getCursor() + 1; - if( mask & MASK_CONTROL ) - { - cursorPos = nextWordPos(cursorPos); - } - extendSelection( cursorPos ); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - case KEY_PAGE_UP: - case KEY_HOME: - extendSelection( 0 ); - break; - - case KEY_PAGE_DOWN: - case KEY_END: - { - S32 len = mText.length(); - if( len ) - { - extendSelection( len ); - } - break; - } - - default: - handled = FALSE; - break; - } - } - - if(handled) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < getCursor() ) + { + S32 cursorPos = getCursor() - 1; + if( mask & MASK_CONTROL ) + { + cursorPos = prevWordPos(cursorPos); + } + extendSelection( cursorPos ); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + case KEY_RIGHT: + if( getCursor() < mText.length()) + { + S32 cursorPos = getCursor() + 1; + if( mask & MASK_CONTROL ) + { + cursorPos = nextWordPos(cursorPos); + } + extendSelection( cursorPos ); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + case KEY_PAGE_UP: + case KEY_HOME: + extendSelection( 0 ); + break; + + case KEY_PAGE_DOWN: + case KEY_END: + { + S32 len = mText.length(); + if( len ) + { + extendSelection( len ); + } + break; + } + + default: + handled = FALSE; + break; + } + } + + if(handled) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } void LLLineEditor::deleteSelection() { - if( !mReadOnly && hasSelection() ) - { - S32 left_pos, selection_length; - getSelectionRange(&left_pos, &selection_length); - const LLWString& selection = mText.getWString().substr(left_pos, selection_length); + if( !mReadOnly && hasSelection() ) + { + S32 left_pos, selection_length; + getSelectionRange(&left_pos, &selection_length); + const LLWString& selection = mText.getWString().substr(left_pos, selection_length); - if (!prevalidateInput(selection)) - return; + if (!prevalidateInput(selection)) + return; - mText.erase(left_pos, selection_length); - deselect(); - setCursor(left_pos); - } + mText.erase(left_pos, selection_length); + deselect(); + setCursor(left_pos); + } } BOOL LLLineEditor::canCut() const { - return !mReadOnly && !mDrawAsterixes && hasSelection(); + return !mReadOnly && !mDrawAsterixes && hasSelection(); } // cut selection to clipboard void LLLineEditor::cut() { - if( canCut() ) - { - S32 left_pos, length; - getSelectionRange(&left_pos, &length); - const LLWString& selection = mText.getWString().substr(left_pos, length); - - if (!prevalidateInput(selection)) - return; - - // Prepare for possible rollback - LLLineEditorRollback rollback( this ); - - LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length ); - deleteSelection(); - - // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) - { - rollback.doRollback( this ); - LLUI::getInstance()->reportBadKeystroke(); - } - else - { - onKeystroke(); - } - } + if( canCut() ) + { + S32 left_pos, length; + getSelectionRange(&left_pos, &length); + const LLWString& selection = mText.getWString().substr(left_pos, length); + + if (!prevalidateInput(selection)) + return; + + // Prepare for possible rollback + LLLineEditorRollback rollback( this ); + + LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length ); + deleteSelection(); + + // Validate new string and rollback the if needed. + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) + { + rollback.doRollback( this ); + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + } + else + { + onKeystroke(); + } + } } BOOL LLLineEditor::canCopy() const { - return !mDrawAsterixes && hasSelection(); + return !mDrawAsterixes && hasSelection(); } // copy selection to clipboard void LLLineEditor::copy() { - if( canCopy() ) - { - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length ); - } + if( canCopy() ) + { + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length ); + } } BOOL LLLineEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } void LLLineEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } void LLLineEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (is_primary==true) or clipboard (is_primary==false) void LLLineEditor::pasteHelper(bool is_primary) { - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } - - if (can_paste_it) - { - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); - - if (!paste.empty()) - { - if (!prevalidateInput(paste)) - return; - - // Prepare for possible rollback - LLLineEditorRollback rollback(this); - - // Delete any selected characters - if ((!is_primary) && hasSelection()) - { - deleteSelection(); - } - - // Clean up string (replace tabs and returns and remove characters that our fonts don't support.) - LLWString clean_string(paste); - LLWStringUtil::replaceTabsWithSpaces(clean_string, 1); - //clean_string = wstring_detabify(paste, 1); - LLWStringUtil::replaceChar(clean_string, '\n', mReplaceNewlinesWithSpaces ? ' ' : 182); // 182 == paragraph character - - // Insert the string - - // Check to see that the size isn't going to be larger than the max number of bytes - U32 available_bytes = mMaxLengthBytes - wstring_utf8_length(mText); - - if ( available_bytes < (U32) wstring_utf8_length(clean_string) ) - { // Doesn't all fit - llwchar current_symbol = clean_string[0]; - U32 wchars_that_fit = 0; - U32 total_bytes = wchar_utf8_length(current_symbol); - - //loop over the "wide" characters (symbols) - //and check to see how large (in bytes) each symbol is. - while ( total_bytes <= available_bytes ) - { - //while we still have available bytes - //"accept" the current symbol and check the size - //of the next one - current_symbol = clean_string[++wchars_that_fit]; - total_bytes += wchar_utf8_length(current_symbol); - } - // Truncate the clean string at the limit of what will fit - clean_string = clean_string.substr(0, wchars_that_fit); - LLUI::getInstance()->reportBadKeystroke(); - } - - if (mMaxLengthChars) - { - U32 available_chars = mMaxLengthChars - mText.getWString().size(); - - if (available_chars < clean_string.size()) - { - clean_string = clean_string.substr(0, available_chars); - } - - LLUI::getInstance()->reportBadKeystroke(); - } - - mText.insert(getCursor(), clean_string); - setCursor( getCursor() + (S32)clean_string.length() ); - deselect(); - - // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) - { - rollback.doRollback( this ); - LLUI::getInstance()->reportBadKeystroke(); - } - else - { - onKeystroke(); - } - } - } + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } + + if (can_paste_it) + { + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); + + if (!paste.empty()) + { + if (!mAllowEmoji) + { + wstring_remove_emojis(paste); + } + + if (!prevalidateInput(paste)) + return; + + // Prepare for possible rollback + LLLineEditorRollback rollback(this); + + // Delete any selected characters + if ((!is_primary) && hasSelection()) + { + deleteSelection(); + } + + // Clean up string (replace tabs and returns and remove characters that our fonts don't support.) + LLWString clean_string(paste); + LLWStringUtil::replaceTabsWithSpaces(clean_string, 1); + //clean_string = wstring_detabify(paste, 1); + LLWStringUtil::replaceChar(clean_string, '\n', mReplaceNewlinesWithSpaces ? ' ' : 182); // 182 == paragraph character + + // Insert the string + + // Check to see that the size isn't going to be larger than the max number of bytes + U32 available_bytes = mMaxLengthBytes - wstring_utf8_length(mText); + + if ( available_bytes < (U32) wstring_utf8_length(clean_string) ) + { // Doesn't all fit + llwchar current_symbol = clean_string[0]; + U32 wchars_that_fit = 0; + U32 total_bytes = wchar_utf8_length(current_symbol); + + //loop over the "wide" characters (symbols) + //and check to see how large (in bytes) each symbol is. + while ( total_bytes <= available_bytes ) + { + //while we still have available bytes + //"accept" the current symbol and check the size + //of the next one + current_symbol = clean_string[++wchars_that_fit]; + total_bytes += wchar_utf8_length(current_symbol); + } + // Truncate the clean string at the limit of what will fit + clean_string = clean_string.substr(0, wchars_that_fit); + LLUI::getInstance()->reportBadKeystroke(); + } + + if (mMaxLengthChars) + { + U32 available_chars = mMaxLengthChars - mText.getWString().size(); + + if (available_chars < clean_string.size()) + { + clean_string = clean_string.substr(0, available_chars); + } + + LLUI::getInstance()->reportBadKeystroke(); + } + + mText.insert(getCursor(), clean_string); + setCursor( getCursor() + (S32)clean_string.length() ); + deselect(); + + // Validate new string and rollback the if needed. + BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) + { + rollback.doRollback( this ); + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + } + else + { + onKeystroke(); + } + } + } } // copy selection to primary void LLLineEditor::copyPrimary() { - if( canCopy() ) - { - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length, true); - } + if( canCopy() ) + { + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( mText.getWString(), left_pos, length, true); + } } BOOL LLLineEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLLineEditor::updatePrimary() { - if(canCopy() ) - { - copyPrimary(); - } -} - -BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) -{ - BOOL handled = FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - - handled = TRUE; - break; - - case KEY_BACKSPACE: - if (!mReadOnly) - { - //LL_INFOS() << "Handling backspace" << LL_ENDL; - if( hasSelection() ) - { - deleteSelection(); - } - else - if( 0 < getCursor() ) - { - removeChar(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - handled = TRUE; - break; - - case KEY_PAGE_UP: - case KEY_HOME: - if (!mIgnoreArrowKeys) - { - setCursor(0); - handled = TRUE; - } - break; - - case KEY_PAGE_DOWN: - case KEY_END: - if (!mIgnoreArrowKeys) - { - S32 len = mText.length(); - if( len ) - { - setCursor(len); - } - handled = TRUE; - } - break; - - case KEY_LEFT: - if (mIgnoreArrowKeys && mask == MASK_NONE) - break; - if ((mask & MASK_ALT) == 0) - { - if( hasSelection() ) - { - setCursor(llmin( getCursor() - 1, mSelectionStart, mSelectionEnd )); - } - else - if( 0 < getCursor() ) - { - S32 cursorPos = getCursor() - 1; - if( mask & MASK_CONTROL ) - { - cursorPos = prevWordPos(cursorPos); - } - setCursor(cursorPos); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - case KEY_RIGHT: - if (mIgnoreArrowKeys && mask == MASK_NONE) - break; - if ((mask & MASK_ALT) == 0) - { - if (hasSelection()) - { - setCursor(llmax(getCursor() + 1, mSelectionStart, mSelectionEnd)); - } - else - if (getCursor() < mText.length()) - { - S32 cursorPos = getCursor() + 1; - if( mask & MASK_CONTROL ) - { - cursorPos = nextWordPos(cursorPos); - } - setCursor(cursorPos); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - // handle ctrl-uparrow if we have a history enabled line editor. - case KEY_UP: - if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) ) - { - if( mCurrentHistoryLine > mLineHistory.begin() ) - { - mText.assign( *(--mCurrentHistoryLine) ); - setCursorToEnd(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - // handle [ctrl]-downarrow if we have a history enabled line editor - case KEY_DOWN: - if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) ) - { - if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 ) - { - mText.assign( *(++mCurrentHistoryLine) ); - setCursorToEnd(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - handled = TRUE; - } - break; - - case KEY_RETURN: - // store sent line in history - updateHistory(); - break; - - case KEY_ESCAPE: - if (mRevertOnEsc && mText.getString() != mPrevText) - { - setText(mPrevText); - // Note, don't set handled, still want to loose focus (won't commit becase text is now unchanged) - if (mKeystrokeOnEsc) - { - onKeystroke(); - } - } - break; - - default: - break; - } - - return handled; + if(canCopy() ) + { + copyPrimary(); + } +} + +BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) +{ + BOOL handled = FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + + handled = TRUE; + break; + + case KEY_BACKSPACE: + if (!mReadOnly) + { + //LL_INFOS() << "Handling backspace" << LL_ENDL; + if( hasSelection() ) + { + deleteSelection(); + } + else + if( 0 < getCursor() ) + { + removeChar(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + handled = TRUE; + break; + + case KEY_PAGE_UP: + case KEY_HOME: + if (!mIgnoreArrowKeys) + { + setCursor(0); + handled = TRUE; + } + break; + + case KEY_PAGE_DOWN: + case KEY_END: + if (!mIgnoreArrowKeys) + { + S32 len = mText.length(); + if( len ) + { + setCursor(len); + } + handled = TRUE; + } + break; + + case KEY_LEFT: + if (mIgnoreArrowKeys && mask == MASK_NONE) + break; + if ((mask & MASK_ALT) == 0) + { + if( hasSelection() ) + { + setCursor(llmin( getCursor() - 1, mSelectionStart, mSelectionEnd )); + } + else + if( 0 < getCursor() ) + { + S32 cursorPos = getCursor() - 1; + if( mask & MASK_CONTROL ) + { + cursorPos = prevWordPos(cursorPos); + } + setCursor(cursorPos); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + case KEY_RIGHT: + if (mIgnoreArrowKeys && mask == MASK_NONE) + break; + if ((mask & MASK_ALT) == 0) + { + if (hasSelection()) + { + setCursor(llmax(getCursor() + 1, mSelectionStart, mSelectionEnd)); + } + else + if (getCursor() < mText.length()) + { + S32 cursorPos = getCursor() + 1; + if( mask & MASK_CONTROL ) + { + cursorPos = nextWordPos(cursorPos); + } + setCursor(cursorPos); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + // handle ctrl-uparrow if we have a history enabled line editor. + case KEY_UP: + if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) ) + { + if( mCurrentHistoryLine > mLineHistory.begin() ) + { + mText.assign( *(--mCurrentHistoryLine) ); + setCursorToEnd(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + // handle [ctrl]-downarrow if we have a history enabled line editor + case KEY_DOWN: + if( mHaveHistory && ((mIgnoreArrowKeys == false) || ( MASK_CONTROL == mask )) ) + { + if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 ) + { + mText.assign( *(++mCurrentHistoryLine) ); + setCursorToEnd(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + handled = TRUE; + } + break; + + case KEY_RETURN: + // store sent line in history + updateHistory(); + break; + + case KEY_ESCAPE: + if (mRevertOnEsc && mText.getString() != mPrevText) + { + setText(mPrevText); + // Note, don't set handled, still want to loose focus (won't commit becase text is now unchanged) + if (mKeystrokeOnEsc) + { + onKeystroke(); + } + } + break; + + default: + break; + } + + return handled; } BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - BOOL selection_modified = FALSE; - - if ( gFocusMgr.getKeyboardFocus() == this ) - { - LLLineEditorRollback rollback( this ); - - if( !handled ) - { - handled = handleSelectionKey( key, mask ); - selection_modified = handled; - } - - // Handle most keys only if the text editor is writeable. - if ( !mReadOnly ) - { - if( !handled ) - { - handled = handleSpecialKey( key, mask ); - } - } - - if( handled ) - { - mKeystrokeTimer.reset(); - - // Most keystrokes will make the selection box go away, but not all will. - if( !selection_modified && - KEY_SHIFT != key && - KEY_CONTROL != key && - KEY_ALT != key && - KEY_CAPSLOCK != key) - { - deselect(); - } - - BOOL need_to_rollback = FALSE; - - // If read-only, don't allow changes - need_to_rollback |= (mReadOnly && (mText.getString() == rollback.getText())); - - // Validate new string and rollback the keystroke if needed. - need_to_rollback |= (mPrevalidateFunc && !mPrevalidateFunc(mText.getWString())); - - if (need_to_rollback) - { - rollback.doRollback(this); - - LLUI::getInstance()->reportBadKeystroke(); - } - - // Notify owner if requested - if (!need_to_rollback && handled) - { - onKeystroke(); - if ( (!selection_modified) && (KEY_BACKSPACE == key) ) - { - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); - } - } - } - } - - return handled; + BOOL handled = FALSE; + BOOL selection_modified = FALSE; + + if ( gFocusMgr.getKeyboardFocus() == this ) + { + LLLineEditorRollback rollback( this ); + + if( !handled ) + { + handled = handleSelectionKey( key, mask ); + selection_modified = handled; + } + + // Handle most keys only if the text editor is writeable. + if ( !mReadOnly ) + { + if( !handled ) + { + handled = handleSpecialKey( key, mask ); + } + } + + if( handled ) + { + mKeystrokeTimer.reset(); + + // Most keystrokes will make the selection box go away, but not all will. + if( !selection_modified && + KEY_SHIFT != key && + KEY_CONTROL != key && + KEY_ALT != key && + KEY_CAPSLOCK != key) + { + deselect(); + } + + bool prevalidator_failed = false; + + // If read-only, don't allow changes + bool need_to_rollback = mReadOnly && (mText.getString() == rollback.getText()); + + // Validate new string and rollback the keystroke if needed. + if (!need_to_rollback && mPrevalidator) + { + prevalidator_failed = !mPrevalidator.validate(mText.getWString()); + need_to_rollback |= prevalidator_failed; + } + + if (need_to_rollback) + { + rollback.doRollback(this); + + LLUI::getInstance()->reportBadKeystroke(); + if (prevalidator_failed) + { + mPrevalidator.showLastErrorUsingTimeout(); + } + } + + // Notify owner if requested + if (!need_to_rollback && handled) + { + onKeystroke(); + if ( (!selection_modified) && (KEY_BACKSPACE == key) ) + { + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + } + } + } + } + + return handled; } BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } - - BOOL handled = FALSE; - - if ( (gFocusMgr.getKeyboardFocus() == this) && getVisible() && !mReadOnly) - { - handled = TRUE; + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - LLLineEditorRollback rollback( this ); + BOOL handled = FALSE; - { - LLWString u_char; - u_char.assign(1, uni_char); - if (!prevalidateInput(u_char)) - return handled; - } + if ( (gFocusMgr.getKeyboardFocus() == this) && getVisible() && !mReadOnly) + { + handled = TRUE; - addChar(uni_char); + LLLineEditorRollback rollback( this ); - mKeystrokeTimer.reset(); + { + LLWString u_char; + u_char.assign(1, uni_char); + if (!prevalidateInput(u_char)) + return handled; + } - deselect(); + addChar(uni_char); - BOOL need_to_rollback = FALSE; + mKeystrokeTimer.reset(); - // Validate new string and rollback the keystroke if needed. - need_to_rollback |= ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); + deselect(); - if( need_to_rollback ) - { - rollback.doRollback( this ); + // Validate new string and rollback the keystroke if needed. + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) + { + rollback.doRollback( this ); - LLUI::getInstance()->reportBadKeystroke(); - } + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + } - // Notify owner if requested - if( !need_to_rollback && handled ) - { - // HACK! The only usage of this callback doesn't do anything with the character. - // We'll have to do something about this if something ever changes! - Doug - onKeystroke(); + // Notify owner if requested + if (!need_to_rollback && handled) + { + // HACK! The only usage of this callback doesn't do anything with the character. + // We'll have to do something about this if something ever changes! - Doug + onKeystroke(); - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); - } - } - return handled; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + } + } + return handled; } BOOL LLLineEditor::canDoDelete() const { - return ( !mReadOnly && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) ); + return ( !mReadOnly && (!mPassDelete || (hasSelection() || (getCursor() < mText.length()))) ); } void LLLineEditor::doDelete() { - if (canDoDelete() && mText.length() > 0) - { - // Prepare for possible rollback - LLLineEditorRollback rollback( this ); - - if (hasSelection()) - { - deleteSelection(); - } - else if ( getCursor() < mText.length()) - { - const LLWString& text_to_delete = mText.getWString().substr(getCursor(), 1); - - if (!prevalidateInput(text_to_delete)) - { - onKeystroke(); - return; - } - setCursor(getCursor() + 1); - removeChar(); - } - - // Validate new string and rollback the if needed. - BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); - if( need_to_rollback ) - { - rollback.doRollback( this ); - LLUI::getInstance()->reportBadKeystroke(); - } - else - { - onKeystroke(); - - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); - } - } + if (canDoDelete() && mText.length() > 0) + { + // Prepare for possible rollback + LLLineEditorRollback rollback( this ); + + if (hasSelection()) + { + deleteSelection(); + } + else if ( getCursor() < mText.length()) + { + const LLWString& text_to_delete = mText.getWString().substr(getCursor(), 1); + + if (!prevalidateInput(text_to_delete)) + { + onKeystroke(); + return; + } + setCursor(getCursor() + 1); + removeChar(); + } + + // Validate new string and rollback the if needed. + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); + if (need_to_rollback) + { + rollback.doRollback(this); + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + } + else + { + onKeystroke(); + + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + } + } } void LLLineEditor::drawBackground() { - F32 alpha = getCurrentTransparency(); - if (mUseBgColor) - { - gl_rect_2d(getLocalRect(), mBgColor % alpha, TRUE); - } - else - { - bool has_focus = hasFocus(); - LLUIImage* image; - if (mReadOnly) - { - image = mBgImageDisabled; - } - else if (has_focus || mShowImageFocused) - { - image = mBgImageFocused; - } - else - { - image = mBgImage; - } - - if (!image) return; - // optionally draw programmatic border - if (has_focus) - { - LLColor4 tmp_color = gFocusMgr.getFocusColor(); - tmp_color.setAlpha(alpha); - image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), - tmp_color, - gFocusMgr.getFocusFlashWidth()); - } - LLColor4 tmp_color = UI_VERTEX_COLOR; - tmp_color.setAlpha(alpha); - image->draw(getLocalRect(), tmp_color); - } -} - -//virtual -const std::string LLLineEditor::getToolTip() const -{ - if (sDebugUnicode) - { - std::string text = getText(); - std::string tooltip = utf8str_showBytesUTF8(text); - return tooltip; - } - - return LLUICtrl::getToolTip(); -} - -//virtual + F32 alpha = getCurrentTransparency(); + if (mUseBgColor) + { + gl_rect_2d(getLocalRect(), mBgColor % alpha, TRUE); + } + else + { + bool has_focus = hasFocus(); + LLUIImage* image; + if (mReadOnly) + { + image = mBgImageDisabled; + } + else if (has_focus || mShowImageFocused) + { + image = mBgImageFocused; + } + else + { + image = mBgImage; + } + + if (!image) return; + // optionally draw programmatic border + if (has_focus) + { + LLColor4 tmp_color = gFocusMgr.getFocusColor(); + tmp_color.setAlpha(alpha); + image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), + tmp_color, + gFocusMgr.getFocusFlashWidth()); + } + LLColor4 tmp_color = UI_VERTEX_COLOR; + tmp_color.setAlpha(alpha); + image->draw(getLocalRect(), tmp_color); + } +} + +//virtual void LLLineEditor::draw() { - F32 alpha = getDrawContext().mAlpha; - S32 text_len = mText.length(); - static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0); - static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - - std::string saved_text; - if (mDrawAsterixes) - { - saved_text = mText.getString(); - std::string text; - for (S32 i = 0; i < mText.length(); i++) - { - text += PASSWORD_ASTERISK; - } - mText = text; - } - - // draw rectangle for the background - LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - background.stretch( -mBorderThickness ); - - S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2; - if (mSpellCheck) - { - lineeditor_v_pad += 1; - } - - drawBackground(); - - // draw text - - // With viewer-2 art files, input region is 2 pixels up - S32 cursor_bottom = background.mBottom + 2; - S32 cursor_top = background.mTop - 1; - - LLColor4 text_color; - if (!mReadOnly) - { - if (!getTentative()) - { - text_color = mFgColor.get(); - } - else - { - text_color = mTentativeFgColor.get(); - } - } - else - { - text_color = mReadOnlyFgColor.get(); - } - text_color.setAlpha(alpha); - LLColor4 label_color = mTentativeFgColor.get(); - label_color.setAlpha(alpha); - - if (hasPreeditString()) - { - // Draw preedit markers. This needs to be before drawing letters. - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - const S32 preedit_left = mPreeditPositions[i]; - const S32 preedit_right = mPreeditPositions[i + 1]; - if (preedit_right > mScrollHPos) - { - S32 preedit_pixels_left = findPixelNearestPos(llmax(preedit_left, mScrollHPos) - getCursor()); - S32 preedit_pixels_right = llmin(findPixelNearestPos(preedit_right - getCursor()), background.mRight); - if (preedit_pixels_left >= background.mRight) - { - break; - } - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_pixels_left + preedit_standout_gap, - background.mBottom + preedit_standout_position, - preedit_pixels_right - preedit_standout_gap - 1, - background.mBottom + preedit_standout_position - preedit_standout_thickness, - (text_color * preedit_standout_brightness - + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(alpha/*1.0f*/)); - } - else - { - gl_rect_2d(preedit_pixels_left + preedit_marker_gap, - background.mBottom + preedit_marker_position, - preedit_pixels_right - preedit_marker_gap - 1, - background.mBottom + preedit_marker_position - preedit_marker_thickness, - (text_color * preedit_marker_brightness - + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(alpha/*1.0f*/)); - } - } - } - } - - S32 rendered_text = 0; - F32 rendered_pixels_right = (F32)mTextLeftEdge; - F32 text_bottom = (F32)background.mBottom + (F32)lineeditor_v_pad; - - if( (gFocusMgr.getKeyboardFocus() == this) && hasSelection() ) - { - S32 select_left; - S32 select_right; - if (mSelectionStart < mSelectionEnd) - { - select_left = mSelectionStart; - select_right = mSelectionEnd; - } - else - { - select_left = mSelectionEnd; - select_right = mSelectionStart; - } - - if( select_left > mScrollHPos ) - { - // unselected, left side - rendered_text = mGLFont->render( - mText, mScrollHPos, - rendered_pixels_right, text_bottom, - text_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - select_left - mScrollHPos, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right); - } - - if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) - { - LLColor4 color = mHighlightColor; - color.setAlpha(alpha); - // selected middle - S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text); - width = llmin(width, mTextRightEdge - ll_round(rendered_pixels_right)); - gl_rect_2d(ll_round(rendered_pixels_right), cursor_top, ll_round(rendered_pixels_right)+width, cursor_bottom, color); - - LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); - rendered_text += mGLFont->render( - mText, mScrollHPos + rendered_text, - rendered_pixels_right, text_bottom, - tmp_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - select_right - mScrollHPos - rendered_text, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right); - } - - if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) - { - // unselected, right side - rendered_text += mGLFont->render( - mText, mScrollHPos + rendered_text, - rendered_pixels_right, text_bottom, - text_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - S32_MAX, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right); - } - } - else - { - rendered_text = mGLFont->render( - mText, mScrollHPos, - rendered_pixels_right, text_bottom, - text_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - S32_MAX, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right); - } + F32 alpha = getDrawContext().mAlpha; + S32 text_len = mText.length(); + static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0); + static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + + std::string saved_text; + if (mDrawAsterixes) + { + saved_text = mText.getString(); + std::string text; + for (S32 i = 0; i < mText.length(); i++) + { + text += PASSWORD_ASTERISK; + } + mText = text; + } + + // draw rectangle for the background + LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + background.stretch( -mBorderThickness ); + + S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2; + if (mSpellCheck) + { + lineeditor_v_pad += 1; + } + + drawBackground(); + + // draw text + + // With viewer-2 art files, input region is 2 pixels up + S32 cursor_bottom = background.mBottom + 2; + S32 cursor_top = background.mTop - 1; + + LLColor4 text_color; + if (!mReadOnly) + { + if (!getTentative()) + { + text_color = mFgColor.get(); + } + else + { + text_color = mTentativeFgColor.get(); + } + } + else + { + text_color = mReadOnlyFgColor.get(); + } + text_color.setAlpha(alpha); + LLColor4 label_color = mTentativeFgColor.get(); + label_color.setAlpha(alpha); + + if (hasPreeditString()) + { + // Draw preedit markers. This needs to be before drawing letters. + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + const S32 preedit_left = mPreeditPositions[i]; + const S32 preedit_right = mPreeditPositions[i + 1]; + if (preedit_right > mScrollHPos) + { + S32 preedit_pixels_left = findPixelNearestPos(llmax(preedit_left, mScrollHPos) - getCursor()); + S32 preedit_pixels_right = llmin(findPixelNearestPos(preedit_right - getCursor()), background.mRight); + if (preedit_pixels_left >= background.mRight) + { + break; + } + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_pixels_left + preedit_standout_gap, + background.mBottom + preedit_standout_position, + preedit_pixels_right - preedit_standout_gap - 1, + background.mBottom + preedit_standout_position - preedit_standout_thickness, + (text_color * preedit_standout_brightness + + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(alpha/*1.0f*/)); + } + else + { + gl_rect_2d(preedit_pixels_left + preedit_marker_gap, + background.mBottom + preedit_marker_position, + preedit_pixels_right - preedit_marker_gap - 1, + background.mBottom + preedit_marker_position - preedit_marker_thickness, + (text_color * preedit_marker_brightness + + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(alpha/*1.0f*/)); + } + } + } + } + + S32 rendered_text = 0; + F32 rendered_pixels_right = (F32)mTextLeftEdge; + F32 text_bottom = (F32)background.mBottom + (F32)lineeditor_v_pad; + + if( (gFocusMgr.getKeyboardFocus() == this) && hasSelection() ) + { + S32 select_left; + S32 select_right; + if (mSelectionStart < mSelectionEnd) + { + select_left = mSelectionStart; + select_right = mSelectionEnd; + } + else + { + select_left = mSelectionEnd; + select_right = mSelectionStart; + } + + if( select_left > mScrollHPos ) + { + // unselected, left side + rendered_text = mGLFont->render( + mText, mScrollHPos, + rendered_pixels_right, text_bottom, + text_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + select_left - mScrollHPos, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right); + } + + if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) + { + LLColor4 color = mHighlightColor; + color.setAlpha(alpha); + // selected middle + S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text); + width = llmin(width, mTextRightEdge - ll_round(rendered_pixels_right)); + gl_rect_2d(ll_round(rendered_pixels_right), cursor_top, ll_round(rendered_pixels_right)+width, cursor_bottom, color); + + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); + rendered_text += mGLFont->render( + mText, mScrollHPos + rendered_text, + rendered_pixels_right, text_bottom, + tmp_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + select_right - mScrollHPos - rendered_text, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right); + } + + if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) + { + // unselected, right side + rendered_text += mGLFont->render( + mText, mScrollHPos + rendered_text, + rendered_pixels_right, text_bottom, + text_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + S32_MAX, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right); + } + } + else + { + rendered_text = mGLFont->render( + mText, mScrollHPos, + rendered_pixels_right, text_bottom, + text_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + S32_MAX, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right); + } #if 1 // for when we're ready for image art. - mBorder->setVisible(FALSE); // no more programmatic art. + mBorder->setVisible(FALSE); // no more programmatic art. #endif - if ( (getSpellCheck()) && (mText.length() > 2) ) - { - // Calculate start and end indices for the first and last visible word - U32 start = prevWordPos(mScrollHPos), end = nextWordPos(mScrollHPos + rendered_text); - - if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) - { - const LLWString& text = mText.getWString().substr(start, end); - - // Find the start of the first word - U32 word_start = 0, word_end = 0; - while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) ) - { - word_start++; - } - - // Iterate over all words in the text block and check them one by one - mMisspellRanges.clear(); - while (word_start < text.length()) - { - // Find the end of the current word (special case handling for "'" when it's used as a contraction) - word_end = word_start + 1; - while ( (word_end < text.length()) && - ((LLWStringUtil::isPartOfWord(text[word_end])) || - ((L'\'' == text[word_end]) && (word_end + 1 < text.length()) && - (LLStringOps::isAlnum(text[word_end - 1])) && (LLStringOps::isAlnum(text[word_end + 1])))) ) - { - word_end++; - } - if (word_end > text.length()) - { - break; - } - - // Don't process words shorter than 3 characters - std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start)); - if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) - { - mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end)); - } - - // Find the start of the next word - word_start = word_end + 1; - while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) ) - { - word_start++; - } - } - - mSpellCheckStart = start; - mSpellCheckEnd = end; - } - - // Draw squiggly lines under any (visible) misspelled words - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - // Skip over words that aren't (partially) visible - if ( ((it->first < start) && (it->second < start)) || (it->first > end) ) - { - continue; - } - - // Skip the current word if the user is still busy editing it - if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) - { - continue; - } - - S32 pxWidth = getRect().getWidth(); - S32 pxStart = findPixelNearestPos(it->first - getCursor()); - if (pxStart > pxWidth) - { - continue; - } - S32 pxEnd = findPixelNearestPos(it->second - getCursor()); - if (pxEnd > pxWidth) - { - pxEnd = pxWidth; - } - - S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight()); - - gGL.color4ub(255, 0, 0, 200); - while (pxStart + 1 < pxEnd) - { - gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2); - if (pxStart + 3 < pxEnd) - { - gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1); - } - pxStart += 4; - } - } - } - - // If we're editing... - if( hasFocus()) - { - //mBorder->setVisible(TRUE); // ok, programmer art just this once. - // (Flash the cursor every half second) - if (!mReadOnly && gFocusMgr.getAppHasFocus()) - { - F32 elapsed = mKeystrokeTimer.getElapsedTimeF32(); - if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) ) - { - S32 cursor_left = findPixelNearestPos(); - cursor_left -= lineeditor_cursor_thickness / 2; - S32 cursor_right = cursor_left + lineeditor_cursor_thickness; - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) - { - const LLWString space(utf8str_to_wstring(std::string(" "))); - S32 wswidth = mGLFont->getWidth(space.c_str()); - S32 width = mGLFont->getWidth(mText.getWString().c_str(), getCursor(), 1) + 1; - cursor_right = cursor_left + llmax(wswidth, width); - } - // Use same color as text for the Cursor - gl_rect_2d(cursor_left, cursor_top, - cursor_right, cursor_bottom, text_color); - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) - { - LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); - mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom, - tmp_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - 1); - } - - // Make sure the IME is in the right place - S32 pixels_after_scroll = findPixelNearestPos(); // RCalculcate for IME position - LLRect screen_pos = calcScreenRect(); - LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - lineeditor_v_pad ); - - ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]); - ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]); - getWindow()->setLanguageTextInput( ime_pos ); - } - } - - //draw label if no text is provided - //but we should draw it in a different color - //to give indication that it is not text you typed in - if (0 == mText.length() && (mReadOnly || mShowLabelFocused)) - { - mGLFont->render(mLabel.getWString(), 0, - mTextLeftEdge, (F32)text_bottom, - label_color, - LLFontGL::LEFT, - LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - S32_MAX, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right, FALSE); - } - - - // Draw children (border) - //mBorder->setVisible(TRUE); - mBorder->setKeyboardFocusHighlight( TRUE ); - LLView::draw(); - mBorder->setKeyboardFocusHighlight( FALSE ); - //mBorder->setVisible(FALSE); - } - else // does not have keyboard input - { - // draw label if no text provided - if (0 == mText.length()) - { - mGLFont->render(mLabel.getWString(), 0, - mTextLeftEdge, (F32)text_bottom, - label_color, - LLFontGL::LEFT, - LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - S32_MAX, - mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right); - } - // Draw children (border) - LLView::draw(); - } - - if (mDrawAsterixes) - { - mText = saved_text; - } + if ( (getSpellCheck()) && (mText.length() > 2) ) + { + // Calculate start and end indices for the first and last visible word + U32 start = prevWordPos(mScrollHPos), end = nextWordPos(mScrollHPos + rendered_text); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) + { + const LLWString& text = mText.getWString().substr(start, end); + + // Find the start of the first word + U32 word_start = 0, word_end = 0; + while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) ) + { + word_start++; + } + + // Iterate over all words in the text block and check them one by one + mMisspellRanges.clear(); + while (word_start < text.length()) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < text.length()) && + ((LLWStringUtil::isPartOfWord(text[word_end])) || + ((L'\'' == text[word_end]) && (word_end + 1 < text.length()) && + (LLStringOps::isAlnum(text[word_end - 1])) && (LLStringOps::isAlnum(text[word_end + 1])))) ) + { + word_end++; + } + if (word_end > text.length()) + { + break; + } + + // Don't process words shorter than 3 characters + std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start)); + if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { + mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end)); + } + + // Find the start of the next word + word_start = word_end + 1; + while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) ) + { + word_start++; + } + } + + mSpellCheckStart = start; + mSpellCheckEnd = end; + } + + // Draw squiggly lines under any (visible) misspelled words + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + // Skip over words that aren't (partially) visible + if ( ((it->first < start) && (it->second < start)) || (it->first > end) ) + { + continue; + } + + // Skip the current word if the user is still busy editing it + if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + continue; + } + + S32 pxWidth = getRect().getWidth(); + S32 pxStart = findPixelNearestPos(it->first - getCursor()); + if (pxStart > pxWidth) + { + continue; + } + S32 pxEnd = findPixelNearestPos(it->second - getCursor()); + if (pxEnd > pxWidth) + { + pxEnd = pxWidth; + } + + S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight()); + + gGL.color4ub(255, 0, 0, 200); + while (pxStart + 1 < pxEnd) + { + gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2); + if (pxStart + 3 < pxEnd) + { + gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1); + } + pxStart += 4; + } + } + } + + // If we're editing... + if( hasFocus()) + { + //mBorder->setVisible(TRUE); // ok, programmer art just this once. + // (Flash the cursor every half second) + if (!mReadOnly && gFocusMgr.getAppHasFocus()) + { + F32 elapsed = mKeystrokeTimer.getElapsedTimeF32(); + if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) ) + { + S32 cursor_left = findPixelNearestPos(); + cursor_left -= lineeditor_cursor_thickness / 2; + S32 cursor_right = cursor_left + lineeditor_cursor_thickness; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) + { + const LLWString space(utf8str_to_wstring(std::string(" "))); + S32 wswidth = mGLFont->getWidth(space.c_str()); + S32 width = mGLFont->getWidth(mText.getWString().c_str(), getCursor(), 1) + 1; + cursor_right = cursor_left + llmax(wswidth, width); + } + // Use same color as text for the Cursor + gl_rect_2d(cursor_left, cursor_top, + cursor_right, cursor_bottom, text_color); + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) + { + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); + mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom, + tmp_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + 1); + } + + // Make sure the IME is in the right place + S32 pixels_after_scroll = findPixelNearestPos(); // RCalculcate for IME position + LLRect screen_pos = calcScreenRect(); + LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - lineeditor_v_pad ); + + ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]); + ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]); + getWindow()->setLanguageTextInput( ime_pos ); + } + } + + //draw label if no text is provided + //but we should draw it in a different color + //to give indication that it is not text you typed in + if (0 == mText.length() && (mReadOnly || mShowLabelFocused)) + { + mGLFont->render(mLabel.getWString(), 0, + mTextLeftEdge, (F32)text_bottom, + label_color, + LLFontGL::LEFT, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + S32_MAX, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right, FALSE); + } + + + // Draw children (border) + //mBorder->setVisible(TRUE); + mBorder->setKeyboardFocusHighlight( TRUE ); + LLView::draw(); + mBorder->setKeyboardFocusHighlight( FALSE ); + //mBorder->setVisible(FALSE); + } + else // does not have keyboard input + { + // draw label if no text provided + if (0 == mText.length()) + { + mGLFont->render(mLabel.getWString(), 0, + mTextLeftEdge, (F32)text_bottom, + label_color, + LLFontGL::LEFT, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + S32_MAX, + mTextRightEdge - ll_round(rendered_pixels_right), + &rendered_pixels_right); + } + // Draw children (border) + LLView::draw(); + } + + if (mDrawAsterixes) + { + mText = saved_text; + } } // Returns the local screen space X coordinate associated with the text cursor position. S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const { - S32 dpos = getCursor() - mScrollHPos + cursor_offset; - S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mTextLeftEdge; - return result; + S32 dpos = getCursor() - mScrollHPos + cursor_offset; + S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mTextLeftEdge; + return result; } S32 LLLineEditor::calcCursorPos(S32 mouse_x) { - const llwchar* wtext = mText.getWString().c_str(); - LLWString asterix_text; - if (mDrawAsterixes) - { - for (S32 i = 0; i < mText.length(); i++) - { - asterix_text += utf8str_to_wstring(PASSWORD_ASTERISK); - } - wtext = asterix_text.c_str(); - } - - S32 cur_pos = mScrollHPos + - mGLFont->charFromPixelOffset( - wtext, mScrollHPos, - (F32)(mouse_x - mTextLeftEdge), - (F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive - - return cur_pos; + const llwchar* wtext = mText.getWString().c_str(); + LLWString asterix_text; + if (mDrawAsterixes) + { + for (S32 i = 0; i < mText.length(); i++) + { + asterix_text += utf8str_to_wstring(PASSWORD_ASTERISK); + } + wtext = asterix_text.c_str(); + } + + S32 cur_pos = mScrollHPos + + mGLFont->charFromPixelOffset( + wtext, mScrollHPos, + (F32)(mouse_x - mTextLeftEdge), + (F32)(mTextRightEdge - mTextLeftEdge + 1)); // min-max range is inclusive + + return cur_pos; } //virtual void LLLineEditor::clear() { - mText.clear(); - setCursor(0); + mText.clear(); + setCursor(0); } //virtual void LLLineEditor::onTabInto() { - selectAll(); + selectAll(); LLUICtrl::onTabInto(); } //virtual BOOL LLLineEditor::acceptsTextInput() const { - return TRUE; + return TRUE; } // Start or stop the editor from accepting text-editing keystrokes void LLLineEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); - - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } - - - // getting focus when we didn't have it before, and we want to select all - if (!old_state && new_state && mSelectAllonFocusReceived) - { - selectAll(); - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection - // here. - mIsSelecting = FALSE; - } - - if( new_state ) - { - gEditMenuHandler = this; - - // Don't start the cursor flashing right away - mKeystrokeTimer.reset(); - } - else - { - // Not really needed, since loss of keyboard focus should take care of this, - // but limited paranoia is ok. - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - - endSelection(); - } - - LLUICtrl::setFocus( new_state ); - - if (new_state) - { - // Allow Language Text Input only when this LineEditor has - // no prevalidate function attached. This criterion works - // fine on 1.15.0.2, since all prevalidate func reject any - // non-ASCII characters. I'm not sure on future versions, - // however. - getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL); - } -} - -//virtual + BOOL old_state = hasFocus(); + + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } + + + // getting focus when we didn't have it before, and we want to select all + if (!old_state && new_state && mSelectAllonFocusReceived) + { + selectAll(); + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection + // here. + mIsSelecting = FALSE; + } + + if( new_state ) + { + gEditMenuHandler = this; + + // Don't start the cursor flashing right away + mKeystrokeTimer.reset(); + } + else + { + // Not really needed, since loss of keyboard focus should take care of this, + // but limited paranoia is ok. + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } + + endSelection(); + } + + LLUICtrl::setFocus( new_state ); + + if (new_state) + { + // Allow Language Text Input only when this LineEditor has + // no prevalidate function attached. This criterion works + // fine on 1.15.0.2, since all prevalidate func reject any + // non-ASCII characters. I'm not sure on future versions, + // however. + getWindow()->allowLanguageTextInput(this, !mPrevalidator); + } +} + +//virtual void LLLineEditor::setRect(const LLRect& rect) { - LLUICtrl::setRect(rect); - if (mBorder) - { - LLRect border_rect = mBorder->getRect(); - // Scalable UI somehow made these rectangles off-by-one. - // I don't know why. JC - border_rect.setOriginAndSize(border_rect.mLeft, border_rect.mBottom, - rect.getWidth()-1, rect.getHeight()-1); - mBorder->setRect(border_rect); - } + LLUICtrl::setRect(rect); + if (mBorder) + { + LLRect border_rect = mBorder->getRect(); + // Scalable UI somehow made these rectangles off-by-one. + // I don't know why. JC + border_rect.setOriginAndSize(border_rect.mLeft, border_rect.mBottom, + rect.getWidth()-1, rect.getHeight()-1); + mBorder->setRect(border_rect); + } } -void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidate(LLTextValidate::Validator validator) { - mPrevalidateFunc = func; - updateAllowingLanguageInput(); + mPrevalidator = validator; + updateAllowingLanguageInput(); } -void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func) +void LLLineEditor::setPrevalidateInput(LLTextValidate::Validator validator) { - mPrevalidateInputFunc = func; - updateAllowingLanguageInput(); + mInputPrevalidator = validator; + updateAllowingLanguageInput(); } bool LLLineEditor::prevalidateInput(const LLWString& wstr) { - if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr)) - { - return false; - } - - return true; + return mInputPrevalidator.validate(wstr); } // static BOOL LLLineEditor::postvalidateFloat(const std::string &str) { - LLLocale locale(LLLocale::USER_LOCALE); - - BOOL success = TRUE; - BOOL has_decimal = FALSE; - BOOL has_digit = FALSE; - - LLWString trimmed = utf8str_to_wstring(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++; - } - - // May be a comma or period, depending on the locale - llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint(); - - for( ; i < len; i++ ) - { - if( decimal_point == trimmed[i] ) - { - if( has_decimal ) - { - // can't have two - success = FALSE; - break; - } - else - { - has_decimal = TRUE; - } - } - else - if( LLStringOps::isDigit( trimmed[i] ) ) - { - has_digit = TRUE; - } - else - { - success = FALSE; - break; - } - } - } - - // Gotta have at least one - success = has_digit; - - return success; + LLLocale locale(LLLocale::USER_LOCALE); + + BOOL success = TRUE; + BOOL has_decimal = FALSE; + BOOL has_digit = FALSE; + + LLWString trimmed = utf8str_to_wstring(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++; + } + + // May be a comma or period, depending on the locale + llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint(); + + for( ; i < len; i++ ) + { + if( decimal_point == trimmed[i] ) + { + if( has_decimal ) + { + // can't have two + success = FALSE; + break; + } + else + { + has_decimal = TRUE; + } + } + else + if( LLStringOps::isDigit( trimmed[i] ) ) + { + has_digit = TRUE; + } + else + { + success = FALSE; + break; + } + } + } + + // Gotta have at least one + success = has_digit; + + return success; } BOOL LLLineEditor::evaluateFloat() { - bool success; - F32 result = 0.f; - std::string expr = getText(); - LLStringUtil::toUpper(expr); + bool success; + F32 result = 0.f; + std::string expr = getText(); + LLStringUtil::toUpper(expr); - success = LLCalc::getInstance()->evalString(expr, result); + success = LLCalc::getInstance()->evalString(expr, result); - if (!success) - { - // Move the cursor to near the error on failure - setCursor(LLCalc::getInstance()->getLastErrorPos()); - // *TODO: Translated error message indicating the type of error? Select error text? - } - else - { - // Replace the expression with the result - std::string result_str = llformat("%f",result); - setText(result_str); - selectAll(); - } + if (!success) + { + // Move the cursor to near the error on failure + setCursor(LLCalc::getInstance()->getLastErrorPos()); + // *TODO: Translated error message indicating the type of error? Select error text? + } + else + { + // Replace the expression with the result + std::string result_str = llformat("%f",result); + setText(result_str); + selectAll(); + } - return success; + return success; } void LLLineEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } void LLLineEditor::setSelectAllonFocusReceived(BOOL b) { - mSelectAllonFocusReceived = b; + mSelectAllonFocusReceived = b; } void LLLineEditor::onKeystroke() { - if (mKeystrokeCallback) - { - mKeystrokeCallback(this); - } + if (mKeystrokeCallback) + { + mKeystrokeCallback(this); + } - mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckStart = mSpellCheckEnd = -1; } void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data) { - mKeystrokeCallback = boost::bind(callback, _1, user_data); + mKeystrokeCallback = boost::bind(callback, _1, user_data); } BOOL LLLineEditor::setTextArg( const std::string& key, const LLStringExplicit& text ) { - mText.setArg(key, text); - return TRUE; + mText.setArg(key, text); + return TRUE; } BOOL LLLineEditor::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - mLabel.setArg(key, text); - return TRUE; + mLabel.setArg(key, text); + return TRUE; } void LLLineEditor::updateAllowingLanguageInput() { - // Allow Language Text Input only when this LineEditor has - // no prevalidate function attached (as long as other criteria - // common to LLTextEditor). This criterion works - // fine on 1.15.0.2, since all prevalidate func reject any - // non-ASCII characters. I'm not sure on future versions, - // however... - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + // Allow Language Text Input only when this LineEditor has + // no prevalidate function attached (as long as other criteria + // common to LLTextEditor). This criterion works + // fine on 1.15.0.2, since all prevalidate func reject any + // non-ASCII characters. I'm not sure on future versions, + // however... + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly && !mDrawAsterixes && !mPrevalidator) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } BOOL LLLineEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLLineEditor::resetPreedit() { - if (hasSelection()) - { - if (hasPreeditString()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } - else - { - deleteSelection(); - } - } - if (hasPreeditString()) - { - const S32 preedit_pos = mPreeditPositions.front(); - mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos); - mText.insert(preedit_pos, mPreeditOverwrittenWString); - setCursor(preedit_pos); - - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); - - // Don't reset key stroke timer nor invoke keystroke callback, - // because a call to updatePreedit should be follow soon in - // normal course of operation, and timer and callback will be - // maintained there. Doing so here made an odd sound. (VWR-3410) - } + if (hasSelection()) + { + if (hasPreeditString()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } + else + { + deleteSelection(); + } + } + if (hasPreeditString()) + { + const S32 preedit_pos = mPreeditPositions.front(); + mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos); + mText.insert(preedit_pos, mPreeditOverwrittenWString); + setCursor(preedit_pos); + + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); + + // Don't reset key stroke timer nor invoke keystroke callback, + // because a call to updatePreedit should be follow soon in + // normal course of operation, and timer and callback will be + // maintained there. Doing so here made an odd sound. (VWR-3410) + } } void LLLineEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) -{ - // Just in case. - if (mReadOnly) - { - return; - } - - // Note that call to updatePreedit is always preceeded by resetPreedit, - // so we have no existing selection/preedit. - - S32 insert_preedit_at = getCursor(); - - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString.assign( LLWString( mText, insert_preedit_at, mPreeditWString.length() ) ); - mText.erase(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } - mText.insert(insert_preedit_at, mPreeditWString); - - mPreeditStandouts = preedit_standouts; - - setCursor(position); - setCursor(mPreeditPositions.front() + caret_position); - - // Update of the preedit should be caused by some key strokes. - mKeystrokeTimer.reset(); - onKeystroke(); - - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) +{ + // Just in case. + if (mReadOnly) + { + return; + } + + // Note that call to updatePreedit is always preceeded by resetPreedit, + // so we have no existing selection/preedit. + + S32 insert_preedit_at = getCursor(); + + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString.assign( LLWString( mText, insert_preedit_at, mPreeditWString.length() ) ); + mText.erase(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } + mText.insert(insert_preedit_at, mPreeditWString); + + mPreeditStandouts = preedit_standouts; + + setCursor(position); + setCursor(mPreeditPositions.front() + caret_position); + + // Update of the preedit should be caused by some key strokes. + mKeystrokeTimer.reset(); + onKeystroke(); + + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(getRect(), &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_column, preedit_right_column; - if (hasPreeditString()) - { - preedit_left_column = mPreeditPositions.front(); - preedit_right_column = mPreeditPositions.back(); - } - else - { - preedit_left_column = preedit_right_column = getCursor(); - } - if (preedit_right_column < mScrollHPos) - { - // This should not occure... - return FALSE; - } - - const S32 query = (query_offset >= 0 ? preedit_left_column + query_offset : getCursor()); - if (query < mScrollHPos || query < preedit_left_column || query > preedit_right_column) - { - return FALSE; - } - - if (coord) - { - S32 query_local = findPixelNearestPos(query - getCursor()); - S32 query_screen_x, query_screen_y; - localPointToScreen(query_local, getRect().getHeight() / 2, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left_local = findPixelNearestPos(llmax(preedit_left_column, mScrollHPos) - getCursor()); - S32 preedit_right_local = llmin(findPixelNearestPos(preedit_right_column - getCursor()), getRect().getWidth() - mBorderThickness); - if (preedit_left_local > preedit_right_local) - { - // Is this condition possible? - preedit_right_local = preedit_left_local; - } - - LLRect preedit_rect_local(preedit_left_local, getRect().getHeight(), preedit_right_local, 0); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + if (control) + { + LLRect control_rect_screen; + localRectToScreen(getRect(), &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_column, preedit_right_column; + if (hasPreeditString()) + { + preedit_left_column = mPreeditPositions.front(); + preedit_right_column = mPreeditPositions.back(); + } + else + { + preedit_left_column = preedit_right_column = getCursor(); + } + if (preedit_right_column < mScrollHPos) + { + // This should not occure... + return FALSE; + } + + const S32 query = (query_offset >= 0 ? preedit_left_column + query_offset : getCursor()); + if (query < mScrollHPos || query < preedit_left_column || query > preedit_right_column) + { + return FALSE; + } + + if (coord) + { + S32 query_local = findPixelNearestPos(query - getCursor()); + S32 query_screen_x, query_screen_y; + localPointToScreen(query_local, getRect().getHeight() / 2, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left_local = findPixelNearestPos(llmax(preedit_left_column, mScrollHPos) - getCursor()); + S32 preedit_right_local = llmin(findPixelNearestPos(preedit_right_column - getCursor()), getRect().getWidth() - mBorderThickness); + if (preedit_left_local > preedit_right_local) + { + // Is this condition possible? + preedit_right_local = preedit_left_local; + } + + LLRect preedit_rect_local(preedit_left_local, getRect().getHeight(), preedit_right_local, 0); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLLineEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLLineEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLLineEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursor(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString.assign( LLWString( mText.getWString(), position, length ) ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursor(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString.assign( LLWString( mText.getWString(), position, length ) ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLLineEditor::getPreeditFontSize() const { - return ll_round(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } void LLLineEditor::setReplaceNewlinesWithSpaces(BOOL replace) { - mReplaceNewlinesWithSpaces = replace; + mReplaceNewlinesWithSpaces = replace; } LLWString LLLineEditor::getConvertedText() const { - LLWString text = getWText(); - LLWStringUtil::trim(text); - if (!mReplaceNewlinesWithSpaces) - { - LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. - } - return text; + LLWString text = getWText(); + LLWStringUtil::trim(text); + if (!mReplaceNewlinesWithSpaces) + { + LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. + } + return text; } void LLLineEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile<LLContextMenu> - ("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); - setContextMenu(menu); - } - - if (menu) - { - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursor(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); - } + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile<LLContextMenu> + ("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); + setContextMenu(menu); + } + + if (menu) + { + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursor(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); + } } void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu) @@ -2715,5 +2731,5 @@ void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu) void LLLineEditor::setFont(const LLFontGL* font) { - mGLFont = font; + mGLFont = font; } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 5794b3c35a..340308535f 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -1,34 +1,34 @@ -/** +/** * @file lllineeditor.h * @brief Text editor widget to let users enter/edit a single line. * - * Features: - * Text entry of a single line (text, delete, left and right arrow, insert, return). - * Callbacks either on every keystroke or just on the return key. - * Focus (allow multiple text entry widgets) - * Clipboard (cut, copy, and paste) - * Horizontal scrolling to allow strings longer than widget size allows - * Pre-validation (limit which keys can be used) - * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * Features: + * Text entry of a single line (text, delete, left and right arrow, insert, return). + * Callbacks either on every keystroke or just on the return key. + * Focus (allow multiple text entry widgets) + * Clipboard (cut, copy, and paste) + * Horizontal scrolling to allow strings longer than widget size allows + * Pre-validation (limit which keys can be used) + * Optional line history so previous entries can be recalled by CTRL UP/DOWN * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,412 +59,414 @@ class LLLineEditor { public: - typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t; - - struct MaxLength : public LLInitParam::ChoiceBlock<MaxLength> - { - Alternative<S32> bytes, chars; - - MaxLength() : bytes("max_length_bytes", 254), - chars("max_length_chars", 0) - {} - }; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<std::string> default_text; - Optional<MaxLength> max_length; - Optional<keystroke_callback_t> keystroke_callback; - - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback; - Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_input_callback; - - Optional<LLViewBorder::Params> border; - - Optional<LLUIImage*> background_image, - background_image_disabled, - background_image_focused; - - Optional<bool> select_on_focus, - revert_on_esc, - spellcheck, - commit_on_focus_lost, - ignore_tab, - bg_image_always_focused, - show_label_focused, - is_password, - use_bg_color; - - // colors - Optional<LLUIColor> cursor_color, - bg_color, - text_color, - text_readonly_color, - text_tentative_color, - highlight_color, - preedit_bg_color; - - Optional<S32> text_pad_left, - text_pad_right; - - Ignored bg_visible; - - Params(); - }; - - void initFromParams(const LLLineEditor::Params& params); + typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t; + + struct MaxLength : public LLInitParam::ChoiceBlock<MaxLength> + { + Alternative<S32> bytes, chars; + + MaxLength() : bytes("max_length_bytes", 254), + chars("max_length_chars", 0) + {} + }; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<std::string> default_text; + Optional<MaxLength> max_length; + Optional<keystroke_callback_t> keystroke_callback; + + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator; + + Optional<LLViewBorder::Params> border; + + Optional<LLUIImage*> background_image, + background_image_disabled, + background_image_focused; + + Optional<bool> select_on_focus, + revert_on_esc, + spellcheck, + commit_on_focus_lost, + ignore_tab, + bg_image_always_focused, + show_label_focused, + is_password, + allow_emoji, + use_bg_color; + + // colors + Optional<LLUIColor> cursor_color, + bg_color, + text_color, + text_readonly_color, + text_tentative_color, + highlight_color, + preedit_bg_color; + + Optional<S32> text_pad_left, + text_pad_right; + + Ignored bg_visible; + + Params(); + }; + + void initFromParams(const LLLineEditor::Params& params); protected: - LLLineEditor(const Params&); - friend class LLUICtrlFactory; - friend class LLFloaterEditUI; - void showContextMenu(S32 x, S32 y); + LLLineEditor(const Params&); + friend class LLUICtrlFactory; + friend class LLFloaterEditUI; + void showContextMenu(S32 x, S32 y); public: - virtual ~LLLineEditor(); - - // mousehandler overrides - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask) override; - /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask) override; - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; - /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char) override; - /*virtual*/ void onMouseCaptureLost() override; - - // LLEditMenuHandler overrides - /*virtual*/ void cut() override; - /*virtual*/ BOOL canCut() const override; - /*virtual*/ void copy() override; - /*virtual*/ BOOL canCopy() const override; - /*virtual*/ void paste() override; - /*virtual*/ BOOL canPaste() const override; - - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; - - /*virtual*/ void doDelete() override; - /*virtual*/ BOOL canDoDelete() const override; - - /*virtual*/ void selectAll() override; - /*virtual*/ BOOL canSelectAll() const override; - - /*virtual*/ void deselect() override; - /*virtual*/ BOOL canDeselect() const override; - - // LLSpellCheckMenuHandler overrides - /*virtual*/ bool getSpellCheck() const override; - - /*virtual*/ const std::string& getSuggestion(U32 index) const override; - /*virtual*/ U32 getSuggestionCount() const override; - /*virtual*/ void replaceWithSuggestion(U32 index) override; - - /*virtual*/ void addToDictionary() override; - /*virtual*/ bool canAddToDictionary() const override; - - /*virtual*/ void addToIgnore() override; - /*virtual*/ bool canAddToIgnore() const override; - - // Spell checking helper functions - std::string getMisspelledWord(U32 pos) const; - bool isMisspelledWord(U32 pos) const; - void onSpellCheckSettingsChange(); - - // view overrides - /*virtual*/ const std::string getToolTip() const override; - /*virtual*/ void draw() override; - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; - /*virtual*/ void onFocusReceived() override; - /*virtual*/ void onFocusLost() override; - /*virtual*/ void setEnabled(BOOL enabled) override; - - // UI control overrides - /*virtual*/ void clear() override; - /*virtual*/ void onTabInto() override; - /*virtual*/ void setFocus(BOOL b) override; - /*virtual*/ void setRect(const LLRect& rect) override; - /*virtual*/ BOOL acceptsTextInput() const override; - /*virtual*/ void onCommit() override; - /*virtual*/ BOOL isDirty() const override; // Returns TRUE if user changed value at all - /*virtual*/ void resetDirty() override; // Clear dirty state - - // assumes UTF8 text - /*virtual*/ void setValue(const LLSD& value) override; - /*virtual*/ LLSD getValue() const override; - /*virtual*/ BOOL setTextArg(const std::string& key, const LLStringExplicit& text) override; - /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; - - void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; } - const std::string& getLabel() { return mLabel.getString(); } - - void setText(const LLStringExplicit &new_text); - - const std::string& getText() const { return mText.getString(); } - LLWString getWText() const { return mText.getWString(); } - LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines - - S32 getLength() const { return mText.length(); } - - S32 getCursor() const { return mCursorPos; } - void setCursor( S32 pos ); - void setCursorToEnd(); - - // set scroll to earliest position it can reasonable set - void resetScrollPosition(); - - // Selects characters 'start' to 'end'. - void setSelection(S32 start, S32 end); - /*virtual*/ void getSelectionRange(S32 *position, S32 *length) const override; - - void setCommitOnFocusLost( BOOL b ) { mCommitOnFocusLost = b; } - void setRevertOnEsc( BOOL b ) { mRevertOnEsc = b; } - void setKeystrokeOnEsc(BOOL b) { mKeystrokeOnEsc = b; } - - void setCursorColor(const LLColor4& c) { mCursorColor = c; } - const LLColor4& getCursorColor() const { return mCursorColor.get(); } - - void setFgColor( const LLColor4& c ) { mFgColor = c; } - void setReadOnlyFgColor( const LLColor4& c ) { mReadOnlyFgColor = c; } - void setTentativeFgColor(const LLColor4& c) { mTentativeFgColor = c; } - - const LLColor4& getFgColor() const { return mFgColor.get(); } - const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); } - const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); } - - const LLFontGL* getFont() const { return mGLFont; } - void setFont(const LLFontGL* font); - - void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; } - void setIgnoreTab(BOOL b) { mIgnoreTab = b; } - void setPassDelete(BOOL b) { mPassDelete = b; } - void setDrawAsterixes(BOOL b); - - // get the cursor position of the beginning/end of the prev/next word in the text - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; - - BOOL hasSelection() const { return (mSelectionStart != mSelectionEnd); } - void startSelection(); - void endSelection(); - void extendSelection(S32 new_cursor_pos); - void deleteSelection(); - - void setSelectAllonFocusReceived(BOOL b); - void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; } - - void onKeystroke(); - typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t; - void setKeystrokeCallback(callback_t callback, void* user_data); - - void setMaxTextLength(S32 max_text_length); - void setMaxTextChars(S32 max_text_chars); - // Manipulate left and right padding for text - void getTextPadding(S32 *left, S32 *right); - void setTextPadding(S32 left, S32 right); - - // Prevalidation controls which keystrokes can affect the editor - void setPrevalidate( LLTextValidate::validate_func_t func ); - // This method sets callback that prevents from: - // - deleting, selecting, typing, cutting, pasting characters that are not valid. - // Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed - // symbols, before existing text is modified, but setPrevalidate validates line after it was modified. - void setPrevalidateInput(LLTextValidate::validate_func_t func); - static BOOL postvalidateFloat(const std::string &str); - - bool prevalidateInput(const LLWString& wstr); - BOOL evaluateFloat(); - - // line history support: - void setEnableLineHistory( BOOL enabled ) { mHaveHistory = enabled; } // switches line history on or off - void updateHistory(); // stores current line in history - - void setReplaceNewlinesWithSpaces(BOOL replace); - - void resetContextMenu() { setContextMenu(NULL); }; - - void setBgImage(LLPointer<LLUIImage> image) { mBgImage = image; } - void setBgImageFocused(LLPointer<LLUIImage> image) { mBgImageFocused = image; } + virtual ~LLLineEditor(); + + // mousehandler overrides + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; + /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char) override; + /*virtual*/ void onMouseCaptureLost() override; + + // LLEditMenuHandler overrides + /*virtual*/ void cut() override; + /*virtual*/ BOOL canCut() const override; + /*virtual*/ void copy() override; + /*virtual*/ BOOL canCopy() const override; + /*virtual*/ void paste() override; + /*virtual*/ BOOL canPaste() const override; + + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; + + /*virtual*/ void doDelete() override; + /*virtual*/ BOOL canDoDelete() const override; + + /*virtual*/ void selectAll() override; + /*virtual*/ BOOL canSelectAll() const override; + + /*virtual*/ void deselect() override; + /*virtual*/ BOOL canDeselect() const override; + + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const override; + + /*virtual*/ const std::string& getSuggestion(U32 index) const override; + /*virtual*/ U32 getSuggestionCount() const override; + /*virtual*/ void replaceWithSuggestion(U32 index) override; + + /*virtual*/ void addToDictionary() override; + /*virtual*/ bool canAddToDictionary() const override; + + /*virtual*/ void addToIgnore() override; + /*virtual*/ bool canAddToIgnore() const override; + + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + + // view overrides + /*virtual*/ void draw() override; + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + /*virtual*/ void onFocusReceived() override; + /*virtual*/ void onFocusLost() override; + /*virtual*/ void setEnabled(BOOL enabled) override; + + // UI control overrides + /*virtual*/ void clear() override; + /*virtual*/ void onTabInto() override; + /*virtual*/ void setFocus(BOOL b) override; + /*virtual*/ void setRect(const LLRect& rect) override; + /*virtual*/ BOOL acceptsTextInput() const override; + /*virtual*/ void onCommit() override; + /*virtual*/ BOOL isDirty() const override; // Returns TRUE if user changed value at all + /*virtual*/ void resetDirty() override; // Clear dirty state + + // assumes UTF8 text + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLSD getValue() const override; + /*virtual*/ BOOL setTextArg(const std::string& key, const LLStringExplicit& text) override; + /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; + + void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; } + const std::string& getLabel() { return mLabel.getString(); } + + void setText(const LLStringExplicit &new_text); + + const std::string& getText() const override { return mText.getString(); } + LLWString getWText() const { return mText.getWString(); } + LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines + + S32 getLength() const { return mText.length(); } + + S32 getCursor() const { return mCursorPos; } + void setCursor( S32 pos ); + void setCursorToEnd(); + + // set scroll to earliest position it can reasonable set + void resetScrollPosition(); + + // Selects characters 'start' to 'end'. + void setSelection(S32 start, S32 end); + /*virtual*/ void getSelectionRange(S32 *position, S32 *length) const override; + + void setCommitOnFocusLost( BOOL b ) { mCommitOnFocusLost = b; } + void setRevertOnEsc( BOOL b ) { mRevertOnEsc = b; } + void setKeystrokeOnEsc(BOOL b) { mKeystrokeOnEsc = b; } + + void setCursorColor(const LLColor4& c) { mCursorColor = c; } + const LLColor4& getCursorColor() const { return mCursorColor.get(); } + + void setFgColor( const LLColor4& c ) { mFgColor = c; } + void setReadOnlyFgColor( const LLColor4& c ) { mReadOnlyFgColor = c; } + void setTentativeFgColor(const LLColor4& c) { mTentativeFgColor = c; } + + const LLColor4& getFgColor() const { return mFgColor.get(); } + const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); } + const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); } + + const LLFontGL* getFont() const override { return mGLFont; } + void setFont(const LLFontGL* font); + + void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; } + void setIgnoreTab(BOOL b) { mIgnoreTab = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } + void setAllowEmoji(BOOL b) { mAllowEmoji = b; } + void setDrawAsterixes(BOOL b); + + // get the cursor position of the beginning/end of the prev/next word in the text + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; + + BOOL hasSelection() const { return (mSelectionStart != mSelectionEnd); } + void startSelection(); + void endSelection(); + void extendSelection(S32 new_cursor_pos); + void deleteSelection(); + + void setSelectAllonFocusReceived(BOOL b); + void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; } + + void onKeystroke(); + typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t; + void setKeystrokeCallback(callback_t callback, void* user_data); + + void setMaxTextLength(S32 max_text_length); + void setMaxTextChars(S32 max_text_chars); + // Manipulate left and right padding for text + void getTextPadding(S32 *left, S32 *right); + void setTextPadding(S32 left, S32 right); + + // Prevalidation controls which keystrokes can affect the editor + void setPrevalidate(LLTextValidate::Validator validator); + // This method sets callback that prevents from: + // - deleting, selecting, typing, cutting, pasting characters that are not valid. + // Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed + // symbols, before existing text is modified, but setPrevalidate validates line after it was modified. + void setPrevalidateInput(LLTextValidate::Validator validator); + static BOOL postvalidateFloat(const std::string &str); + + bool prevalidateInput(const LLWString& wstr); + BOOL evaluateFloat(); + + // line history support: + void setEnableLineHistory( BOOL enabled ) { mHaveHistory = enabled; } // switches line history on or off + void updateHistory(); // stores current line in history + + void setReplaceNewlinesWithSpaces(BOOL replace); + + void resetContextMenu() { setContextMenu(NULL); }; + + void setBgImage(LLPointer<LLUIImage> image) { mBgImage = image; } + void setBgImageFocused(LLPointer<LLUIImage> image) { mBgImageFocused = image; } void setShowContextMenu(bool show) { mShowContextMenu = show; } bool getShowContextMenu() const { return mShowContextMenu; } private: - // private helper methods - - void pasteHelper(bool is_primary); - - void removeChar(); - void addChar(const llwchar c); - void setCursorAtLocalPos(S32 local_mouse_x); - S32 findPixelNearestPos(S32 cursor_offset = 0) const; - S32 calcCursorPos(S32 mouse_x); - BOOL handleSpecialKey(KEY key, MASK mask); - BOOL handleSelectionKey(KEY key, MASK mask); - BOOL handleControlKey(KEY key, MASK mask); - S32 handleCommitKey(KEY key, MASK mask); - void updateTextPadding(); - - // Draw the background image depending on enabled/focused state. - void drawBackground(); - - // - // private data members - // - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - // Implementation (overrides) of LLPreeditor - /*virtual*/ void resetPreedit() override; - /*virtual*/ void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) override; - /*virtual*/ void markAsPreedit(S32 position, S32 length) override; - /*virtual*/ void getPreeditRange(S32 *position, S32 *length) const override; - /*virtual*/ BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const override; - /*virtual*/ S32 getPreeditFontSize() const override; - /*virtual*/ LLWString getPreeditString() const override { return getWText(); } - - void setText(const LLStringExplicit &new_text, bool use_size_limit); - - void setContextMenu(LLContextMenu* new_context_menu); + // private helper methods + + void pasteHelper(bool is_primary); + + void removeChar(); + void addChar(const llwchar c); + void setCursorAtLocalPos(S32 local_mouse_x); + S32 findPixelNearestPos(S32 cursor_offset = 0) const; + S32 calcCursorPos(S32 mouse_x); + BOOL handleSpecialKey(KEY key, MASK mask); + BOOL handleSelectionKey(KEY key, MASK mask); + BOOL handleControlKey(KEY key, MASK mask); + S32 handleCommitKey(KEY key, MASK mask); + void updateTextPadding(); + + // Draw the background image depending on enabled/focused state. + void drawBackground(); + + // + // private data members + // + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + // Implementation (overrides) of LLPreeditor + /*virtual*/ void resetPreedit() override; + /*virtual*/ void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) override; + /*virtual*/ void markAsPreedit(S32 position, S32 length) override; + /*virtual*/ void getPreeditRange(S32 *position, S32 *length) const override; + /*virtual*/ BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const override; + /*virtual*/ S32 getPreeditFontSize() const override; + /*virtual*/ LLWString getPreeditString() const override { return getWText(); } + + void setText(const LLStringExplicit &new_text, bool use_size_limit); + + void setContextMenu(LLContextMenu* new_context_menu); protected: - LLUIString mText; // The string being edited. - std::string mPrevText; // Saved string for 'ESC' revert - LLUIString mLabel; // text label that is visible when no user text provided - - // line history support: - BOOL mHaveHistory; // flag for enabled line history - typedef std::vector<std::string> line_history_t; - line_history_t mLineHistory; // line history storage - line_history_t::iterator mCurrentHistoryLine; // currently browsed history line - - LLViewBorder* mBorder; - const LLFontGL* mGLFont; - S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes - S32 mMaxLengthChars; // Maximum number of characters in the string - S32 mCursorPos; // I-beam is just after the mCursorPos-th character. - S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling. - LLFrameTimer mScrollTimer; - S32 mTextPadLeft; // Used to reserve space before the beginning of the text for children. - S32 mTextPadRight; // Used to reserve space after the end of the text for children. - S32 mTextLeftEdge; // Pixels, cached left edge of text based on left padding and width - S32 mTextRightEdge; // Pixels, cached right edge of text based on right padding and width - - BOOL mCommitOnFocusLost; - BOOL mRevertOnEsc; - BOOL mKeystrokeOnEsc; - - keystroke_callback_t mKeystrokeCallback; - - BOOL mIsSelecting; // Selection for clipboard operations - S32 mSelectionStart; - S32 mSelectionEnd; - S32 mLastSelectionX; - S32 mLastSelectionY; - S32 mLastSelectionStart; - S32 mLastSelectionEnd; - - bool mSpellCheck; - S32 mSpellCheckStart; - S32 mSpellCheckEnd; - LLTimer mSpellCheckTimer; - std::list<std::pair<U32, U32> > mMisspellRanges; - std::vector<std::string> mSuggestionList; - - LLTextValidate::validate_func_t mPrevalidateFunc; - LLTextValidate::validate_func_t mPrevalidateInputFunc; - - LLFrameTimer mKeystrokeTimer; - LLTimer mTripleClickTimer; - - LLUIColor mCursorColor; - LLUIColor mBgColor; - LLUIColor mFgColor; - LLUIColor mReadOnlyFgColor; - LLUIColor mTentativeFgColor; - LLUIColor mHighlightColor; // background for selected text - LLUIColor mPreeditBgColor; // preedit marker background color - - S32 mBorderThickness; - - BOOL mIgnoreArrowKeys; - BOOL mIgnoreTab; - BOOL mDrawAsterixes; - - BOOL mSelectAllonFocusReceived; - BOOL mSelectAllonCommit; - BOOL mPassDelete; - - BOOL mReadOnly; - - BOOL mShowImageFocused; - BOOL mShowLabelFocused; - - bool mUseBgColor; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector<S32> mPreeditPositions; - LLPreeditor::standouts_t mPreeditStandouts; - - LLHandle<LLContextMenu> mContextMenuHandle; + LLUIString mText; // The string being edited. + std::string mPrevText; // Saved string for 'ESC' revert + LLUIString mLabel; // text label that is visible when no user text provided + + // line history support: + BOOL mHaveHistory; // flag for enabled line history + typedef std::vector<std::string> line_history_t; + line_history_t mLineHistory; // line history storage + line_history_t::iterator mCurrentHistoryLine; // currently browsed history line + + LLViewBorder* mBorder; + const LLFontGL* mGLFont; + S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes + S32 mMaxLengthChars; // Maximum number of characters in the string + S32 mCursorPos; // I-beam is just after the mCursorPos-th character. + S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling. + LLFrameTimer mScrollTimer; + S32 mTextPadLeft; // Used to reserve space before the beginning of the text for children. + S32 mTextPadRight; // Used to reserve space after the end of the text for children. + S32 mTextLeftEdge; // Pixels, cached left edge of text based on left padding and width + S32 mTextRightEdge; // Pixels, cached right edge of text based on right padding and width + + BOOL mCommitOnFocusLost; + BOOL mRevertOnEsc; + BOOL mKeystrokeOnEsc; + + keystroke_callback_t mKeystrokeCallback; + + BOOL mIsSelecting; // Selection for clipboard operations + S32 mSelectionStart; + S32 mSelectionEnd; + S32 mLastSelectionX; + S32 mLastSelectionY; + S32 mLastSelectionStart; + S32 mLastSelectionEnd; + + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list<std::pair<U32, U32> > mMisspellRanges; + std::vector<std::string> mSuggestionList; + + LLTextValidate::Validator mPrevalidator; + LLTextValidate::Validator mInputPrevalidator; + + LLFrameTimer mKeystrokeTimer; + LLTimer mTripleClickTimer; + + LLUIColor mCursorColor; + LLUIColor mBgColor; + LLUIColor mFgColor; + LLUIColor mReadOnlyFgColor; + LLUIColor mTentativeFgColor; + LLUIColor mHighlightColor; // background for selected text + LLUIColor mPreeditBgColor; // preedit marker background color + + S32 mBorderThickness; + + BOOL mIgnoreArrowKeys; + BOOL mIgnoreTab; + BOOL mDrawAsterixes; + + BOOL mSelectAllonFocusReceived; + BOOL mSelectAllonCommit; + BOOL mPassDelete; + + BOOL mReadOnly; + + BOOL mShowImageFocused; + BOOL mShowLabelFocused; + + bool mAllowEmoji; + bool mUseBgColor; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector<S32> mPreeditPositions; + LLPreeditor::standouts_t mPreeditStandouts; + + LLHandle<LLContextMenu> mContextMenuHandle; bool mShowContextMenu; private: - // Instances that by default point to the statics but can be overidden in XML. - LLPointer<LLUIImage> mBgImage; - LLPointer<LLUIImage> mBgImageDisabled; - LLPointer<LLUIImage> mBgImageFocused; - - BOOL mReplaceNewlinesWithSpaces; // if false, will replace pasted newlines with paragraph symbol. - - // private helper class - class LLLineEditorRollback - { - public: - LLLineEditorRollback( LLLineEditor* ed ) - : - mCursorPos( ed->mCursorPos ), - mScrollHPos( ed->mScrollHPos ), - mIsSelecting( ed->mIsSelecting ), - mSelectionStart( ed->mSelectionStart ), - mSelectionEnd( ed->mSelectionEnd ) - { - mText = ed->getText(); - } - - void doRollback( LLLineEditor* ed ) - { - ed->mCursorPos = mCursorPos; - ed->mScrollHPos = mScrollHPos; - ed->mIsSelecting = mIsSelecting; - ed->mSelectionStart = mSelectionStart; - ed->mSelectionEnd = mSelectionEnd; - ed->mText = mText; - ed->mPrevText = mText; - } - - std::string getText() { return mText; } - - private: - std::string mText; - S32 mCursorPos; - S32 mScrollHPos; - BOOL mIsSelecting; - S32 mSelectionStart; - S32 mSelectionEnd; - }; // end class LLLineEditorRollback + // Instances that by default point to the statics but can be overidden in XML. + LLPointer<LLUIImage> mBgImage; + LLPointer<LLUIImage> mBgImageDisabled; + LLPointer<LLUIImage> mBgImageFocused; + + BOOL mReplaceNewlinesWithSpaces; // if false, will replace pasted newlines with paragraph symbol. + + // private helper class + class LLLineEditorRollback + { + public: + LLLineEditorRollback( LLLineEditor* ed ) + : + mCursorPos( ed->mCursorPos ), + mScrollHPos( ed->mScrollHPos ), + mIsSelecting( ed->mIsSelecting ), + mSelectionStart( ed->mSelectionStart ), + mSelectionEnd( ed->mSelectionEnd ) + { + mText = ed->getText(); + } + + void doRollback( LLLineEditor* ed ) + { + ed->mCursorPos = mCursorPos; + ed->mScrollHPos = mScrollHPos; + ed->mIsSelecting = mIsSelecting; + ed->mSelectionStart = mSelectionStart; + ed->mSelectionEnd = mSelectionEnd; + ed->mText = mText; + ed->mPrevText = mText; + } + + std::string getText() { return mText; } + + private: + std::string mText; + S32 mCursorPos; + S32 mScrollHPos; + BOOL mIsSelecting; + S32 mSelectionStart; + S32 mSelectionEnd; + }; // end class LLLineEditorRollback }; // end class LLLineEditor // Build time optimization, generate once in .cpp file #ifndef LLLINEEDITOR_CPP extern template class LLLineEditor* LLView::getChild<class LLLineEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_LINEEDITOR_ diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp index e8b6b7e43b..70730705e6 100644 --- a/indra/llui/llloadingindicator.cpp +++ b/indra/llui/llloadingindicator.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llloadingindicator.cpp * @brief Perpetual loading indicator * * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,57 +43,57 @@ /////////////////////////////////////////////////////////////////////////////// LLLoadingIndicator::LLLoadingIndicator(const Params& p) -: LLUICtrl(p), - mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f), - mCurImageIdx(0) +: LLUICtrl(p), + mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f), + mCurImageIdx(0) { } void LLLoadingIndicator::initFromParams(const Params& p) { - for (LLUIImage* image : p.images().image) - { - mImages.push_back(image); - } + for (LLUIImage* image : p.images().image) + { + mImages.push_back(image); + } - // Start timer for switching images. - start(); + // Start timer for switching images. + start(); } void LLLoadingIndicator::draw() { - // Time to switch to the next image? - if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired()) - { - // Switch to the next image. - if (!mImages.empty()) - { - mCurImageIdx = (mCurImageIdx + 1) % mImages.size(); - } - - // Restart timer. - start(); - } - - LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx]; - - // Draw current image. - if( cur_image.notNull() ) - { - cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha); - } - - LLUICtrl::draw(); + // Time to switch to the next image? + if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired()) + { + // Switch to the next image. + if (!mImages.empty()) + { + mCurImageIdx = (mCurImageIdx + 1) % mImages.size(); + } + + // Restart timer. + start(); + } + + LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx]; + + // Draw current image. + if( cur_image.notNull() ) + { + cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha); + } + + LLUICtrl::draw(); } void LLLoadingIndicator::stop() { - mImageSwitchTimer.stop(); + mImageSwitchTimer.stop(); } void LLLoadingIndicator::start() { - mImageSwitchTimer.start(); - F32 period = 1.0f / (mImages.size() * mImagesPerSec); - mImageSwitchTimer.setTimerExpirySec(period); + mImageSwitchTimer.start(); + F32 period = 1.0f / (mImages.size() * mImagesPerSec); + mImageSwitchTimer.setTimerExpirySec(period); } diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h index ffcb329f42..5e824af993 100644 --- a/indra/llui/llloadingindicator.h +++ b/indra/llui/llloadingindicator.h @@ -1,25 +1,25 @@ -/** +/** * @file llloadingindicator.h * @brief Perpetual loading indicator * * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,69 +36,69 @@ /** * Perpetual loading indicator (a la MacOSX or YouTube) - * + * * Number of rotations per second can be overridden * with the "images_per_sec" parameter. - * + * * Can start/stop spinning. - * + * * @see start() * @see stop() */ class LLLoadingIndicator : public LLUICtrl { - LOG_CLASS(LLLoadingIndicator); + LOG_CLASS(LLLoadingIndicator); public: - struct Images : public LLInitParam::Block<Images> - { - Multiple<LLUIImage*> image; + struct Images : public LLInitParam::Block<Images> + { + Multiple<LLUIImage*> image; - Images() - : image("image") - {} - }; + Images() + : image("image") + {} + }; - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<F32> images_per_sec; - Optional<Atomic<Images> > images; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<F32> images_per_sec; + Optional<Atomic<Images> > images; - Params() - : images_per_sec("images_per_sec", 1.0f), - images("images") - {} - }; + Params() + : images_per_sec("images_per_sec", 1.0f), + images("images") + {} + }; - virtual ~LLLoadingIndicator() {} + virtual ~LLLoadingIndicator() {} - // llview overrides - virtual void draw(); + // llview overrides + virtual void draw(); - /** - * Stop spinning. - */ - void stop(); + /** + * Stop spinning. + */ + void stop(); - /** - * Start spinning. - */ - void start(); + /** + * Start spinning. + */ + void start(); - void reset() { mCurImageIdx = 0; } + void reset() { mCurImageIdx = 0; } private: - LLLoadingIndicator(const Params&); - void initFromParams(const Params&); + LLLoadingIndicator(const Params&); + void initFromParams(const Params&); - friend class LLUICtrlFactory; + friend class LLUICtrlFactory; - F32 mImagesPerSec; - S8 mCurImageIdx; - LLFrameTimer mImageSwitchTimer; + F32 mImagesPerSec; + S8 mCurImageIdx; + LLFrameTimer mImageSwitchTimer; - std::vector<LLUIImagePtr> mImages; + std::vector<LLUIImagePtr> mImages; }; #endif // LL_LLLOADINGINDICATOR_H diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp index f3a526faeb..f8ccb807e6 100644 --- a/indra/llui/lllocalcliprect.cpp +++ b/indra/llui/lllocalcliprect.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lllocalcliprect.cpp * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,77 +33,77 @@ LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) -: mScissorState(GL_SCISSOR_TEST), - mEnabled(enabled) +: mScissorState(GL_SCISSOR_TEST), + mEnabled(enabled) { - if (mEnabled) - { - pushClipRect(rect); - mScissorState.setEnabled(!sClipRectStack.empty()); - updateScissorRegion(); - } + if (mEnabled) + { + pushClipRect(rect); + mScissorState.setEnabled(!sClipRectStack.empty()); + updateScissorRegion(); + } } LLScreenClipRect::~LLScreenClipRect() { - if (mEnabled) - { - popClipRect(); - updateScissorRegion(); - } + if (mEnabled) + { + popClipRect(); + updateScissorRegion(); + } } -//static +//static void LLScreenClipRect::pushClipRect(const LLRect& rect) { - LLRect combined_clip_rect = rect; - if (!sClipRectStack.empty()) - { - LLRect top = sClipRectStack.top(); - combined_clip_rect.intersectWith(top); + LLRect combined_clip_rect = rect; + if (!sClipRectStack.empty()) + { + LLRect top = sClipRectStack.top(); + combined_clip_rect.intersectWith(top); - if(combined_clip_rect.isEmpty()) - { - // avoid artifacts where zero area rects show up as lines - combined_clip_rect = LLRect::null; - } - } - sClipRectStack.push(combined_clip_rect); + if(combined_clip_rect.isEmpty()) + { + // avoid artifacts where zero area rects show up as lines + combined_clip_rect = LLRect::null; + } + } + sClipRectStack.push(combined_clip_rect); } -//static +//static void LLScreenClipRect::popClipRect() { - sClipRectStack.pop(); + sClipRectStack.pop(); } //static void LLScreenClipRect::updateScissorRegion() { - if (sClipRectStack.empty()) return; + if (sClipRectStack.empty()) return; - // finish any deferred calls in the old clipping region - gGL.flush(); + // finish any deferred calls in the old clipping region + gGL.flush(); - LLRect rect = sClipRectStack.top(); - stop_glerror(); - S32 x,y,w,h; - x = llfloor(rect.mLeft * LLUI::getScaleFactor().mV[VX]); - y = llfloor(rect.mBottom * LLUI::getScaleFactor().mV[VY]); - w = llmax(0, llceil(rect.getWidth() * LLUI::getScaleFactor().mV[VX])) + 1; - h = llmax(0, llceil(rect.getHeight() * LLUI::getScaleFactor().mV[VY])) + 1; - glScissor( x,y,w,h ); - stop_glerror(); + LLRect rect = sClipRectStack.top(); + stop_glerror(); + S32 x,y,w,h; + x = llfloor(rect.mLeft * LLUI::getScaleFactor().mV[VX]); + y = llfloor(rect.mBottom * LLUI::getScaleFactor().mV[VY]); + w = llmax(0, llceil(rect.getWidth() * LLUI::getScaleFactor().mV[VX])) + 1; + h = llmax(0, llceil(rect.getHeight() * LLUI::getScaleFactor().mV[VY])) + 1; + glScissor( x,y,w,h ); + stop_glerror(); } //--------------------------------------------------------------------------- // LLLocalClipRect //--------------------------------------------------------------------------- LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */) -: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, - rect.mTop + LLFontGL::sCurOrigin.mY, - rect.mRight + LLFontGL::sCurOrigin.mX, - rect.mBottom + LLFontGL::sCurOrigin.mY), enabled) +: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, + rect.mTop + LLFontGL::sCurOrigin.mY, + rect.mRight + LLFontGL::sCurOrigin.mX, + rect.mBottom + LLFontGL::sCurOrigin.mY), enabled) {} LLLocalClipRect::~LLLocalClipRect() diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h index eeeaf2adb6..cb74de7c22 100644 --- a/indra/llui/lllocalcliprect.h +++ b/indra/llui/lllocalcliprect.h @@ -1,24 +1,24 @@ -/** +/** * @file lllocalcliprect.h * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -26,7 +26,7 @@ #define LLLOCALCLIPRECT_H #include "llgl.h" -#include "llrect.h" // can't forward declare, it's templated +#include "llrect.h" // can't forward declare, it's templated #include <stack> // Clip rendering to a specific rectangle using GL scissor @@ -38,26 +38,26 @@ class LLScreenClipRect { public: - LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); - virtual ~LLScreenClipRect(); + LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); + virtual ~LLScreenClipRect(); private: - static void pushClipRect(const LLRect& rect); - static void popClipRect(); - static void updateScissorRegion(); + static void pushClipRect(const LLRect& rect); + static void popClipRect(); + static void updateScissorRegion(); private: - LLGLState mScissorState; - BOOL mEnabled; + LLGLState mScissorState; + BOOL mEnabled; - static std::stack<LLRect> sClipRectStack; + static std::stack<LLRect> sClipRectStack; }; class LLLocalClipRect : public LLScreenClipRect { public: - LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); - ~LLLocalClipRect(); + LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); + ~LLLocalClipRect(); }; #endif diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 583704418b..bfc4c089f3 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llbutton.cpp * @brief LLButton base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,210 +37,210 @@ static LLDefaultChildRegistry::Register<LLMenuButton> r("menu_button"); void LLMenuButton::MenuPositions::declareValues() { - declare("topleft", MP_TOP_LEFT); - declare("topright", MP_TOP_RIGHT); - declare("bottomleft", MP_BOTTOM_LEFT); - declare("bottomright", MP_BOTTOM_RIGHT); + declare("topleft", MP_TOP_LEFT); + declare("topright", MP_TOP_RIGHT); + declare("bottomleft", MP_BOTTOM_LEFT); + declare("bottomright", MP_BOTTOM_RIGHT); } LLMenuButton::Params::Params() -: menu_filename("menu_filename"), - position("menu_position", MP_BOTTOM_LEFT) +: menu_filename("menu_filename"), + position("menu_position", MP_BOTTOM_LEFT) { - addSynonym(position, "position"); + addSynonym(position, "position"); } LLMenuButton::LLMenuButton(const LLMenuButton::Params& p) -: LLButton(p), - mIsMenuShown(false), - mMenuPosition(p.position), - mOwnMenu(false) +: LLButton(p), + mIsMenuShown(false), + mMenuPosition(p.position), + mOwnMenu(false) { - std::string menu_filename = p.menu_filename; + std::string menu_filename = p.menu_filename; - setMenu(menu_filename, mMenuPosition); - updateMenuOrigin(); + setMenu(menu_filename, mMenuPosition); + updateMenuOrigin(); } LLMenuButton::~LLMenuButton() { - cleanup(); + cleanup(); } boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) { - return LLUICtrl::setMouseDownCallback(cb); + return LLUICtrl::setMouseDownCallback(cb); } void LLMenuButton::hideMenu() { - LLToggleableMenu* menu = getMenu(); - if (menu) - { - menu->setVisible(FALSE); - } + LLToggleableMenu* menu = getMenu(); + if (menu) + { + menu->setVisible(FALSE); + } } LLToggleableMenu* LLMenuButton::getMenu() { - return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get()); + return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get()); } void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition position /*MP_TOP_LEFT*/) { - if (menu_filename.empty()) - { - return; - } - - llassert(LLMenuGL::sMenuContainer != NULL); - LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); - if (!menu) - { - LL_WARNS() << "Error loading menu_button menu" << LL_ENDL; - return; - } - - setMenu(menu, position, true); + if (menu_filename.empty()) + { + return; + } + + llassert(LLMenuGL::sMenuContainer != NULL); + LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + if (!menu) + { + LL_WARNS() << "Error loading menu_button menu" << LL_ENDL; + return; + } + + setMenu(menu, position, true); } void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/, bool take_ownership /*false*/) { - if (!menu) return; + if (!menu) return; - cleanup(); // destroy the previous memnu if we own it + cleanup(); // destroy the previous memnu if we own it - mMenuHandle = menu->getHandle(); - mMenuPosition = position; - mOwnMenu = take_ownership; + mMenuHandle = menu->getHandle(); + mMenuPosition = position; + mOwnMenu = take_ownership; - menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2)); + menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2)); } BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask ) { - if (!getMenu()) return FALSE; - - if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) - { - // *HACK: We emit the mouse down signal to fire the callback bound to the - // menu emerging event before actually displaying the menu. See STORM-263. - LLUICtrl::handleMouseDown(-1, -1, MASK_NONE); - - toggleMenu(); - return TRUE; - } - - LLToggleableMenu* menu = getMenu(); - if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE) - { - menu->setVisible(FALSE); - return TRUE; - } - - return FALSE; + if (!getMenu()) return FALSE; + + if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) + { + // *HACK: We emit the mouse down signal to fire the callback bound to the + // menu emerging event before actually displaying the menu. See STORM-263. + LLUICtrl::handleMouseDown(-1, -1, MASK_NONE); + + toggleMenu(); + return TRUE; + } + + LLToggleableMenu* menu = getMenu(); + if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE) + { + menu->setVisible(FALSE); + return TRUE; + } + + return FALSE; } BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask) { - LLButton::handleMouseDown(x, y, mask); + LLButton::handleMouseDown(x, y, mask); + + toggleMenu(); - toggleMenu(); - - return TRUE; + return TRUE; } void LLMenuButton::toggleMenu() { - if (mValidateSignal && !(*mValidateSignal)(this, LLSD())) - { - return; - } - - LLToggleableMenu* menu = getMenu(); - if (!menu) return; - - // Store the button rectangle to toggle menu visibility if a mouse event - // occurred inside or outside the button rect. - menu->setButtonRect(this); - - if (!menu->toggleVisibility() && mIsMenuShown) - { - setForcePressedState(false); - mIsMenuShown = false; - } - else - { - menu->buildDrawLabels(); - menu->arrangeAndClear(); - menu->updateParent(LLMenuGL::sMenuContainer); - - updateMenuOrigin(); - - LLMenuGL::showPopup(getParent(), menu, mX, mY); - - setForcePressedState(true); - mIsMenuShown = true; - } + if (mValidateSignal && !(*mValidateSignal)(this, LLSD())) + { + return; + } + + LLToggleableMenu* menu = getMenu(); + if (!menu) return; + + // Store the button rectangle to toggle menu visibility if a mouse event + // occurred inside or outside the button rect. + menu->setButtonRect(this); + + if (!menu->toggleVisibility() && mIsMenuShown) + { + setForcePressedState(false); + mIsMenuShown = false; + } + else + { + menu->buildDrawLabels(); + menu->arrangeAndClear(); + menu->updateParent(LLMenuGL::sMenuContainer); + + updateMenuOrigin(); + + LLMenuGL::showPopup(getParent(), menu, mX, mY); + + setForcePressedState(true); + mIsMenuShown = true; + } } void LLMenuButton::updateMenuOrigin() { - LLToggleableMenu* menu = getMenu(); - if (!menu) return; - - LLRect rect = getRect(); - - switch (mMenuPosition) - { - case MP_TOP_LEFT: - { - mX = rect.mLeft; - mY = rect.mTop + menu->getRect().getHeight(); - break; - } - case MP_TOP_RIGHT: - { - const LLRect& menu_rect = menu->getRect(); - mX = rect.mRight - menu_rect.getWidth(); - mY = rect.mTop + menu_rect.getHeight(); - break; - } - case MP_BOTTOM_LEFT: - { - mX = rect.mLeft; - mY = rect.mBottom; - break; - } - case MP_BOTTOM_RIGHT: - { - const LLRect& menu_rect = menu->getRect(); - mX = rect.mRight - menu_rect.getWidth(); - mY = rect.mBottom; - break; - } - } + LLToggleableMenu* menu = getMenu(); + if (!menu) return; + + LLRect rect = getRect(); + + switch (mMenuPosition) + { + case MP_TOP_LEFT: + { + mX = rect.mLeft; + mY = rect.mTop + menu->getRect().getHeight(); + break; + } + case MP_TOP_RIGHT: + { + const LLRect& menu_rect = menu->getRect(); + mX = rect.mRight - menu_rect.getWidth(); + mY = rect.mTop + menu_rect.getHeight(); + break; + } + case MP_BOTTOM_LEFT: + { + mX = rect.mLeft; + mY = rect.mBottom; + break; + } + case MP_BOTTOM_RIGHT: + { + const LLRect& menu_rect = menu->getRect(); + mX = rect.mRight - menu_rect.getWidth(); + mY = rect.mBottom; + break; + } + } } void LLMenuButton::onMenuVisibilityChange(const LLSD& param) { - bool new_visibility = param["visibility"].asBoolean(); - bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean(); - - // Reset the button "pressed" state only if the menu is shown by this particular - // menu button (not any other control) and is not being closed by a click on the button. - if (!new_visibility && !is_closed_by_button_click && mIsMenuShown) - { - setForcePressedState(false); - mIsMenuShown = false; - } + bool new_visibility = param["visibility"].asBoolean(); + bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean(); + + // Reset the button "pressed" state only if the menu is shown by this particular + // menu button (not any other control) and is not being closed by a click on the button. + if (!new_visibility && !is_closed_by_button_click && mIsMenuShown) + { + setForcePressedState(false); + mIsMenuShown = false; + } } void LLMenuButton::cleanup() { - if (mMenuHandle.get() && mOwnMenu) - { - mMenuHandle.get()->die(); - } + if (mMenuHandle.get() && mOwnMenu) + { + mMenuHandle.get()->die(); + } } diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index e42f8f53bd..1039560827 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -1,25 +1,25 @@ -/** +/** * @file llbutton.h * @brief Header for buttons * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,67 +34,67 @@ class LLToggleableMenu; class LLMenuButton : public LLButton { - LOG_CLASS(LLMenuButton); + LOG_CLASS(LLMenuButton); public: - typedef enum e_menu_position - { - MP_TOP_LEFT, - MP_TOP_RIGHT, - MP_BOTTOM_LEFT, - MP_BOTTOM_RIGHT - } EMenuPosition; + typedef enum e_menu_position + { + MP_TOP_LEFT, + MP_TOP_RIGHT, + MP_BOTTOM_LEFT, + MP_BOTTOM_RIGHT + } EMenuPosition; + + struct MenuPositions + : public LLInitParam::TypeValuesHelper<EMenuPosition, MenuPositions> + { + static void declareValues(); + }; + + struct Params + : public LLInitParam::Block<Params, LLButton::Params> + { + // filename for it's toggleable menu + Optional<std::string> menu_filename; + Optional<EMenuPosition, MenuPositions> position; - struct MenuPositions - : public LLInitParam::TypeValuesHelper<EMenuPosition, MenuPositions> - { - static void declareValues(); - }; + Params(); + }; - struct Params - : public LLInitParam::Block<Params, LLButton::Params> - { - // filename for it's toggleable menu - Optional<std::string> menu_filename; - Optional<EMenuPosition, MenuPositions> position; - - Params(); - }; - - boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); - void hideMenu(); + void hideMenu(); - LLToggleableMenu* getMenu(); - void setMenu(const std::string& menu_filename, EMenuPosition position = MP_TOP_LEFT); - void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT, bool take_ownership = false); + LLToggleableMenu* getMenu(); + void setMenu(const std::string& menu_filename, EMenuPosition position = MP_TOP_LEFT); + void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT, bool take_ownership = false); - void setMenuPosition(EMenuPosition position) { mMenuPosition = position; } + void setMenuPosition(EMenuPosition position) { mMenuPosition = position; } protected: - friend class LLUICtrlFactory; - LLMenuButton(const Params&); - ~LLMenuButton(); + friend class LLUICtrlFactory; + LLMenuButton(const Params&); + ~LLMenuButton(); - void toggleMenu(); - void updateMenuOrigin(); + void toggleMenu(); + void updateMenuOrigin(); - void onMenuVisibilityChange(const LLSD& param); + void onMenuVisibilityChange(const LLSD& param); private: - void cleanup(); - - LLHandle<LLView> mMenuHandle; - bool mIsMenuShown; - EMenuPosition mMenuPosition; - S32 mX; - S32 mY; - bool mOwnMenu; // true if we manage the menu lifetime + void cleanup(); + + LLHandle<LLView> mMenuHandle; + bool mIsMenuShown; + EMenuPosition mMenuPosition; + S32 mX; + S32 mY; + bool mOwnMenu; // true if we manage the menu lifetime }; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7381dc80a8..8fcb558aae 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.cpp * @brief LLMenuItemGL base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -65,8 +65,8 @@ LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; view_listener_t::listener_map_t view_listener_t::sListeners; -S32 MENU_BAR_HEIGHT = 0; -S32 MENU_BAR_WIDTH = 0; +S32 MENU_BAR_HEIGHT = 18; +S32 MENU_BAR_WIDTH = 410; ///============================================================================ /// Local function declarations, constants, enums, and typedefs @@ -124,229 +124,229 @@ static LLDefaultChildRegistry::Register<LLMenuGL> register_menu_default("menu"); ///============================================================================ LLMenuItemGL::Params::Params() -: shortcut("shortcut"), - jump_key("jump_key", KEY_NONE), - use_mac_ctrl("use_mac_ctrl", false), - allow_key_repeat("allow_key_repeat", false), - rect("rect"), - left("left"), - top("top"), - right("right"), - bottom("bottom"), - width("width"), - height("height"), - bottom_delta("bottom_delta"), - left_delta("left_delta"), - enabled_color("enabled_color"), - disabled_color("disabled_color"), - highlight_bg_color("highlight_bg_color"), - highlight_fg_color("highlight_fg_color") -{ - changeDefault(mouse_opaque, true); +: shortcut("shortcut"), + jump_key("jump_key", KEY_NONE), + use_mac_ctrl("use_mac_ctrl", false), + allow_key_repeat("allow_key_repeat", false), + rect("rect"), + left("left"), + top("top"), + right("right"), + bottom("bottom"), + width("width"), + height("height"), + bottom_delta("bottom_delta"), + left_delta("left_delta"), + enabled_color("enabled_color"), + disabled_color("disabled_color"), + highlight_bg_color("highlight_bg_color"), + highlight_fg_color("highlight_fg_color") +{ + changeDefault(mouse_opaque, true); } // Default constructor LLMenuItemGL::LLMenuItemGL(const LLMenuItemGL::Params& p) -: LLUICtrl(p), - mJumpKey(p.jump_key), - mAllowKeyRepeat(p.allow_key_repeat), - mHighlight( FALSE ), - mGotHover( FALSE ), - mBriefItem( FALSE ), - mDrawTextDisabled( FALSE ), - mFont(p.font), - mAcceleratorKey(KEY_NONE), - mAcceleratorMask(MASK_NONE), - mLabel(p.label.isProvided() ? p.label() : p.name()), - mEnabledColor(p.enabled_color()), - mDisabledColor(p.disabled_color()), - mHighlightBackground(p.highlight_bg_color()), - mHighlightForeground(p.highlight_fg_color()) +: LLUICtrl(p), + mJumpKey(p.jump_key), + mAllowKeyRepeat(p.allow_key_repeat), + mHighlight( FALSE ), + mGotHover( FALSE ), + mBriefItem( FALSE ), + mDrawTextDisabled( FALSE ), + mFont(p.font), + mAcceleratorKey(KEY_NONE), + mAcceleratorMask(MASK_NONE), + mLabel(p.label.isProvided() ? p.label() : p.name()), + mEnabledColor(p.enabled_color()), + mDisabledColor(p.disabled_color()), + mHighlightBackground(p.highlight_bg_color()), + mHighlightForeground(p.highlight_fg_color()) { #ifdef LL_DARWIN - // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd - BOOL useMacCtrl = p.use_mac_ctrl; + // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd + BOOL useMacCtrl = p.use_mac_ctrl; #endif // LL_DARWIN - - std::string shortcut = p.shortcut; - if (shortcut.find("control") != shortcut.npos) - { + + std::string shortcut = p.shortcut; + if (shortcut.find("control") != shortcut.npos) + { #ifdef LL_DARWIN - if ( useMacCtrl ) - { - mAcceleratorMask |= MASK_MAC_CONTROL; - } + if ( useMacCtrl ) + { + mAcceleratorMask |= MASK_MAC_CONTROL; + } #endif // LL_DARWIN - mAcceleratorMask |= MASK_CONTROL; - } - if (shortcut.find("alt") != shortcut.npos) - { - mAcceleratorMask |= MASK_ALT; - } - if (shortcut.find("shift") != shortcut.npos) - { - mAcceleratorMask |= MASK_SHIFT; - } - S32 pipe_pos = shortcut.rfind("|"); - std::string key_str = shortcut.substr(pipe_pos+1); - - LLKeyboard::keyFromString(key_str, &mAcceleratorKey); - - LL_DEBUGS("HotKeys") << "Process short cut key: shortcut: " << shortcut - << ", key str: " << key_str - << ", accelerator mask: " << mAcceleratorMask - << ", accelerator key: " << mAcceleratorKey - << LL_ENDL; + mAcceleratorMask |= MASK_CONTROL; + } + if (shortcut.find("alt") != shortcut.npos) + { + mAcceleratorMask |= MASK_ALT; + } + if (shortcut.find("shift") != shortcut.npos) + { + mAcceleratorMask |= MASK_SHIFT; + } + S32 pipe_pos = shortcut.rfind("|"); + std::string key_str = shortcut.substr(pipe_pos+1); + + LLKeyboard::keyFromString(key_str, &mAcceleratorKey); + + LL_DEBUGS("HotKeys") << "Process short cut key: shortcut: " << shortcut + << ", key str: " << key_str + << ", accelerator mask: " << mAcceleratorMask + << ", accelerator key: " << mAcceleratorKey + << LL_ENDL; } //virtual void LLMenuItemGL::setValue(const LLSD& value) { - setLabel(value.asString()); + setLabel(value.asString()); } //virtual LLSD LLMenuItemGL::getValue() const { - return getLabel(); + return getLabel(); } //virtual bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const { - return (mAcceleratorKey == key) && (mAcceleratorMask == mask); + return (mAcceleratorKey == key) && (mAcceleratorMask == mask); } //virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { - if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) - { - onCommit(); - return TRUE; - } - return FALSE; + if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) + { + onCommit(); + return TRUE; + } + return FALSE; } BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask) { - getWindow()->setCursor(UI_CURSOR_ARROW); - return TRUE; + getWindow()->setCursor(UI_CURSOR_ARROW); + return TRUE; } //virtual BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask) { - return LLUICtrl::handleRightMouseDown(x,y,mask); + return LLUICtrl::handleRightMouseDown(x,y,mask); } void LLMenuItemGL::onMouseEnter(S32 x, S32 y, MASK mask) { - setHover(TRUE); - LLUICtrl::onMouseEnter(x,y,mask); + setHover(TRUE); + LLUICtrl::onMouseEnter(x,y,mask); } void LLMenuItemGL::onMouseLeave(S32 x, S32 y, MASK mask) { - setHover(FALSE); - LLUICtrl::onMouseLeave(x,y,mask); + setHover(FALSE); + LLUICtrl::onMouseLeave(x,y,mask); } //virtual BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) { - // If this event came from a right-click context menu spawn, - // process as a left-click to allow menu items to be hit - if (LLMenuHolderGL::sContextMenuSpawnPos.mX != S32_MAX - || LLMenuHolderGL::sContextMenuSpawnPos.mY != S32_MAX) - { - BOOL handled = handleMouseUp(x, y, mask); - return handled; - } - return LLUICtrl::handleRightMouseUp(x,y,mask); + // If this event came from a right-click context menu spawn, + // process as a left-click to allow menu items to be hit + if (LLMenuHolderGL::sContextMenuSpawnPos.mX != S32_MAX + || LLMenuHolderGL::sContextMenuSpawnPos.mY != S32_MAX) + { + BOOL handled = handleMouseUp(x, y, mask); + return handled; + } + return LLUICtrl::handleRightMouseUp(x,y,mask); } // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp) { - LLMenuKeyboardBinding *accelerator = NULL; - - if (mAcceleratorKey != KEY_NONE) - { - std::list<LLMenuKeyboardBinding*>::iterator list_it; - for (list_it = listp->begin(); list_it != listp->end(); ++list_it) - { - accelerator = *list_it; - if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == (mAcceleratorMask & MASK_NORMALKEYS))) - { - - // *NOTE: get calling code to throw up warning or route - // warning messages back to app-provided output - // std::string warning; - // warning.append("Duplicate key binding <"); - // appendAcceleratorString( warning ); - // warning.append("> for menu items:\n "); - // warning.append(accelerator->mName); - // warning.append("\n "); - // warning.append(mLabel); - - // LL_WARNS() << warning << LL_ENDL; - // LLAlertDialog::modalAlert(warning); - return FALSE; - } - } - if (!accelerator) - { - accelerator = new LLMenuKeyboardBinding; - if (accelerator) - { - accelerator->mKey = mAcceleratorKey; - accelerator->mMask = (mAcceleratorMask & MASK_NORMALKEYS); -// accelerator->mName = mLabel; - } - listp->push_back(accelerator);//addData(accelerator); - } - } - return TRUE; + LLMenuKeyboardBinding *accelerator = NULL; + + if (mAcceleratorKey != KEY_NONE) + { + std::list<LLMenuKeyboardBinding*>::iterator list_it; + for (list_it = listp->begin(); list_it != listp->end(); ++list_it) + { + accelerator = *list_it; + if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == (mAcceleratorMask & MASK_NORMALKEYS))) + { + + // *NOTE: get calling code to throw up warning or route + // warning messages back to app-provided output + // std::string warning; + // warning.append("Duplicate key binding <"); + // appendAcceleratorString( warning ); + // warning.append("> for menu items:\n "); + // warning.append(accelerator->mName); + // warning.append("\n "); + // warning.append(mLabel); + + // LL_WARNS() << warning << LL_ENDL; + // LLAlertDialog::modalAlert(warning); + return FALSE; + } + } + if (!accelerator) + { + accelerator = new LLMenuKeyboardBinding; + if (accelerator) + { + accelerator->mKey = mAcceleratorKey; + accelerator->mMask = (mAcceleratorMask & MASK_NORMALKEYS); +// accelerator->mName = mLabel; + } + listp->push_back(accelerator);//addData(accelerator); + } + } + return TRUE; } // This function appends the character string representation of // the current accelerator key and mask to the provided string. void LLMenuItemGL::appendAcceleratorString( std::string& st ) const { - st = LLKeyboard::stringFromAccelerator( mAcceleratorMask, mAcceleratorKey ); - LL_DEBUGS("HotKeys") << "appendAcceleratorString: " << st << LL_ENDL; + st = LLKeyboard::stringFromAccelerator( mAcceleratorMask, mAcceleratorKey ); + LL_DEBUGS("HotKeys") << "appendAcceleratorString: " << st << LL_ENDL; } void LLMenuItemGL::setJumpKey(KEY key) { - mJumpKey = LLStringOps::toUpper((char)key); + mJumpKey = LLStringOps::toUpper((char)key); } -// virtual -U32 LLMenuItemGL::getNominalHeight( void ) const -{ - return mFont->getLineHeight() + MENU_ITEM_PADDING; +// virtual +U32 LLMenuItemGL::getNominalHeight( void ) const +{ + return mFont->getLineHeight() + MENU_ITEM_PADDING; } //virtual void LLMenuItemGL::setBriefItem(BOOL brief) { - mBriefItem = brief; + mBriefItem = brief; } //virtual BOOL LLMenuItemGL::isBriefItem() const { - return mBriefItem; + return mBriefItem; } // Get the parent menu for this item LLMenuGL* LLMenuItemGL::getMenu() const { - return (LLMenuGL*) getParent(); + return (LLMenuGL*) getParent(); } @@ -355,216 +355,216 @@ LLMenuGL* LLMenuItemGL::getMenu() const // for horizontal arrangement. U32 LLMenuItemGL::getNominalWidth( void ) const { - U32 width; - - if (mBriefItem) - { - width = BRIEF_PAD_PIXELS; - } - else - { - width = PLAIN_PAD_PIXELS; - } - - if( KEY_NONE != mAcceleratorKey ) - { - width += getMenu()->getShortcutPad(); - std::string temp; - appendAcceleratorString( temp ); - width += mFont->getWidth( temp ); - } - width += mFont->getWidth( mLabel.getWString().c_str() ); - return width; + U32 width; + + if (mBriefItem) + { + width = BRIEF_PAD_PIXELS; + } + else + { + width = PLAIN_PAD_PIXELS; + } + + if( KEY_NONE != mAcceleratorKey ) + { + width += getMenu()->getShortcutPad(); + std::string temp; + appendAcceleratorString( temp ); + width += mFont->getWidth( temp ); + } + width += mFont->getWidth( mLabel.getWString().c_str() ); + return width; } // called to rebuild the draw label void LLMenuItemGL::buildDrawLabel( void ) { - mDrawAccelLabel.clear(); - std::string st = mDrawAccelLabel.getString(); - appendAcceleratorString( st ); - mDrawAccelLabel = st; + mDrawAccelLabel.clear(); + std::string st = mDrawAccelLabel.getString(); + appendAcceleratorString( st ); + mDrawAccelLabel = st; } void LLMenuItemGL::onCommit( void ) { - // Check torn-off status to allow left-arrow keyboard navigation back - // to parent menu. - // Also, don't hide if item triggered by keyboard shortcut (and hence - // parent not visible). - if (!getMenu()->getTornOff() - && getMenu()->getVisible()) - { - LLMenuGL::sMenuContainer->hideMenus(); - } - - LLUICtrl::onCommit(); + // Check torn-off status to allow left-arrow keyboard navigation back + // to parent menu. + // Also, don't hide if item triggered by keyboard shortcut (and hence + // parent not visible). + if (!getMenu()->getTornOff() + && getMenu()->getVisible()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + + LLUICtrl::onCommit(); } // set the hover status (called by it's menu) void LLMenuItemGL::setHighlight( BOOL highlight ) { - if (highlight) - { - getMenu()->clearHoverItem(); - } + if (highlight) + { + getMenu()->clearHoverItem(); + } - if (mHighlight != highlight) - { - dirtyRect(); - } + if (mHighlight != highlight) + { + dirtyRect(); + } - mHighlight = highlight; + mHighlight = highlight; } BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask ) { - if (getHighlight() && - getMenu()->isOpen()) - { - if (key == KEY_UP) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - getMenu()->highlightPrevItem(this); - return TRUE; - } - else if (key == KEY_DOWN) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - getMenu()->highlightNextItem(this); - return TRUE; - } - else if (key == KEY_RETURN && mask == MASK_NONE) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - onCommit(); - return TRUE; - } - } - - return FALSE; + if (getHighlight() && + getMenu()->isOpen()) + { + if (key == KEY_UP) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + getMenu()->highlightPrevItem(this); + return TRUE; + } + else if (key == KEY_DOWN) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + getMenu()->highlightNextItem(this); + return TRUE; + } + else if (key == KEY_RETURN && mask == MASK_NONE) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + onCommit(); + return TRUE; + } + } + + return FALSE; } BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask) { - // switch to mouse navigation mode - LLMenuGL::setKeyboardMode(FALSE); + // switch to mouse navigation mode + LLMenuGL::setKeyboardMode(FALSE); - onCommit(); - make_ui_sound("UISndClickRelease"); - return LLView::handleMouseUp(x, y, mask); + onCommit(); + make_ui_sound("UISndClickRelease"); + return LLView::handleMouseUp(x, y, mask); } BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask) { - // switch to mouse navigation mode - LLMenuGL::setKeyboardMode(FALSE); + // switch to mouse navigation mode + LLMenuGL::setKeyboardMode(FALSE); - setHighlight(TRUE); - return LLView::handleMouseDown(x, y, mask); + setHighlight(TRUE); + return LLView::handleMouseDown(x, y, mask); } BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - // If the menu is scrollable let it handle the wheel event. - return !getMenu()->isScrollable(); + // If the menu is scrollable let it handle the wheel event. + return !getMenu()->isScrollable(); } void LLMenuItemGL::draw( void ) { - // *FIX: This can be optimized by using switches. Want to avoid - // that until the functionality is finalized. - - // HACK: Brief items don't highlight. Pie menu takes care of it. JC - // let disabled items be highlighted, just don't draw them as such - if( getEnabled() && getHighlight() && !mBriefItem) - { - gGL.color4fv( mHighlightBackground.get().mV ); - - gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - } - - LLColor4 color; - - if ( getEnabled() && getHighlight() ) - { - color = mHighlightForeground.get(); - } - else if( getEnabled() && !mDrawTextDisabled ) - { - color = mEnabledColor.get(); - } - else - { - color = mDisabledColor.get(); - } - - // Highlight if needed - if( ll::ui::SearchableControl::getHighlighted() ) - color = ll::ui::SearchableControl::getHighlightColor(); - - // Draw the text on top. - if (mBriefItem) - { - mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color, - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL); - } - else - { - if( !mDrawBoolLabel.empty() ) - { - mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); - } - mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); - if( !mDrawAccelLabel.empty() ) - { - mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, - LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); - } - if( !mDrawBranchLabel.empty() ) - { - mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, - LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); - } - } - - // underline "jump" key only when keyboard navigation has been initiated - if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode()) - { - std::string upper_case_label = mLabel.getString(); - LLStringUtil::toUpper(upper_case_label); - std::string::size_type offset = upper_case_label.find(mJumpKey); - if (offset != std::string::npos) - { - S32 x_begin = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset); - S32 x_end = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset + 1); - gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1); - } - } + // *FIX: This can be optimized by using switches. Want to avoid + // that until the functionality is finalized. + + // HACK: Brief items don't highlight. Pie menu takes care of it. JC + // let disabled items be highlighted, just don't draw them as such + if( getEnabled() && getHighlight() && !mBriefItem) + { + gGL.color4fv( mHighlightBackground.get().mV ); + + gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + } + + LLColor4 color; + + if ( getEnabled() && getHighlight() ) + { + color = mHighlightForeground.get(); + } + else if( getEnabled() && !mDrawTextDisabled ) + { + color = mEnabledColor.get(); + } + else + { + color = mDisabledColor.get(); + } + + // Highlight if needed + if( ll::ui::SearchableControl::getHighlighted() ) + color = ll::ui::SearchableControl::getHighlightColor(); + + // Draw the text on top. + if (mBriefItem) + { + mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL); + } + else + { + if( !mDrawBoolLabel.empty() ) + { + mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + } + mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + if( !mDrawAccelLabel.empty() ) + { + mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, + LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + } + if( !mDrawBranchLabel.empty() ) + { + mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color, + LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); + } + } + + // underline "jump" key only when keyboard navigation has been initiated + if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode()) + { + std::string upper_case_label = mLabel.getString(); + LLStringUtil::toUpper(upper_case_label); + std::string::size_type offset = upper_case_label.find(mJumpKey); + if (offset != std::string::npos) + { + S32 x_begin = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset); + S32 x_end = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset + 1); + gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1); + } + } } BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - mLabel.setArg(key, text); - return TRUE; + mLabel.setArg(key, text); + return TRUE; } void LLMenuItemGL::onVisibilityChange(BOOL new_visibility) { - if (getMenu()) - { - getMenu()->needsArrange(); - } - LLView::onVisibilityChange(new_visibility); + if (getMenu()) + { + getMenu()->needsArrange(); + } + LLView::onVisibilityChange(new_visibility); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -578,7 +578,7 @@ LLMenuItemSeparatorGL::Params::Params() } LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) : - LLMenuItemGL( p ) + LLMenuItemGL( p ) { if (p.on_visible.isProvided()) { @@ -589,15 +589,15 @@ LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params //virtual U32 LLMenuItemSeparatorGL::getNominalHeight( void ) const { - return SEPARATOR_HEIGHT_PIXELS; + return SEPARATOR_HEIGHT_PIXELS; } void LLMenuItemSeparatorGL::draw( void ) { - gGL.color4fv( mDisabledColor.get().mV ); - const S32 y = getRect().getHeight() / 2; - const S32 PAD = 6; - gl_line_2d( PAD, y, getRect().getWidth() - PAD, y ); + gGL.color4fv( mDisabledColor.get().mV ); + const S32 y = getRect().getHeight() / 2; + const S32 PAD = 6; + gl_line_2d( PAD, y, getRect().getWidth() - PAD, y ); } void LLMenuItemSeparatorGL::buildDrawLabel( void ) @@ -611,48 +611,48 @@ void LLMenuItemSeparatorGL::buildDrawLabel( void ) BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask) { - LLMenuGL* parent_menu = getMenu(); - if (y > getRect().getHeight() / 2) - { - // the menu items are in the child list in bottom up order - LLView* prev_menu_item = parent_menu->findNextSibling(this); - return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; - } - else - { - LLView* next_menu_item = parent_menu->findPrevSibling(this); - return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; - } -} - -BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) -{ - LLMenuGL* parent_menu = getMenu(); - if (y > getRect().getHeight() / 2) - { - LLView* prev_menu_item = parent_menu->findNextSibling(this); - return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; - } - else - { - LLView* next_menu_item = parent_menu->findPrevSibling(this); - return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; - } -} - -BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) -{ - LLMenuGL* parent_menu = getMenu(); - if (y > getRect().getHeight() / 2) - { - parent_menu->highlightPrevItem(this, FALSE); - return FALSE; - } - else - { - parent_menu->highlightNextItem(this, FALSE); - return FALSE; - } + LLMenuGL* parent_menu = getMenu(); + if (y > getRect().getHeight() / 2) + { + // the menu items are in the child list in bottom up order + LLView* prev_menu_item = parent_menu->findNextSibling(this); + return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; + } + else + { + LLView* next_menu_item = parent_menu->findPrevSibling(this); + return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; + } +} + +BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) +{ + LLMenuGL* parent_menu = getMenu(); + if (y > getRect().getHeight() / 2) + { + LLView* prev_menu_item = parent_menu->findNextSibling(this); + return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; + } + else + { + LLView* next_menu_item = parent_menu->findPrevSibling(this); + return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; + } +} + +BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) +{ + LLMenuGL* parent_menu = getMenu(); + if (y > getRect().getHeight() / 2) + { + parent_menu->highlightPrevItem(this, FALSE); + return FALSE; + } + else + { + parent_menu->highlightNextItem(this, FALSE); + return FALSE; + } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -662,120 +662,120 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemVerticalSeparatorGL -: public LLMenuItemSeparatorGL +: public LLMenuItemSeparatorGL { public: - LLMenuItemVerticalSeparatorGL( void ); + LLMenuItemVerticalSeparatorGL( void ); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } }; LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void ) { - setLabel( VERTICAL_SEPARATOR_LABEL ); + setLabel( VERTICAL_SEPARATOR_LABEL ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemTearOffGL //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLMenuItemTearOffGL::LLMenuItemTearOffGL(const LLMenuItemTearOffGL::Params& p) -: LLMenuItemGL(p) +LLMenuItemTearOffGL::LLMenuItemTearOffGL(const LLMenuItemTearOffGL::Params& p) +: LLMenuItemGL(p) { } // Returns the first floater ancestor if there is one LLFloater* LLMenuItemTearOffGL::getParentFloater() { - LLView* parent_view = getMenu(); + LLView* parent_view = getMenu(); - while (parent_view) - { - if (dynamic_cast<LLFloater*>(parent_view)) - { - return dynamic_cast<LLFloater*>(parent_view); - } + while (parent_view) + { + if (dynamic_cast<LLFloater*>(parent_view)) + { + return dynamic_cast<LLFloater*>(parent_view); + } - bool parent_is_menu = dynamic_cast<LLMenuGL*>(parent_view) && !dynamic_cast<LLMenuBarGL*>(parent_view); + bool parent_is_menu = dynamic_cast<LLMenuGL*>(parent_view) && !dynamic_cast<LLMenuBarGL*>(parent_view); - if (parent_is_menu) - { - // use menu parent - parent_view = dynamic_cast<LLMenuGL*>(parent_view)->getParentMenuItem(); - } - else - { - // just use regular view parent - parent_view = parent_view->getParent(); - } - } + if (parent_is_menu) + { + // use menu parent + parent_view = dynamic_cast<LLMenuGL*>(parent_view)->getParentMenuItem(); + } + else + { + // just use regular view parent + parent_view = parent_view->getParent(); + } + } - return NULL; + return NULL; } void LLMenuItemTearOffGL::onCommit() { - if (getMenu()->getTornOff()) - { - LLTearOffMenu * torn_off_menu = dynamic_cast<LLTearOffMenu*>(getMenu()->getParent()); - if (torn_off_menu) - { - torn_off_menu->closeFloater(); - } - } - else - { - // transfer keyboard focus and highlight to first real item in list - if (getHighlight()) - { - getMenu()->highlightNextItem(this); - } - - getMenu()->needsArrange(); - - LLFloater* parent_floater = getParentFloater(); - LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu()); - - if (tear_off_menu) - { - if (parent_floater) - { - parent_floater->addDependentFloater(tear_off_menu, FALSE); - } - - // give focus to torn off menu because it will have - // been taken away when parent menu closes - tear_off_menu->setFocus(TRUE); - } - } - LLMenuItemGL::onCommit(); + if (getMenu()->getTornOff()) + { + LLTearOffMenu * torn_off_menu = dynamic_cast<LLTearOffMenu*>(getMenu()->getParent()); + if (torn_off_menu) + { + torn_off_menu->closeFloater(); + } + } + else + { + // transfer keyboard focus and highlight to first real item in list + if (getHighlight()) + { + getMenu()->highlightNextItem(this); + } + + getMenu()->needsArrange(); + + LLFloater* parent_floater = getParentFloater(); + LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu()); + + if (tear_off_menu) + { + if (parent_floater) + { + parent_floater->addDependentFloater(tear_off_menu, FALSE); + } + + // give focus to torn off menu because it will have + // been taken away when parent menu closes + tear_off_menu->setFocus(TRUE); + } + } + LLMenuItemGL::onCommit(); } void LLMenuItemTearOffGL::draw() { - // disabled items can be highlighted, but shouldn't render as such - if( getEnabled() && getHighlight() && !isBriefItem()) - { - gGL.color4fv( mHighlightBackground.get().mV ); - gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - } + // disabled items can be highlighted, but shouldn't render as such + if( getEnabled() && getHighlight() && !isBriefItem()) + { + gGL.color4fv( mHighlightBackground.get().mV ); + gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + } - if (getEnabled()) - { - gGL.color4fv( mEnabledColor.get().mV ); - } - else - { - gGL.color4fv( mDisabledColor.get().mV ); - } - const S32 y = getRect().getHeight() / 3; - const S32 PAD = 6; - gl_line_2d( PAD, y, getRect().getWidth() - PAD, y ); - gl_line_2d( PAD, y * 2, getRect().getWidth() - PAD, y * 2 ); + if (getEnabled()) + { + gGL.color4fv( mEnabledColor.get().mV ); + } + else + { + gGL.color4fv( mDisabledColor.get().mV ); + } + const S32 y = getRect().getHeight() / 3; + const S32 PAD = 6; + gl_line_2d( PAD, y, getRect().getWidth() - PAD, y ); + gl_line_2d( PAD, y * 2, getRect().getWidth() - PAD, y * 2 ); } -U32 LLMenuItemTearOffGL::getNominalHeight( void ) const -{ - return TEAROFF_SEPARATOR_HEIGHT_PIXELS; +U32 LLMenuItemTearOffGL::getNominalHeight( void ) const +{ + return TEAROFF_SEPARATOR_HEIGHT_PIXELS; } ///============================================================================ @@ -783,104 +783,104 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const ///============================================================================ LLMenuItemCallGL::LLMenuItemCallGL(const LLMenuItemCallGL::Params& p) -: LLMenuItemGL(p) +: LLMenuItemGL(p) { } void LLMenuItemCallGL::initFromParams(const Params& p) { - if (p.on_visible.isProvided()) - { - mVisibleSignal.connect(initEnableCallback(p.on_visible)); - } - if (p.on_enable.isProvided()) - { - setEnableCallback(initEnableCallback(p.on_enable)); - // Set the enabled control variable (for backwards compatability) - if (p.on_enable.control_name.isProvided() && !p.on_enable.control_name().empty()) - { - LLControlVariable* control = findControl(p.on_enable.control_name()); - if (control) - { - setEnabledControlVariable(control); - } - else - { - LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName() - << ": control " << p.on_enable.control_name() - << " does not exist." << LL_ENDL; - } - } - } - if (p.on_click.isProvided()) - { - setCommitCallback(initCommitCallback(p.on_click)); - } - - LLUICtrl::initFromParams(p); + if (p.on_visible.isProvided()) + { + mVisibleSignal.connect(initEnableCallback(p.on_visible)); + } + if (p.on_enable.isProvided()) + { + setEnableCallback(initEnableCallback(p.on_enable)); + // Set the enabled control variable (for backwards compatability) + if (p.on_enable.control_name.isProvided() && !p.on_enable.control_name().empty()) + { + LLControlVariable* control = findControl(p.on_enable.control_name()); + if (control) + { + setEnabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to menu " << getName() + << ": control " << p.on_enable.control_name() + << " does not exist." << LL_ENDL; + } + } + } + if (p.on_click.isProvided()) + { + setCommitCallback(initCommitCallback(p.on_click)); + } + + LLUICtrl::initFromParams(p); } void LLMenuItemCallGL::onCommit( void ) { - // RN: menu item can be deleted in callback, so beware - getMenu()->setItemLastSelected( this ); - - LLMenuItemGL::onCommit(); + // RN: menu item can be deleted in callback, so beware + getMenu()->setItemLastSelected( this ); + + LLMenuItemGL::onCommit(); } void LLMenuItemCallGL::updateEnabled( void ) { - if (mEnableSignal.num_slots() > 0) - { - bool enabled = mEnableSignal(this, LLSD()); - if (mEnabledControlVariable) - { - if (!enabled) - { - // callback overrides control variable; this will call setEnabled() - mEnabledControlVariable->set(false); - } - } - else - { - setEnabled(enabled); - } - } + if (mEnableSignal.num_slots() > 0) + { + bool enabled = mEnableSignal(this, LLSD()); + if (mEnabledControlVariable) + { + if (!enabled) + { + // callback overrides control variable; this will call setEnabled() + mEnabledControlVariable->set(false); + } + } + else + { + setEnabled(enabled); + } + } } void LLMenuItemCallGL::updateVisible( void ) { - if (mVisibleSignal.num_slots() > 0) - { - bool visible = mVisibleSignal(this, LLSD()); - setVisible(visible); - } + if (mVisibleSignal.num_slots() > 0) + { + bool visible = mVisibleSignal(this, LLSD()); + setVisible(visible); + } } void LLMenuItemCallGL::buildDrawLabel( void ) { - updateEnabled(); - updateVisible(); - LLMenuItemGL::buildDrawLabel(); + updateEnabled(); + updateVisible(); + LLMenuItemGL::buildDrawLabel(); } BOOL LLMenuItemCallGL::handleKeyHere( KEY key, MASK mask ) { - return LLMenuItemGL::handleKeyHere(key, mask); + return LLMenuItemGL::handleKeyHere(key, mask); } BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask ) { - if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) - { - updateEnabled(); - if (getEnabled()) - { - onCommit(); - return TRUE; - } - } - return FALSE; + if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) + { + updateEnabled(); + if (getEnabled()) + { + onCommit(); + return TRUE; + } + } + return FALSE; } // handleRightMouseUp moved into base class LLMenuItemGL so clicks are @@ -890,76 +890,76 @@ BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask ) /// Class LLMenuItemCheckGL ///============================================================================ LLMenuItemCheckGL::LLMenuItemCheckGL (const LLMenuItemCheckGL::Params& p) -: LLMenuItemCallGL(p) +: LLMenuItemCallGL(p) { } void LLMenuItemCheckGL::initFromParams(const Params& p) { - if (p.on_check.isProvided()) - { - setCheckCallback(initEnableCallback(p.on_check)); - // Set the control name (for backwards compatability) - if (p.on_check.control_name.isProvided() && !p.on_check.control_name().empty()) - { - setControlName(p.on_check.control_name()); - } - } - - LLMenuItemCallGL::initFromParams(p); + if (p.on_check.isProvided()) + { + setCheckCallback(initEnableCallback(p.on_check)); + // Set the control name (for backwards compatability) + if (p.on_check.control_name.isProvided() && !p.on_check.control_name().empty()) + { + setControlName(p.on_check.control_name()); + } + } + + LLMenuItemCallGL::initFromParams(p); } void LLMenuItemCheckGL::onCommit( void ) { - LLMenuItemCallGL::onCommit(); + LLMenuItemCallGL::onCommit(); } //virtual void LLMenuItemCheckGL::setValue(const LLSD& value) { - LLUICtrl::setValue(value); - if(value.asBoolean()) - { - mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; - } - else - { - mDrawBoolLabel.clear(); - } + LLUICtrl::setValue(value); + if(value.asBoolean()) + { + mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; + } + else + { + mDrawBoolLabel.clear(); + } } //virtual LLSD LLMenuItemCheckGL::getValue() const { - // Get our boolean value from the view model. - // If we don't override this method then the implementation from - // LLMenuItemGL will return a string. (EXT-8501) - return LLUICtrl::getValue(); + // Get our boolean value from the view model. + // If we don't override this method then the implementation from + // LLMenuItemGL will return a string. (EXT-8501) + return LLUICtrl::getValue(); } // called to rebuild the draw label void LLMenuItemCheckGL::buildDrawLabel( void ) { - // Note: mCheckSignal() returns true if no callbacks are set - bool checked = mCheckSignal(this, LLSD()); - if (mControlVariable) - { - if (!checked) - setControlValue(false); // callback overrides control variable; this will call setValue() - } - else - { - setValue(checked); - } - if(getValue().asBoolean()) - { - mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; - } - else - { - mDrawBoolLabel.clear(); - } - LLMenuItemCallGL::buildDrawLabel(); + // Note: mCheckSignal() returns true if no callbacks are set + bool checked = mCheckSignal(this, LLSD()); + if (mControlVariable) + { + if (!checked) + setControlValue(false); // callback overrides control variable; this will call setValue() + } + else + { + setValue(checked); + } + if(getValue().asBoolean()) + { + mDrawBoolLabel = LLMenuGL::BOOLEAN_TRUE_PREFIX; + } + else + { + mDrawBoolLabel.clear(); + } + LLMenuItemCallGL::buildDrawLabel(); } ///============================================================================ @@ -968,21 +968,21 @@ void LLMenuItemCheckGL::buildDrawLabel( void ) LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p) : LLMenuItemGL(p) { - LLMenuGL* branch = p.branch; - if (branch) - { - mBranchHandle = branch->getHandle(); - branch->setVisible(FALSE); - branch->setParentMenuItem(this); - } + LLMenuGL* branch = p.branch; + if (branch) + { + mBranchHandle = branch->getHandle(); + branch->setVisible(FALSE); + branch->setParentMenuItem(this); + } } LLMenuItemBranchGL::~LLMenuItemBranchGL() { - if (mBranchHandle.get()) - { - mBranchHandle.get()->die(); - } + if (mBranchHandle.get()) + { + mBranchHandle.get()->die(); + } } @@ -990,348 +990,348 @@ LLMenuItemBranchGL::~LLMenuItemBranchGL() // virtual LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse) const { - LLMenuGL* branch = getBranch(); - if (branch) - { - if (branch->getName() == name) - { - return branch; - } + LLMenuGL* branch = getBranch(); + if (branch) + { + if (branch->getName() == name) + { + return branch; + } - // Always recurse on branches - return branch->getChildView(name, recurse); - } + // Always recurse on branches + return branch->getChildView(name, recurse); + } - return LLView::getChildView(name, recurse); + return LLView::getChildView(name, recurse); } LLView* LLMenuItemBranchGL::findChildView(const std::string& name, BOOL recurse) const { - LLMenuGL* branch = getBranch(); - if (branch) - { - if (branch->getName() == name) - { - return branch; - } + LLMenuGL* branch = getBranch(); + if (branch) + { + if (branch->getName() == name) + { + return branch; + } - // Always recurse on branches - return branch->findChildView(name, recurse); - } + // Always recurse on branches + return branch->findChildView(name, recurse); + } - return LLView::findChildView(name, recurse); + return LLView::findChildView(name, recurse); } // virtual BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask) { - // switch to mouse navigation mode - LLMenuGL::setKeyboardMode(FALSE); + // switch to mouse navigation mode + LLMenuGL::setKeyboardMode(FALSE); - onCommit(); - make_ui_sound("UISndClickRelease"); - return TRUE; + onCommit(); + make_ui_sound("UISndClickRelease"); + return TRUE; } bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const { - return getBranch() && getBranch()->hasAccelerator(key, mask); + return getBranch() && getBranch()->hasAccelerator(key, mask); } BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask) { - return getBranch() && getBranch()->handleAcceleratorKey(key, mask); + return getBranch() && getBranch()->handleAcceleratorKey(key, mask); } // This function checks to see if the accelerator key is already in use; // if not, it will be added to the list BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp) { - LLMenuGL* branch = getBranch(); - if (!branch) - return FALSE; + LLMenuGL* branch = getBranch(); + if (!branch) + return FALSE; + + U32 item_count = branch->getItemCount(); + LLMenuItemGL *item; - U32 item_count = branch->getItemCount(); - LLMenuItemGL *item; - - while (item_count--) - { - if ((item = branch->getItem(item_count))) - { - return item->addToAcceleratorList(listp); - } - } + while (item_count--) + { + if ((item = branch->getItem(item_count))) + { + return item->addToAcceleratorList(listp); + } + } - return FALSE; + return FALSE; } // called to rebuild the draw label void LLMenuItemBranchGL::buildDrawLabel( void ) { - mDrawAccelLabel.clear(); - std::string st = mDrawAccelLabel; - appendAcceleratorString( st ); - mDrawAccelLabel = st; - mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; + mDrawAccelLabel.clear(); + std::string st = mDrawAccelLabel; + appendAcceleratorString( st ); + mDrawAccelLabel = st; + mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; } void LLMenuItemBranchGL::onCommit( void ) { - openMenu(); + openMenu(); + + // keyboard navigation automatically propagates highlight to sub-menu + // to facilitate fast menu control via jump keys + if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem()) + { + getBranch()->highlightNextItem(NULL); + } - // keyboard navigation automatically propagates highlight to sub-menu - // to facilitate fast menu control via jump keys - if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem()) - { - getBranch()->highlightNextItem(NULL); - } - - LLUICtrl::onCommit(); + LLUICtrl::onCommit(); } BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - BOOL handled = FALSE; - if (getBranch() && called_from_parent) - { - handled = getBranch()->handleKey(key, mask, called_from_parent); - } + BOOL handled = FALSE; + if (getBranch() && called_from_parent) + { + handled = getBranch()->handleKey(key, mask, called_from_parent); + } - if (!handled) - { - handled = LLMenuItemGL::handleKey(key, mask, called_from_parent); - } + if (!handled) + { + handled = LLMenuItemGL::handleKey(key, mask, called_from_parent); + } - return handled; + return handled; } BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { - BOOL handled = FALSE; - if (getBranch() && called_from_parent) - { - handled = getBranch()->handleUnicodeChar(uni_char, TRUE); - } + BOOL handled = FALSE; + if (getBranch() && called_from_parent) + { + handled = getBranch()->handleUnicodeChar(uni_char, TRUE); + } - if (!handled) - { - handled = LLMenuItemGL::handleUnicodeChar(uni_char, called_from_parent); - } + if (!handled) + { + handled = LLMenuItemGL::handleUnicodeChar(uni_char, called_from_parent); + } - return handled; + return handled; } void LLMenuItemBranchGL::setHighlight( BOOL highlight ) { - if (highlight == getHighlight()) - return; - - LLMenuGL* branch = getBranch(); - if (!branch) - return; - - BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff()); - // torn off menus don't open sub menus on hover unless they have focus - LLFloater * menu_parent = dynamic_cast<LLFloater *>(getMenu()->getParent()); - if (getMenu()->getTornOff() && menu_parent && !menu_parent->hasFocus()) - { - auto_open = FALSE; - } - // don't auto open torn off sub-menus (need to explicitly active menu item to give them focus) - if (branch->getTornOff()) - { - auto_open = FALSE; - } - LLMenuItemGL::setHighlight(highlight); - if( highlight ) - { - if(auto_open) - { - openMenu(); - } - } - else - { - if (branch->getTornOff()) - { - LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); - if (branch_parent) - { - branch_parent->setFocus(FALSE); - } - branch->clearHoverItem(); - } - else - { - branch->setVisible( FALSE ); - } - } + if (highlight == getHighlight()) + return; + + LLMenuGL* branch = getBranch(); + if (!branch) + return; + + BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff()); + // torn off menus don't open sub menus on hover unless they have focus + LLFloater * menu_parent = dynamic_cast<LLFloater *>(getMenu()->getParent()); + if (getMenu()->getTornOff() && menu_parent && !menu_parent->hasFocus()) + { + auto_open = FALSE; + } + // don't auto open torn off sub-menus (need to explicitly active menu item to give them focus) + if (branch->getTornOff()) + { + auto_open = FALSE; + } + LLMenuItemGL::setHighlight(highlight); + if( highlight ) + { + if(auto_open) + { + openMenu(); + } + } + else + { + if (branch->getTornOff()) + { + LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } + branch->clearHoverItem(); + } + else + { + branch->setVisible( FALSE ); + } + } } void LLMenuItemBranchGL::draw() { - LLMenuItemGL::draw(); - if (getBranch() && getBranch()->getVisible() && !getBranch()->getTornOff()) - { - setHighlight(TRUE); - } + LLMenuItemGL::draw(); + if (getBranch() && getBranch()->getVisible() && !getBranch()->getTornOff()) + { + setHighlight(TRUE); + } } void LLMenuItemBranchGL::updateBranchParent(LLView* parentp) { - if (getBranch() && getBranch()->getParent() == NULL) - { - // make the branch menu a sibling of my parent menu - getBranch()->updateParent(parentp); - } + if (getBranch() && getBranch()->getParent() == NULL) + { + // make the branch menu a sibling of my parent menu + getBranch()->updateParent(parentp); + } } void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility ) { - if (new_visibility == FALSE && getBranch() && !getBranch()->getTornOff()) - { - getBranch()->setVisible(FALSE); - } - LLMenuItemGL::onVisibilityChange(new_visibility); + if (new_visibility == FALSE && getBranch() && !getBranch()->getTornOff()) + { + getBranch()->setVisible(FALSE); + } + LLMenuItemGL::onVisibilityChange(new_visibility); } BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask ) { - LLMenuGL* branch = getBranch(); - if (!branch) - return LLMenuItemGL::handleKeyHere(key, mask); - - // an item is highlighted, my menu is open, and I have an active sub menu or we are in - // keyboard navigation mode - if (getHighlight() - && getMenu()->isOpen() - && (isActive() || LLMenuGL::getKeyboardMode())) - { - if (branch->getVisible() && key == KEY_LEFT) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - BOOL handled = branch->clearHoverItem(); - if (branch->getTornOff()) - { - LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); - if (branch_parent) - { - branch_parent->setFocus(FALSE); - } - } - if (handled && getMenu()->getTornOff()) - { - LLFloater * menu_parent = dynamic_cast<LLFloater *>(getMenu()->getParent()); - if (menu_parent) - { - menu_parent->setFocus(TRUE); - } - } - return handled; - } - - if (key == KEY_RIGHT && !branch->getHighlightedItem()) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - LLMenuItemGL* itemp = branch->highlightNextItem(NULL); - if (itemp) - { - return TRUE; - } - } - } - return LLMenuItemGL::handleKeyHere(key, mask); + LLMenuGL* branch = getBranch(); + if (!branch) + return LLMenuItemGL::handleKeyHere(key, mask); + + // an item is highlighted, my menu is open, and I have an active sub menu or we are in + // keyboard navigation mode + if (getHighlight() + && getMenu()->isOpen() + && (isActive() || LLMenuGL::getKeyboardMode())) + { + if (branch->getVisible() && key == KEY_LEFT) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + BOOL handled = branch->clearHoverItem(); + if (branch->getTornOff()) + { + LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } + } + if (handled && getMenu()->getTornOff()) + { + LLFloater * menu_parent = dynamic_cast<LLFloater *>(getMenu()->getParent()); + if (menu_parent) + { + menu_parent->setFocus(TRUE); + } + } + return handled; + } + + if (key == KEY_RIGHT && !branch->getHighlightedItem()) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + LLMenuItemGL* itemp = branch->highlightNextItem(NULL); + if (itemp) + { + return TRUE; + } + } + } + return LLMenuItemGL::handleKeyHere(key, mask); } //virtual BOOL LLMenuItemBranchGL::isActive() const { - return isOpen() && getBranch() && getBranch()->getHighlightedItem(); + return isOpen() && getBranch() && getBranch()->getHighlightedItem(); } //virtual BOOL LLMenuItemBranchGL::isOpen() const { - return getBranch() && getBranch()->isOpen(); + return getBranch() && getBranch()->isOpen(); } void LLMenuItemBranchGL::openMenu() { - LLMenuGL* branch = getBranch(); - if (!branch) - return; - - if (branch->getTornOff()) - { - LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); - if (branch_parent) - { - gFloaterView->bringToFront(branch_parent); - // this might not be necessary, as torn off branches don't get focus and hence no highligth - branch->highlightNextItem(NULL); - } - } - else if( !branch->getVisible() ) - { - // get valid rectangle for menus - const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); - - branch->arrange(); - - LLRect branch_rect = branch->getRect(); - // calculate root-view relative position for branch menu - S32 left = getRect().mRight; - S32 top = getRect().mTop - getRect().mBottom; - - localPointToOtherView(left, top, &left, &top, branch->getParent()); - - branch_rect.setLeftTopAndSize( left, top, - branch_rect.getWidth(), branch_rect.getHeight() ); - - if (branch->getCanTearOff()) - { - branch_rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS); - } - branch->setRect( branch_rect ); - - // if branch extends outside of menu region change the direction it opens in - S32 x, y; - S32 delta_x = 0; - S32 delta_y = 0; - branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); - if( y < menu_region_rect.mBottom ) - { - // open upwards if menu extends past bottom - // adjust by the height of the menu item branch since it is a submenu - if (y + 2 * branch_rect.getHeight() - getRect().getHeight() > menu_region_rect.mTop) - { - // overlaps with top border, align with top - delta_y = menu_region_rect.mTop - y - branch_rect.getHeight(); - } - else - { - delta_y = branch_rect.getHeight() - getRect().getHeight(); - } - } - - if( x + branch_rect.getWidth() > menu_region_rect.mRight ) - { - // move sub-menu over to left side - delta_x = llmax(-x, ( -(branch_rect.getWidth() + getRect().getWidth()))); - } - branch->translate( delta_x, delta_y ); - - branch->setVisible( TRUE ); - branch->getParent()->sendChildToFront(branch); - - dirtyRect(); - } + LLMenuGL* branch = getBranch(); + if (!branch) + return; + + if (branch->getTornOff()) + { + LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); + if (branch_parent) + { + gFloaterView->bringToFront(branch_parent); + // this might not be necessary, as torn off branches don't get focus and hence no highligth + branch->highlightNextItem(NULL); + } + } + else if( !branch->getVisible() ) + { + // get valid rectangle for menus + const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); + + branch->arrange(); + + LLRect branch_rect = branch->getRect(); + // calculate root-view relative position for branch menu + S32 left = getRect().mRight; + S32 top = getRect().mTop - getRect().mBottom; + + localPointToOtherView(left, top, &left, &top, branch->getParent()); + + branch_rect.setLeftTopAndSize( left, top, + branch_rect.getWidth(), branch_rect.getHeight() ); + + if (branch->getCanTearOff()) + { + branch_rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS); + } + branch->setRect( branch_rect ); + + // if branch extends outside of menu region change the direction it opens in + S32 x, y; + S32 delta_x = 0; + S32 delta_y = 0; + branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); + if( y < menu_region_rect.mBottom ) + { + // open upwards if menu extends past bottom + // adjust by the height of the menu item branch since it is a submenu + if (y + 2 * branch_rect.getHeight() - getRect().getHeight() > menu_region_rect.mTop) + { + // overlaps with top border, align with top + delta_y = menu_region_rect.mTop - y - branch_rect.getHeight(); + } + else + { + delta_y = branch_rect.getHeight() - getRect().getHeight(); + } + } + + if( x + branch_rect.getWidth() > menu_region_rect.mRight ) + { + // move sub-menu over to left side + delta_x = llmax(-x, ( -(branch_rect.getWidth() + getRect().getWidth()))); + } + branch->translate( delta_x, delta_y ); + + branch->setVisible( TRUE ); + branch->getParent()->sendChildToFront(branch); + + dirtyRect(); + } } @@ -1347,39 +1347,39 @@ class LLMenuItemBranchDownGL : public LLMenuItemBranchGL protected: public: - LLMenuItemBranchDownGL( const Params& ); + LLMenuItemBranchDownGL( const Params& ); - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // handles opening, positioning, and arranging the menu branch associated with this item - virtual void openMenu( void ); + // handles opening, positioning, and arranging the menu branch associated with this item + virtual void openMenu( void ); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL isActive( void ) const; + virtual BOOL isActive( void ) const; + + // LLView functionality + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual void draw( void ); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // LLView functionality - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual void draw( void ); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual void onFocusLost(); virtual void setFocus(BOOL b); }; LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const Params& p) : - LLMenuItemBranchGL(p) + LLMenuItemBranchGL(p) { } @@ -1388,147 +1388,147 @@ LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const Params& p) : // arrangement. U32 LLMenuItemBranchDownGL::getNominalWidth( void ) const { - U32 width = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS + RIGHT_PAD_PIXELS; - width += getFont()->getWidth( mLabel.getWString().c_str() ); - return width; + U32 width = LEFT_PAD_PIXELS + LEFT_WIDTH_PIXELS + RIGHT_PAD_PIXELS; + width += getFont()->getWidth( mLabel.getWString().c_str() ); + return width; } // called to rebuild the draw label void LLMenuItemBranchDownGL::buildDrawLabel( void ) { - mDrawAccelLabel.clear(); - std::string st = mDrawAccelLabel; - appendAcceleratorString( st ); - mDrawAccelLabel = st; + mDrawAccelLabel.clear(); + std::string st = mDrawAccelLabel; + appendAcceleratorString( st ); + mDrawAccelLabel = st; } void LLMenuItemBranchDownGL::openMenu( void ) { - LLMenuGL* branch = getBranch(); - if( branch->getVisible() && !branch->getTornOff() ) - { - branch->setVisible( FALSE ); - } - else - { - if (branch->getTornOff()) - { - LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); - if (branch_parent) - { - gFloaterView->bringToFront(branch_parent); - } - } - else - { - // We're showing the drop-down menu, so patch up its labels/rects - branch->arrange(); - - LLRect rect = branch->getRect(); - S32 left = 0; - S32 top = getRect().mBottom; - localPointToOtherView(left, top, &left, &top, branch->getParent()); - - rect.setLeftTopAndSize( left, top, - rect.getWidth(), rect.getHeight() ); - branch->setRect( rect ); - S32 x = 0; - S32 y = 0; - branch->localPointToScreen( 0, 0, &x, &y ); - S32 delta_x = 0; - - LLCoordScreen window_size; - LLWindow* windowp = getWindow(); - windowp->getSize(&window_size); - - S32 window_width = window_size.mX; - if( x > window_width - rect.getWidth() ) - { - delta_x = (window_width - rect.getWidth()) - x; - } - branch->translate( delta_x, 0 ); - - setHighlight(TRUE); - branch->setVisible( TRUE ); - branch->getParent()->sendChildToFront(branch); - } - } + LLMenuGL* branch = getBranch(); + if( branch->getVisible() && !branch->getTornOff() ) + { + branch->setVisible( FALSE ); + } + else + { + if (branch->getTornOff()) + { + LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); + if (branch_parent) + { + gFloaterView->bringToFront(branch_parent); + } + } + else + { + // We're showing the drop-down menu, so patch up its labels/rects + branch->arrange(); + + LLRect rect = branch->getRect(); + S32 left = 0; + S32 top = getRect().mBottom; + localPointToOtherView(left, top, &left, &top, branch->getParent()); + + rect.setLeftTopAndSize( left, top, + rect.getWidth(), rect.getHeight() ); + branch->setRect( rect ); + S32 x = 0; + S32 y = 0; + branch->localPointToScreen( 0, 0, &x, &y ); + S32 delta_x = 0; + + LLCoordScreen window_size; + LLWindow* windowp = getWindow(); + windowp->getSize(&window_size); + + S32 window_width = window_size.mX; + if( x > window_width - rect.getWidth() ) + { + delta_x = (window_width - rect.getWidth()) - x; + } + branch->translate( delta_x, 0 ); + + setHighlight(TRUE); + branch->setVisible( TRUE ); + branch->getParent()->sendChildToFront(branch); + } + } } // set the hover status (called by it's menu) void LLMenuItemBranchDownGL::setHighlight( BOOL highlight ) { - if (highlight == getHighlight()) - return; - - //NOTE: Purposely calling all the way to the base to bypass auto-open. - LLMenuItemGL::setHighlight(highlight); - - LLMenuGL* branch = getBranch(); - if (!branch) - return; - - if( !highlight) - { - if (branch->getTornOff()) - { - LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); - if (branch_parent) - { - branch_parent->setFocus(FALSE); - } - branch->clearHoverItem(); - } - else - { - branch->setVisible( FALSE ); - } - } + if (highlight == getHighlight()) + return; + + //NOTE: Purposely calling all the way to the base to bypass auto-open. + LLMenuItemGL::setHighlight(highlight); + + LLMenuGL* branch = getBranch(); + if (!branch) + return; + + if( !highlight) + { + if (branch->getTornOff()) + { + LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } + branch->clearHoverItem(); + } + else + { + branch->setVisible( FALSE ); + } + } } BOOL LLMenuItemBranchDownGL::isActive() const { - // for top level menus, being open is sufficient to be considered - // active, because clicking on them with the mouse will open - // them, without moving keyboard focus to them - return isOpen(); + // for top level menus, being open is sufficient to be considered + // active, because clicking on them with the mouse will open + // them, without moving keyboard focus to them + return isOpen(); } BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask ) { - // switch to mouse control mode - LLMenuGL::setKeyboardMode(FALSE); + // switch to mouse control mode + LLMenuGL::setKeyboardMode(FALSE); - if (getVisible() && isOpen()) - { - LLMenuGL::sMenuContainer->hideMenus(); - } - else - { - onCommit(); - } + if (getVisible() && isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + else + { + onCommit(); + } - make_ui_sound("UISndClick"); - return TRUE; + make_ui_sound("UISndClick"); + return TRUE; } BOOL LLMenuItemBranchDownGL::handleMouseUp( S32 x, S32 y, MASK mask ) { - return TRUE; + return TRUE; } BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask) { - BOOL branch_visible = getBranch()->getVisible(); - BOOL handled = getBranch()->handleAcceleratorKey(key, mask); - if (handled && !branch_visible && isInVisibleChain()) - { - // flash this menu entry because we triggered an invisible menu item - LLMenuHolderGL::setActivatedItem(this); - } + BOOL branch_visible = getBranch()->getVisible(); + BOOL handled = getBranch()->handleAcceleratorKey(key, mask); + if (handled && !branch_visible && isInVisibleChain()) + { + // flash this menu entry because we triggered an invisible menu item + LLMenuHolderGL::setActivatedItem(this); + } - return handled; + return handled; } void LLMenuItemBranchDownGL::onFocusLost() { @@ -1548,211 +1548,211 @@ void LLMenuItemBranchDownGL::setFocus(BOOL b) BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) { - BOOL menu_open = getBranch()->getVisible(); - // don't do keyboard navigation of top-level menus unless in keyboard mode, or menu expanded - if (getHighlight() && getMenu()->isOpen() && (isActive() || LLMenuGL::getKeyboardMode())) - { - if (key == KEY_LEFT) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - LLMenuItemGL* itemp = getMenu()->highlightPrevItem(this); - // open new menu only if previous menu was open - if (itemp && itemp->getEnabled() && menu_open) - { - itemp->onCommit(); - } - - return TRUE; - } - else if (key == KEY_RIGHT) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - LLMenuItemGL* itemp = getMenu()->highlightNextItem(this); - // open new menu only if previous menu was open - if (itemp && itemp->getEnabled() && menu_open) - { - itemp->onCommit(); - } - - return TRUE; - } - else if (key == KEY_DOWN) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - if (!isActive()) - { - onCommit(); - } - getBranch()->highlightNextItem(NULL); - return TRUE; - } - else if (key == KEY_UP) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - if (!isActive()) - { - onCommit(); - } - getBranch()->highlightPrevItem(NULL); - return TRUE; - } - } - - return FALSE; + BOOL menu_open = getBranch()->getVisible(); + // don't do keyboard navigation of top-level menus unless in keyboard mode, or menu expanded + if (getHighlight() && getMenu()->isOpen() && (isActive() || LLMenuGL::getKeyboardMode())) + { + if (key == KEY_LEFT) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + LLMenuItemGL* itemp = getMenu()->highlightPrevItem(this); + // open new menu only if previous menu was open + if (itemp && itemp->getEnabled() && menu_open) + { + itemp->onCommit(); + } + + return TRUE; + } + else if (key == KEY_RIGHT) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + LLMenuItemGL* itemp = getMenu()->highlightNextItem(this); + // open new menu only if previous menu was open + if (itemp && itemp->getEnabled() && menu_open) + { + itemp->onCommit(); + } + + return TRUE; + } + else if (key == KEY_DOWN) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + if (!isActive()) + { + onCommit(); + } + getBranch()->highlightNextItem(NULL); + return TRUE; + } + else if (key == KEY_UP) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); + + if (!isActive()) + { + onCommit(); + } + getBranch()->highlightPrevItem(NULL); + return TRUE; + } + } + + return FALSE; } void LLMenuItemBranchDownGL::draw( void ) { - //FIXME: try removing this - if (getBranch()->getVisible() && !getBranch()->getTornOff()) - { - setHighlight(TRUE); - } - - if( getHighlight() ) - { - gGL.color4fv( mHighlightBackground.get().mV ); - gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - } - - LLColor4 color; - if (getHighlight()) - { - color = mHighlightForeground.get(); - } - else if( getEnabled() ) - { - color = mEnabledColor.get(); - } - else - { - color = mDisabledColor.get(); - } - getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color, - LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL); - - - // underline navigation key only when keyboard navigation has been initiated - if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode()) - { - std::string upper_case_label = mLabel.getString(); - LLStringUtil::toUpper(upper_case_label); - std::string::size_type offset = upper_case_label.find(getJumpKey()); - if (offset != std::string::npos) - { - S32 x_offset = ll_round((F32)getRect().getWidth() / 2.f - getFont()->getWidthF32(mLabel.getString(), 0, S32_MAX) / 2.f); - S32 x_begin = x_offset + getFont()->getWidth(mLabel, 0, offset); - S32 x_end = x_offset + getFont()->getWidth(mLabel, 0, offset + 1); - gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS); - } - } + //FIXME: try removing this + if (getBranch()->getVisible() && !getBranch()->getTornOff()) + { + setHighlight(TRUE); + } + + if( getHighlight() ) + { + gGL.color4fv( mHighlightBackground.get().mV ); + gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + } + + LLColor4 color; + if (getHighlight()) + { + color = mHighlightForeground.get(); + } + else if( getEnabled() ) + { + color = mEnabledColor.get(); + } + else + { + color = mDisabledColor.get(); + } + getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color, + LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL); + + + // underline navigation key only when keyboard navigation has been initiated + if (getMenu()->jumpKeysActive() && LLMenuGL::getKeyboardMode()) + { + std::string upper_case_label = mLabel.getString(); + LLStringUtil::toUpper(upper_case_label); + std::string::size_type offset = upper_case_label.find(getJumpKey()); + if (offset != std::string::npos) + { + S32 x_offset = ll_round((F32)getRect().getWidth() / 2.f - getFont()->getWidthF32(mLabel.getString(), 0, S32_MAX) / 2.f); + S32 x_begin = x_offset + getFont()->getWidth(mLabel, 0, offset); + S32 x_end = x_offset + getFont()->getWidth(mLabel, 0, offset + 1); + gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS); + } + } } class LLMenuScrollItem : public LLMenuItemCallGL { public: - enum EArrowType - { - ARROW_DOWN, - ARROW_UP - }; - struct ArrowTypes : public LLInitParam::TypeValuesHelper<EArrowType, ArrowTypes> - { - static void declareValues() - { - declare("up", ARROW_UP); - declare("down", ARROW_DOWN); - } - }; - - struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> - { - Optional<EArrowType, ArrowTypes> arrow_type; - Optional<CommitCallbackParam> scroll_callback; - }; + enum EArrowType + { + ARROW_DOWN, + ARROW_UP + }; + struct ArrowTypes : public LLInitParam::TypeValuesHelper<EArrowType, ArrowTypes> + { + static void declareValues() + { + declare("up", ARROW_UP); + declare("down", ARROW_DOWN); + } + }; + + struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> + { + Optional<EArrowType, ArrowTypes> arrow_type; + Optional<CommitCallbackParam> scroll_callback; + }; protected: - LLMenuScrollItem(const Params&); - friend class LLUICtrlFactory; + LLMenuScrollItem(const Params&); + friend class LLUICtrlFactory; public: - /*virtual*/ void draw(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); - /*virtual*/ void setEnabled(BOOL enabled); - virtual void onCommit( void ); + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); + /*virtual*/ void setEnabled(BOOL enabled); + virtual void onCommit( void ); private: - LLButton* mArrowBtn; + LLButton* mArrowBtn; }; LLMenuScrollItem::LLMenuScrollItem(const Params& p) -: LLMenuItemCallGL(p) -{ - std::string icon; - if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP) - { - icon = "arrow_up.tga"; - } - else - { - icon = "arrow_down.tga"; - } - - LLButton::Params bparams; - - // Disabled the Return key handling by LLMenuScrollItem instead of - // passing the key press to the currently selected menu item. See STORM-385. - bparams.commit_on_return(false); - bparams.mouse_opaque(true); - bparams.scale_image(false); - bparams.click_callback(p.scroll_callback); - bparams.mouse_held_callback(p.scroll_callback); - bparams.follows.flags(FOLLOWS_ALL); - std::string background = "transparent.j2c"; - bparams.image_unselected.name(background); - bparams.image_disabled.name(background); - bparams.image_selected.name(background); - bparams.image_hover_selected.name(background); - bparams.image_disabled_selected.name(background); - bparams.image_hover_unselected.name(background); - bparams.image_overlay.name(icon); - - mArrowBtn = LLUICtrlFactory::create<LLButton>(bparams); - addChild(mArrowBtn); +: LLMenuItemCallGL(p) +{ + std::string icon; + if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP) + { + icon = "arrow_up.tga"; + } + else + { + icon = "arrow_down.tga"; + } + + LLButton::Params bparams; + + // Disabled the Return key handling by LLMenuScrollItem instead of + // passing the key press to the currently selected menu item. See STORM-385. + bparams.commit_on_return(false); + bparams.mouse_opaque(true); + bparams.scale_image(false); + bparams.click_callback(p.scroll_callback); + bparams.mouse_held_callback(p.scroll_callback); + bparams.follows.flags(FOLLOWS_ALL); + std::string background = "transparent.j2c"; + bparams.image_unselected.name(background); + bparams.image_disabled.name(background); + bparams.image_selected.name(background); + bparams.image_hover_selected.name(background); + bparams.image_disabled_selected.name(background); + bparams.image_hover_unselected.name(background); + bparams.image_overlay.name(icon); + + mArrowBtn = LLUICtrlFactory::create<LLButton>(bparams); + addChild(mArrowBtn); } /*virtual*/ void LLMenuScrollItem::draw() { - LLUICtrl::draw(); + LLUICtrl::draw(); } /*virtual*/ void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent) { - mArrowBtn->reshape(width, height, called_from_parent); - LLView::reshape(width, height, called_from_parent); + mArrowBtn->reshape(width, height, called_from_parent); + LLView::reshape(width, height, called_from_parent); } /*virtual*/ void LLMenuScrollItem::setEnabled(BOOL enabled) { - mArrowBtn->setEnabled(enabled); - LLView::setEnabled(enabled); + mArrowBtn->setEnabled(enabled); + LLView::setEnabled(enabled); } void LLMenuScrollItem::onCommit( void ) { - LLUICtrl::onCommit(); + LLUICtrl::onCommit(); } ///============================================================================ @@ -1760,105 +1760,105 @@ void LLMenuScrollItem::onCommit( void ) ///============================================================================ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p) -: LLUICtrl(p), - mBackgroundColor( p.bg_color() ), - mBgVisible( p.bg_visible ), - mDropShadowed( p.drop_shadow ), - mHasSelection(false), - mHorizontalLayout( p.horizontal_layout ), - mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout - mMaxScrollableItems(p.max_scrollable_items), - mPreferredWidth(p.preferred_width), - mKeepFixedSize( p.keep_fixed_size ), - mLabel (p.label), - mLastMouseX(0), - mLastMouseY(0), - mMouseVelX(0), - mMouseVelY(0), - mTornOff(FALSE), - mTearOffItem(NULL), - mSpilloverBranch(NULL), - mFirstVisibleItem(NULL), - mArrowUpItem(NULL), - mArrowDownItem(NULL), - mSpilloverMenu(NULL), - mJumpKey(p.jump_key), - mCreateJumpKeys(p.create_jump_keys), - mNeedsArrange(FALSE), - mAlwaysShowMenu(FALSE), - mResetScrollPositionOnShow(true), - mShortcutPad(p.shortcut_pad), +: LLUICtrl(p), + mBackgroundColor( p.bg_color() ), + mBgVisible( p.bg_visible ), + mDropShadowed( p.drop_shadow ), + mHasSelection(false), + mHorizontalLayout( p.horizontal_layout ), + mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout + mMaxScrollableItems(p.max_scrollable_items), + mPreferredWidth(p.preferred_width), + mKeepFixedSize( p.keep_fixed_size ), + mLabel (p.label), + mLastMouseX(0), + mLastMouseY(0), + mMouseVelX(0), + mMouseVelY(0), + mTornOff(FALSE), + mTearOffItem(NULL), + mSpilloverBranch(NULL), + mFirstVisibleItem(NULL), + mArrowUpItem(NULL), + mArrowDownItem(NULL), + mSpilloverMenu(NULL), + mJumpKey(p.jump_key), + mCreateJumpKeys(p.create_jump_keys), + mNeedsArrange(FALSE), + mAlwaysShowMenu(FALSE), + mResetScrollPositionOnShow(true), + mShortcutPad(p.shortcut_pad), mFont(p.font) { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("_"); - tokenizer tokens(p.label(), sep); - tokenizer::iterator token_iter; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("_"); + tokenizer tokens(p.label(), sep); + tokenizer::iterator token_iter; - S32 token_count = 0; - std::string new_menu_label; - for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - new_menu_label += (*token_iter); - if (token_count > 0) - { - setJumpKey((*token_iter).c_str()[0]); - } - ++token_count; - } - setLabel(new_menu_label); + S32 token_count = 0; + std::string new_menu_label; + for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + new_menu_label += (*token_iter); + if (token_count > 0) + { + setJumpKey((*token_iter).c_str()[0]); + } + ++token_count; + } + setLabel(new_menu_label); - mFadeTimer.stop(); + mFadeTimer.stop(); } void LLMenuGL::initFromParams(const LLMenuGL::Params& p) { - LLUICtrl::initFromParams(p); - setCanTearOff(p.can_tear_off); + LLUICtrl::initFromParams(p); + setCanTearOff(p.can_tear_off); } // Destroys the object LLMenuGL::~LLMenuGL( void ) { - // delete the branch, as it might not be in view hierarchy - // leave the menu, because it is always in view hierarchy - delete mSpilloverBranch; - mJumpKeys.clear(); + // delete the branch, as it might not be in view hierarchy + // leave the menu, because it is always in view hierarchy + delete mSpilloverBranch; + mJumpKeys.clear(); } void LLMenuGL::setCanTearOff(BOOL tear_off) { - if (tear_off && mTearOffItem == NULL) - { - LLMenuItemTearOffGL::Params p; - mTearOffItem = LLUICtrlFactory::create<LLMenuItemTearOffGL>(p); - addChild(mTearOffItem); - } - else if (!tear_off && mTearOffItem != NULL) - { - mItems.remove(mTearOffItem); - removeChild(mTearOffItem); - delete mTearOffItem; - mTearOffItem = NULL; - needsArrange(); - } + if (tear_off && mTearOffItem == NULL) + { + LLMenuItemTearOffGL::Params p; + mTearOffItem = LLUICtrlFactory::create<LLMenuItemTearOffGL>(p); + addChild(mTearOffItem); + } + else if (!tear_off && mTearOffItem != NULL) + { + mItems.remove(mTearOffItem); + removeChild(mTearOffItem); + delete mTearOffItem; + mTearOffItem = NULL; + needsArrange(); + } } bool LLMenuGL::addChild(LLView* view, S32 tab_group) { - LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); - if (menup) - { - return appendMenu(menup); - } - - LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view); - if (itemp) - { - return append(itemp); - } - - return false; + LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); + if (menup) + { + return appendMenu(menup); + } + + LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view); + if (itemp) + { + return append(itemp); + } + + return false; } // Used in LLContextMenu and in LLTogleableMenu @@ -1866,31 +1866,31 @@ bool LLMenuGL::addChild(LLView* view, S32 tab_group) // Add an item to the context menu branch bool LLMenuGL::addContextChild(LLView* view, S32 tab_group) { - LLContextMenu* context = dynamic_cast<LLContextMenu*>(view); - if (context) - { - return appendContextSubMenu(context); - } + LLContextMenu* context = dynamic_cast<LLContextMenu*>(view); + if (context) + { + return appendContextSubMenu(context); + } + + LLMenuItemSeparatorGL* separator = dynamic_cast<LLMenuItemSeparatorGL*>(view); + if (separator) + { + return append(separator); + } - LLMenuItemSeparatorGL* separator = dynamic_cast<LLMenuItemSeparatorGL*>(view); - if (separator) - { - return append(separator); - } + LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view); + if (item) + { + return append(item); + } - LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view); - if (item) - { - return append(item); - } - - LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); - if (menup) - { - return appendMenu(menup); - } + LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); + if (menup) + { + return appendMenu(menup); + } - return false; + return false; } @@ -1902,502 +1902,502 @@ void LLMenuGL::deleteAllChildren() void LLMenuGL::removeChild( LLView* ctrl) { - // previously a dynamic_cast with if statement to check validity - // unfortunately removeChild is called by ~LLView, and at that point the - // object being deleted is no longer a LLMenuItemGL so a dynamic_cast will fail - LLMenuItemGL* itemp = static_cast<LLMenuItemGL*>(ctrl); + // previously a dynamic_cast with if statement to check validity + // unfortunately removeChild is called by ~LLView, and at that point the + // object being deleted is no longer a LLMenuItemGL so a dynamic_cast will fail + LLMenuItemGL* itemp = static_cast<LLMenuItemGL*>(ctrl); - item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp)); - if (found_it != mItems.end()) - { - mItems.erase(found_it); - } + item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp)); + if (found_it != mItems.end()) + { + mItems.erase(found_it); + } - return LLUICtrl::removeChild(ctrl); + return LLUICtrl::removeChild(ctrl); } BOOL LLMenuGL::postBuild() { - createJumpKeys(); - return LLUICtrl::postBuild(); + createJumpKeys(); + return LLUICtrl::postBuild(); } // are we the childmost active menu and hence our jump keys should be enabled? // or are we a free-standing torn-off menu (which uses jump keys too) BOOL LLMenuGL::jumpKeysActive() { - LLMenuItemGL* highlighted_item = getHighlightedItem(); - BOOL active = getVisible() && getEnabled(); - - if (active) - { - if (getTornOff()) - { - // activation of jump keys on torn off menus controlled by keyboard focus - LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); - if (parent) - { - active = parent->hasFocus(); - } - } - else - { - // Are we the terminal active menu? - // Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus) - // and we don't have a highlighted menu item pointing to an active sub-menu - active = (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active... - && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active - } - } - - return active; + LLMenuItemGL* highlighted_item = getHighlightedItem(); + BOOL active = getVisible() && getEnabled(); + + if (active) + { + if (getTornOff()) + { + // activation of jump keys on torn off menus controlled by keyboard focus + LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); + if (parent) + { + active = parent->hasFocus(); + } + } + else + { + // Are we the terminal active menu? + // Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus) + // and we don't have a highlighted menu item pointing to an active sub-menu + active = (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active... + && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active + } + } + + return active; } BOOL LLMenuGL::isOpen() { - if (getTornOff()) - { - LLMenuItemGL* itemp = getHighlightedItem(); - // if we have an open sub-menu, then we are considered part of - // the open menu chain even if we don't have focus - if (itemp && itemp->isOpen()) - { - return TRUE; - } - // otherwise we are only active if we have keyboard focus - LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); - if (parent) - { - return parent->hasFocus(); - } - return FALSE; - } - else - { - // normally, menus are hidden as soon as the user focuses - // on another menu, so just use the visibility criterion - return getVisible(); - } + if (getTornOff()) + { + LLMenuItemGL* itemp = getHighlightedItem(); + // if we have an open sub-menu, then we are considered part of + // the open menu chain even if we don't have focus + if (itemp && itemp->isOpen()) + { + return TRUE; + } + // otherwise we are only active if we have keyboard focus + LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); + if (parent) + { + return parent->hasFocus(); + } + return FALSE; + } + else + { + // normally, menus are hidden as soon as the user focuses + // on another menu, so just use the visibility criterion + return getVisible(); + } } bool LLMenuGL::scrollItems(EScrollingDirection direction) { - // Slowing down items scrolling when arrow button is held - if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem) - { - mScrollItemsTimer.setTimerExpirySec(.033f); - } - else - { - return false; - } - - switch (direction) - { - case SD_UP: - { - item_list_t::iterator cur_item_iter; - item_list_t::iterator prev_item_iter; - for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) - { - if( (*cur_item_iter) == mFirstVisibleItem) - { - break; - } - if ((*cur_item_iter)->getVisible()) - { - prev_item_iter = cur_item_iter; - } - } - - if ((*prev_item_iter)->getVisible()) - { - mFirstVisibleItem = *prev_item_iter; - } - break; - } - case SD_DOWN: - { - if (NULL == mFirstVisibleItem) - { - mFirstVisibleItem = *mItems.begin(); - } - - item_list_t::iterator cur_item_iter; - - for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) - { - if( (*cur_item_iter) == mFirstVisibleItem) - { - break; - } - } - - item_list_t::iterator next_item_iter; - - if (cur_item_iter != mItems.end()) - { - for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) - { - if( (*next_item_iter)->getVisible()) - { - break; - } - } - - if (next_item_iter != mItems.end() && - (*next_item_iter)->getVisible()) - { - mFirstVisibleItem = *next_item_iter; - } - } - break; - } - case SD_BEGIN: - { - mFirstVisibleItem = *mItems.begin(); - break; - } - case SD_END: - { - item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); - - // Need to scroll through number of actual existing items in menu. - // Otherwise viewer will hang for a time needed to scroll U32_MAX - // times in std::advance(). STORM-659. - size_t nitems = mItems.size(); - U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems; - - // Advance by mMaxScrollableItems back from the end of the list - // to make the last item visible. - std::advance(first_visible_item_iter, scrollable_items); - mFirstVisibleItem = *first_visible_item_iter; - break; - } - default: - LL_WARNS() << "Unknown scrolling direction: " << direction << LL_ENDL; - } - - mNeedsArrange = TRUE; - arrangeAndClear(); - - return true; + // Slowing down items scrolling when arrow button is held + if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem) + { + mScrollItemsTimer.setTimerExpirySec(.033f); + } + else + { + return false; + } + + switch (direction) + { + case SD_UP: + { + item_list_t::iterator cur_item_iter; + item_list_t::iterator prev_item_iter; + for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + if ((*cur_item_iter)->getVisible()) + { + prev_item_iter = cur_item_iter; + } + } + + if ((*prev_item_iter)->getVisible()) + { + mFirstVisibleItem = *prev_item_iter; + } + break; + } + case SD_DOWN: + { + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *mItems.begin(); + } + + item_list_t::iterator cur_item_iter; + + for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + } + + item_list_t::iterator next_item_iter; + + if (cur_item_iter != mItems.end()) + { + for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) + { + if( (*next_item_iter)->getVisible()) + { + break; + } + } + + if (next_item_iter != mItems.end() && + (*next_item_iter)->getVisible()) + { + mFirstVisibleItem = *next_item_iter; + } + } + break; + } + case SD_BEGIN: + { + mFirstVisibleItem = *mItems.begin(); + break; + } + case SD_END: + { + item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); + + // Need to scroll through number of actual existing items in menu. + // Otherwise viewer will hang for a time needed to scroll U32_MAX + // times in std::advance(). STORM-659. + size_t nitems = mItems.size(); + U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems; + + // Advance by mMaxScrollableItems back from the end of the list + // to make the last item visible. + std::advance(first_visible_item_iter, scrollable_items); + mFirstVisibleItem = *first_visible_item_iter; + break; + } + default: + LL_WARNS() << "Unknown scrolling direction: " << direction << LL_ENDL; + } + + mNeedsArrange = TRUE; + arrangeAndClear(); + + return true; } // rearrange the child rects so they fit the shape of the menu. void LLMenuGL::arrange( void ) { - // calculate the height & width, and set our rect based on that - // information. - const LLRect& initial_rect = getRect(); - - U32 width = 0, height = MENU_ITEM_PADDING; - - cleanupSpilloverBranch(); - - if( mItems.size() ) - { - const LLRect menu_region_rect = LLMenuGL::sMenuContainer ? LLMenuGL::sMenuContainer->getMenuRect() : LLRect(0, S32_MAX, S32_MAX, 0); - - // torn off menus are not constrained to the size of the screen - U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth(); - U32 max_height = getTornOff() ? U32_MAX: menu_region_rect.getHeight(); - - // *FIX: create the item first and then ask for its dimensions? - S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate - S32 spillover_item_height = LLFontGL::getFontSansSerif()->getLineHeight() + MENU_ITEM_PADDING; - - // Scrolling support - item_list_t::iterator first_visible_item_iter; - item_list_t::iterator first_hidden_item_iter = mItems.end(); - S32 height_before_first_visible_item = -1; - S32 visible_items_height = 0; - U32 scrollable_items_cnt = 0; - - if (mHorizontalLayout) - { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - // do first so LLMenuGLItemCall can call on_visible to determine if visible - (*item_iter)->buildDrawLabel(); - - if ((*item_iter)->getVisible()) - { - if (!getTornOff() - && *item_iter != mSpilloverBranch - && width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width) - { - // no room for any more items - createSpilloverBranch(); - - std::vector<LLMenuItemGL*> items_to_remove; - std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); - std::vector<LLMenuItemGL*>::iterator spillover_iter; - for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) - { - LLMenuItemGL* itemp = (*spillover_iter); - removeChild(itemp); - mSpilloverMenu->addChild(itemp); - } - - addChild(mSpilloverBranch); - - height = llmax(height, mSpilloverBranch->getNominalHeight()); - width += mSpilloverBranch->getNominalWidth(); - - break; - } - else - { - // track our rect - height = llmax(height, (*item_iter)->getNominalHeight()); - width += (*item_iter)->getNominalWidth(); - } - } - } - } - else - { - for (LLMenuItemGL* itemp : mItems) - { - // do first so LLMenuGLItemCall can call on_visible to determine if visible - itemp->buildDrawLabel(); - } - item_list_t::iterator item_iter; - - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if ((*item_iter)->getVisible()) - { - if (!getTornOff() - && !mScrollable - && *item_iter != mSpilloverBranch - && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) - { - // don't show only one item - int visible_items = 0; - item_list_t::iterator count_iter; - for (count_iter = item_iter; count_iter != mItems.end(); ++count_iter) - { - if((*count_iter)->getVisible()) - visible_items++; - } - if (visible_items>1) - { - // no room for any more items - createSpilloverBranch(); - - std::vector<LLMenuItemGL*> items_to_remove; - std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); - std::vector<LLMenuItemGL*>::iterator spillover_iter; - for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) - { - LLMenuItemGL* itemp = (*spillover_iter); - removeChild(itemp); - mSpilloverMenu->addChild(itemp); - } - - - addChild(mSpilloverBranch); - - height += mSpilloverBranch->getNominalHeight(); - width = llmax( width, mSpilloverBranch->getNominalWidth() ); - - break; - } - } - - // track our rect - height += (*item_iter)->getNominalHeight(); - width = llmax( width, (*item_iter)->getNominalWidth() ); - - if (mScrollable) - { - // Determining visible items boundaries - if (NULL == mFirstVisibleItem) - { - mFirstVisibleItem = *item_iter; - } - - if (*item_iter == mFirstVisibleItem) - { - height_before_first_visible_item = height - (*item_iter)->getNominalHeight(); - first_visible_item_iter = item_iter; - scrollable_items_cnt = 0; - } - - if (-1 != height_before_first_visible_item && 0 == visible_items_height && - (++scrollable_items_cnt > mMaxScrollableItems || - height - height_before_first_visible_item > max_height - spillover_item_height * 2 )) - { - first_hidden_item_iter = item_iter; - visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight(); - scrollable_items_cnt--; - } - } - } - } - - if (mPreferredWidth < U32_MAX) - width = llmin(mPreferredWidth, max_width); - - if (mScrollable) - { - S32 max_items_height = max_height - spillover_item_height * 2; - - if (visible_items_height == 0) - visible_items_height = height - height_before_first_visible_item; - - // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit - if (visible_items_height < max_items_height && scrollable_items_cnt < mMaxScrollableItems) - { - item_list_t::iterator tmp_iter(first_visible_item_iter); - while (visible_items_height < max_items_height && - scrollable_items_cnt < mMaxScrollableItems && - first_visible_item_iter != mItems.begin()) - { - if ((*first_visible_item_iter)->getVisible()) - { - // It keeps visible item, after first_visible_item_iter - tmp_iter = first_visible_item_iter; - } - - first_visible_item_iter--; - - if ((*first_visible_item_iter)->getVisible()) - { - visible_items_height += (*first_visible_item_iter)->getNominalHeight(); - height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight(); - scrollable_items_cnt++; - } - } - - // Roll back one item, that doesn't fit - if (visible_items_height > max_items_height) - { - visible_items_height -= (*first_visible_item_iter)->getNominalHeight(); - height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight(); - scrollable_items_cnt--; - first_visible_item_iter = tmp_iter; - } - if (!(*first_visible_item_iter)->getVisible()) - { - first_visible_item_iter = tmp_iter; - } - - mFirstVisibleItem = *first_visible_item_iter; - } - } - } - - S32 cur_height = (S32)llmin(max_height, height); - - if (mScrollable && - (height_before_first_visible_item > MENU_ITEM_PADDING || - height_before_first_visible_item + visible_items_height < (S32)height)) - { - // Reserving 2 extra slots for arrow items - cur_height = visible_items_height + spillover_item_height * 2; - } - - setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height)); - - S32 cur_width = 0; - S32 offset = 0; - if (mScrollable) - { - // No space for all items, creating arrow items - if (height_before_first_visible_item > MENU_ITEM_PADDING || - height_before_first_visible_item + visible_items_height < (S32)height) - { - if (NULL == mArrowUpItem) - { - LLMenuScrollItem::Params item_params; - item_params.name(ARROW_UP); - item_params.arrow_type(LLMenuScrollItem::ARROW_UP); - item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP)); - - mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); - LLUICtrl::addChild(mArrowUpItem); - - } - if (NULL == mArrowDownItem) - { - LLMenuScrollItem::Params item_params; - item_params.name(ARROW_DOWN); - item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); - item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN)); - - mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); - LLUICtrl::addChild(mArrowDownItem); - } - - LLRect rect; - mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight())); - mArrowUpItem->setVisible(TRUE); - mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING); - mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight()); - mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight())); - mArrowDownItem->setVisible(TRUE); - mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height); - mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight()); - - cur_height -= mArrowUpItem->getNominalHeight(); - - offset = menu_region_rect.mRight; // This moves items behind visible area - } - else - { - if (NULL != mArrowUpItem) - { - mArrowUpItem->setVisible(FALSE); - } - if (NULL != mArrowDownItem) - { - mArrowDownItem->setVisible(FALSE); - } - } - - } - - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if ((*item_iter)->getVisible()) - { - if (mScrollable) - { - if (item_iter == first_visible_item_iter) - { - offset = 0; - } - else if (item_iter == first_hidden_item_iter) - { - offset = menu_region_rect.mRight; // This moves items behind visible area - } - } - - // setup item rect to hold label - LLRect rect; - if (mHorizontalLayout) - { - rect.setLeftTopAndSize( cur_width, height, (*item_iter)->getNominalWidth(), height); - cur_width += (*item_iter)->getNominalWidth(); - } - else - { - rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight()); - if (offset == 0) - { - cur_height -= (*item_iter)->getNominalHeight(); - } - } - (*item_iter)->setRect( rect ); - } - } + // calculate the height & width, and set our rect based on that + // information. + const LLRect& initial_rect = getRect(); + + U32 width = 0, height = MENU_ITEM_PADDING; + + cleanupSpilloverBranch(); + + if( mItems.size() ) + { + const LLRect menu_region_rect = LLMenuGL::sMenuContainer ? LLMenuGL::sMenuContainer->getMenuRect() : LLRect(0, S32_MAX, S32_MAX, 0); + + // torn off menus are not constrained to the size of the screen + U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth(); + U32 max_height = getTornOff() ? U32_MAX: menu_region_rect.getHeight(); + + // *FIX: create the item first and then ask for its dimensions? + S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate + S32 spillover_item_height = LLFontGL::getFontSansSerif()->getLineHeight() + MENU_ITEM_PADDING; + + // Scrolling support + item_list_t::iterator first_visible_item_iter; + item_list_t::iterator first_hidden_item_iter = mItems.end(); + S32 height_before_first_visible_item = -1; + S32 visible_items_height = 0; + U32 scrollable_items_cnt = 0; + + if (mHorizontalLayout) + { + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + // do first so LLMenuGLItemCall can call on_visible to determine if visible + (*item_iter)->buildDrawLabel(); + + if ((*item_iter)->getVisible()) + { + if (!getTornOff() + && *item_iter != mSpilloverBranch + && width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width) + { + // no room for any more items + createSpilloverBranch(); + + std::vector<LLMenuItemGL*> items_to_remove; + std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); + std::vector<LLMenuItemGL*>::iterator spillover_iter; + for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) + { + LLMenuItemGL* itemp = (*spillover_iter); + removeChild(itemp); + mSpilloverMenu->addChild(itemp); + } + + addChild(mSpilloverBranch); + + height = llmax(height, mSpilloverBranch->getNominalHeight()); + width += mSpilloverBranch->getNominalWidth(); + + break; + } + else + { + // track our rect + height = llmax(height, (*item_iter)->getNominalHeight()); + width += (*item_iter)->getNominalWidth(); + } + } + } + } + else + { + for (LLMenuItemGL* itemp : mItems) + { + // do first so LLMenuGLItemCall can call on_visible to determine if visible + itemp->buildDrawLabel(); + } + item_list_t::iterator item_iter; + + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if ((*item_iter)->getVisible()) + { + if (!getTornOff() + && !mScrollable + && *item_iter != mSpilloverBranch + && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) + { + // don't show only one item + int visible_items = 0; + item_list_t::iterator count_iter; + for (count_iter = item_iter; count_iter != mItems.end(); ++count_iter) + { + if((*count_iter)->getVisible()) + visible_items++; + } + if (visible_items>1) + { + // no room for any more items + createSpilloverBranch(); + + std::vector<LLMenuItemGL*> items_to_remove; + std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove)); + std::vector<LLMenuItemGL*>::iterator spillover_iter; + for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter) + { + LLMenuItemGL* itemp = (*spillover_iter); + removeChild(itemp); + mSpilloverMenu->addChild(itemp); + } + + + addChild(mSpilloverBranch); + + height += mSpilloverBranch->getNominalHeight(); + width = llmax( width, mSpilloverBranch->getNominalWidth() ); + + break; + } + } + + // track our rect + height += (*item_iter)->getNominalHeight(); + width = llmax( width, (*item_iter)->getNominalWidth() ); + + if (mScrollable) + { + // Determining visible items boundaries + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *item_iter; + } + + if (*item_iter == mFirstVisibleItem) + { + height_before_first_visible_item = height - (*item_iter)->getNominalHeight(); + first_visible_item_iter = item_iter; + scrollable_items_cnt = 0; + } + + if (-1 != height_before_first_visible_item && 0 == visible_items_height && + (++scrollable_items_cnt > mMaxScrollableItems || + height - height_before_first_visible_item > max_height - spillover_item_height * 2 )) + { + first_hidden_item_iter = item_iter; + visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight(); + scrollable_items_cnt--; + } + } + } + } + + if (mPreferredWidth < U32_MAX) + width = llmin(mPreferredWidth, max_width); + + if (mScrollable) + { + S32 max_items_height = max_height - spillover_item_height * 2; + + if (visible_items_height == 0) + visible_items_height = height - height_before_first_visible_item; + + // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit + if (visible_items_height < max_items_height && scrollable_items_cnt < mMaxScrollableItems) + { + item_list_t::iterator tmp_iter(first_visible_item_iter); + while (visible_items_height < max_items_height && + scrollable_items_cnt < mMaxScrollableItems && + first_visible_item_iter != mItems.begin()) + { + if ((*first_visible_item_iter)->getVisible()) + { + // It keeps visible item, after first_visible_item_iter + tmp_iter = first_visible_item_iter; + } + + first_visible_item_iter--; + + if ((*first_visible_item_iter)->getVisible()) + { + visible_items_height += (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt++; + } + } + + // Roll back one item, that doesn't fit + if (visible_items_height > max_items_height) + { + visible_items_height -= (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt--; + first_visible_item_iter = tmp_iter; + } + if (!(*first_visible_item_iter)->getVisible()) + { + first_visible_item_iter = tmp_iter; + } + + mFirstVisibleItem = *first_visible_item_iter; + } + } + } + + S32 cur_height = (S32)llmin(max_height, height); + + if (mScrollable && + (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height)) + { + // Reserving 2 extra slots for arrow items + cur_height = visible_items_height + spillover_item_height * 2; + } + + setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height)); + + S32 cur_width = 0; + S32 offset = 0; + if (mScrollable) + { + // No space for all items, creating arrow items + if (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height) + { + if (NULL == mArrowUpItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_UP); + item_params.arrow_type(LLMenuScrollItem::ARROW_UP); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP)); + + mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); + LLUICtrl::addChild(mArrowUpItem); + + } + if (NULL == mArrowDownItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_DOWN); + item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN)); + + mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); + LLUICtrl::addChild(mArrowDownItem); + } + + LLRect rect; + mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight())); + mArrowUpItem->setVisible(TRUE); + mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING); + mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight()); + mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight())); + mArrowDownItem->setVisible(TRUE); + mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height); + mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight()); + + cur_height -= mArrowUpItem->getNominalHeight(); + + offset = menu_region_rect.mRight; // This moves items behind visible area + } + else + { + if (NULL != mArrowUpItem) + { + mArrowUpItem->setVisible(FALSE); + } + if (NULL != mArrowDownItem) + { + mArrowDownItem->setVisible(FALSE); + } + } + + } + + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if ((*item_iter)->getVisible()) + { + if (mScrollable) + { + if (item_iter == first_visible_item_iter) + { + offset = 0; + } + else if (item_iter == first_hidden_item_iter) + { + offset = menu_region_rect.mRight; // This moves items behind visible area + } + } + + // setup item rect to hold label + LLRect rect; + if (mHorizontalLayout) + { + rect.setLeftTopAndSize( cur_width, height, (*item_iter)->getNominalWidth(), height); + cur_width += (*item_iter)->getNominalWidth(); + } + else + { + rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight()); + if (offset == 0) + { + cur_height -= (*item_iter)->getNominalHeight(); + } + } + (*item_iter)->setRect( rect ); + } + } if (getTornOff()) @@ -2408,376 +2408,376 @@ void LLMenuGL::arrange( void ) torn_off_menu->updateSize(); } } - } - if (mKeepFixedSize) - { - reshape(initial_rect.getWidth(), initial_rect.getHeight()); - } + } + if (mKeepFixedSize) + { + reshape(initial_rect.getWidth(), initial_rect.getHeight()); + } } void LLMenuGL::arrangeAndClear( void ) { - if (mNeedsArrange) - { - arrange(); - mNeedsArrange = FALSE; - } + if (mNeedsArrange) + { + arrange(); + mNeedsArrange = FALSE; + } } void LLMenuGL::createSpilloverBranch() { - if (!mSpilloverBranch) - { - // should be NULL but delete anyway - delete mSpilloverMenu; - // technically, you can't tear off spillover menus, but we're passing the handle - // along just to be safe - LLMenuGL::Params p; - std::string label = LLTrans::getString("More"); - p.name("More"); - p.label(label); - p.bg_color(mBackgroundColor); - p.bg_visible(true); - p.can_tear_off(false); - mSpilloverMenu = new LLMenuGL(p); - mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); - - LLMenuItemBranchGL::Params branch_params; - branch_params.name = "More"; - branch_params.label = label; - branch_params.branch = mSpilloverMenu; - branch_params.font.style = "italic"; - branch_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); - branch_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); - branch_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); - - mSpilloverBranch = LLUICtrlFactory::create<LLMenuItemBranchGL>(branch_params); - } + if (!mSpilloverBranch) + { + // should be NULL but delete anyway + delete mSpilloverMenu; + // technically, you can't tear off spillover menus, but we're passing the handle + // along just to be safe + LLMenuGL::Params p; + std::string label = LLTrans::getString("More"); + p.name("More"); + p.label(label); + p.bg_color(mBackgroundColor); + p.bg_visible(true); + p.can_tear_off(false); + mSpilloverMenu = new LLMenuGL(p); + mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); + + LLMenuItemBranchGL::Params branch_params; + branch_params.name = "More"; + branch_params.label = label; + branch_params.branch = mSpilloverMenu; + branch_params.font.style = "italic"; + branch_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + branch_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + branch_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); + + mSpilloverBranch = LLUICtrlFactory::create<LLMenuItemBranchGL>(branch_params); + } } void LLMenuGL::cleanupSpilloverBranch() { - if (mSpilloverBranch && mSpilloverBranch->getParent() == this) - { - // head-recursion to propagate items back up to root menu - mSpilloverMenu->cleanupSpilloverBranch(); - - // pop off spillover items - while (mSpilloverMenu->getItemCount()) - { - LLMenuItemGL* itemp = mSpilloverMenu->getItem(0); - mSpilloverMenu->removeChild(itemp); - // put them at the end of our own list - addChild(itemp); - } - - // Delete the branch, and since the branch will delete the menu, - // set the menu* to null. - delete mSpilloverBranch; - mSpilloverBranch = NULL; - mSpilloverMenu = NULL; - } + if (mSpilloverBranch && mSpilloverBranch->getParent() == this) + { + // head-recursion to propagate items back up to root menu + mSpilloverMenu->cleanupSpilloverBranch(); + + // pop off spillover items + while (mSpilloverMenu->getItemCount()) + { + LLMenuItemGL* itemp = mSpilloverMenu->getItem(0); + mSpilloverMenu->removeChild(itemp); + // put them at the end of our own list + addChild(itemp); + } + + // Delete the branch, and since the branch will delete the menu, + // set the menu* to null. + delete mSpilloverBranch; + mSpilloverBranch = NULL; + mSpilloverMenu = NULL; + } } void LLMenuGL::createJumpKeys() { - if (!mCreateJumpKeys) return; - mCreateJumpKeys = FALSE; - - mJumpKeys.clear(); - - std::set<std::string> unique_words; - std::set<std::string> shared_words; - - item_list_t::iterator item_it; - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(" "); - - for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) - { - std::string uppercase_label = (*item_it)->getLabel(); - LLStringUtil::toUpper(uppercase_label); - - tokenizer tokens(uppercase_label, sep); - tokenizer::iterator token_iter; - for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - if (unique_words.find(*token_iter) != unique_words.end()) - { - // this word exists in more than one menu instance - shared_words.insert(*token_iter); - } - else - { - // we have a new word, keep track of it - unique_words.insert(*token_iter); - } - } - } - - // pre-assign specified jump keys - for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) - { - KEY jump_key = (*item_it)->getJumpKey(); - if(jump_key != KEY_NONE) - { - if (mJumpKeys.find(jump_key) == mJumpKeys.end()) - { - mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it))); - } - else - { - // this key is already spoken for, - // so we need to reassign it below - (*item_it)->setJumpKey(KEY_NONE); - } - } - } - - for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) - { - // skip over items that already have assigned jump keys - if ((*item_it)->getJumpKey() != KEY_NONE) - { - continue; - } - std::string uppercase_label = (*item_it)->getLabel(); - LLStringUtil::toUpper(uppercase_label); - - tokenizer tokens(uppercase_label, sep); - tokenizer::iterator token_iter; - - BOOL found_key = FALSE; - for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - std::string uppercase_word = *token_iter; - - // this word is not shared with other menu entries... - if (shared_words.find(*token_iter) == shared_words.end()) - { - S32 i; - for(i = 0; i < (S32)uppercase_word.size(); i++) - { - char jump_key = uppercase_word[i]; - - if (LLStringOps::isDigit(jump_key) || (LLStringOps::isUpper(jump_key) && - mJumpKeys.find(jump_key) == mJumpKeys.end())) - { - mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it))); - (*item_it)->setJumpKey(jump_key); - found_key = TRUE; - break; - } - } - } - if (found_key) - { - break; - } - } - } + if (!mCreateJumpKeys) return; + mCreateJumpKeys = FALSE; + + mJumpKeys.clear(); + + std::set<std::string> unique_words; + std::set<std::string> shared_words; + + item_list_t::iterator item_it; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep(" "); + + for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) + { + std::string uppercase_label = (*item_it)->getLabel(); + LLStringUtil::toUpper(uppercase_label); + + tokenizer tokens(uppercase_label, sep); + tokenizer::iterator token_iter; + for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + if (unique_words.find(*token_iter) != unique_words.end()) + { + // this word exists in more than one menu instance + shared_words.insert(*token_iter); + } + else + { + // we have a new word, keep track of it + unique_words.insert(*token_iter); + } + } + } + + // pre-assign specified jump keys + for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) + { + KEY jump_key = (*item_it)->getJumpKey(); + if(jump_key != KEY_NONE) + { + if (mJumpKeys.find(jump_key) == mJumpKeys.end()) + { + mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it))); + } + else + { + // this key is already spoken for, + // so we need to reassign it below + (*item_it)->setJumpKey(KEY_NONE); + } + } + } + + for(item_it = mItems.begin(); item_it != mItems.end(); ++item_it) + { + // skip over items that already have assigned jump keys + if ((*item_it)->getJumpKey() != KEY_NONE) + { + continue; + } + std::string uppercase_label = (*item_it)->getLabel(); + LLStringUtil::toUpper(uppercase_label); + + tokenizer tokens(uppercase_label, sep); + tokenizer::iterator token_iter; + + BOOL found_key = FALSE; + for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + std::string uppercase_word = *token_iter; + + // this word is not shared with other menu entries... + if (shared_words.find(*token_iter) == shared_words.end()) + { + S32 i; + for(i = 0; i < (S32)uppercase_word.size(); i++) + { + char jump_key = uppercase_word[i]; + + if (LLStringOps::isDigit(jump_key) || (LLStringOps::isUpper(jump_key) && + mJumpKeys.find(jump_key) == mJumpKeys.end())) + { + mJumpKeys.insert(std::pair<KEY, LLMenuItemGL*>(jump_key, (*item_it))); + (*item_it)->setJumpKey(jump_key); + found_key = TRUE; + break; + } + } + } + if (found_key) + { + break; + } + } + } } // remove all items on the menu void LLMenuGL::empty( void ) { - cleanupSpilloverBranch(); + cleanupSpilloverBranch(); - mItems.clear(); - mFirstVisibleItem = NULL; - mArrowUpItem = NULL; - mArrowDownItem = NULL; + mItems.clear(); + mFirstVisibleItem = NULL; + mArrowUpItem = NULL; + mArrowDownItem = NULL; - deleteAllChildren(); + deleteAllChildren(); } // erase group of items from menu void LLMenuGL::erase( S32 begin, S32 end, bool arrange/* = true*/) { - S32 items = mItems.size(); + S32 items = mItems.size(); - if ( items == 0 || begin >= end || begin < 0 || end > items ) - { - return; - } + if ( items == 0 || begin >= end || begin < 0 || end > items ) + { + return; + } - item_list_t::iterator start_position = mItems.begin(); - std::advance(start_position, begin); + item_list_t::iterator start_position = mItems.begin(); + std::advance(start_position, begin); - item_list_t::iterator end_position = mItems.begin(); - std::advance(end_position, end); + item_list_t::iterator end_position = mItems.begin(); + std::advance(end_position, end); - for (item_list_t::iterator position_iter = start_position; position_iter != end_position; position_iter++) - { - LLUICtrl::removeChild(*position_iter); - } + for (item_list_t::iterator position_iter = start_position; position_iter != end_position; position_iter++) + { + LLUICtrl::removeChild(*position_iter); + } - mItems.erase(start_position, end_position); + mItems.erase(start_position, end_position); - if (arrange) - { - needsArrange(); - } + if (arrange) + { + needsArrange(); + } } // add new item at position void LLMenuGL::insert( S32 position, LLView * ctrl, bool arrange /*= true*/ ) { - LLMenuItemGL * item = dynamic_cast<LLMenuItemGL *>(ctrl); + LLMenuItemGL * item = dynamic_cast<LLMenuItemGL *>(ctrl); - if (NULL == item || position < 0 || position >= mItems.size()) - { - return; - } + if (NULL == item || position < 0 || position >= mItems.size()) + { + return; + } - item_list_t::iterator position_iter = mItems.begin(); - std::advance(position_iter, position); - mItems.insert(position_iter, item); - LLUICtrl::addChild(item); + item_list_t::iterator position_iter = mItems.begin(); + std::advance(position_iter, position); + mItems.insert(position_iter, item); + LLUICtrl::addChild(item); - if (arrange) - { - needsArrange(); - } + if (arrange) + { + needsArrange(); + } } // Adjust rectangle of the menu void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom) { - setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom)); - needsArrange(); + setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom)); + needsArrange(); } BOOL LLMenuGL::handleJumpKey(KEY key) { - // must perform case-insensitive comparison, so just switch to uppercase input key - key = toupper(key); - navigation_key_map_t::iterator found_it = mJumpKeys.find(key); - if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); + // must perform case-insensitive comparison, so just switch to uppercase input key + key = toupper(key); + navigation_key_map_t::iterator found_it = mJumpKeys.find(key); + if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); - // force highlight to close old menus and open and sub-menus - found_it->second->setHighlight(TRUE); - found_it->second->onCommit(); + // force highlight to close old menus and open and sub-menus + found_it->second->setHighlight(TRUE); + found_it->second->onCommit(); - } - // if we are navigating the menus, we need to eat the keystroke - // so rest of UI doesn't handle it - return TRUE; + } + // if we are navigating the menus, we need to eat the keystroke + // so rest of UI doesn't handle it + return TRUE; } // Add the menu item to this menu. BOOL LLMenuGL::append( LLMenuItemGL* item ) { - if (!item) return FALSE; - mItems.push_back( item ); - LLUICtrl::addChild(item); - needsArrange(); - return TRUE; + if (!item) return FALSE; + mItems.push_back( item ); + LLUICtrl::addChild(item); + needsArrange(); + return TRUE; } // add a separator to this menu BOOL LLMenuGL::addSeparator() { - LLMenuItemSeparatorGL::Params p; - LLMenuItemGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(p); - return addChild(separator); + LLMenuItemSeparatorGL::Params p; + LLMenuItemGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(p); + return addChild(separator); } // add a menu - this will create a cascading menu BOOL LLMenuGL::appendMenu( LLMenuGL* menu ) { - if( menu == this ) - { - LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " - << "a logic error." << LL_ENDL; - } - BOOL success = TRUE; + if( menu == this ) + { + LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " + << "a logic error." << LL_ENDL; + } + BOOL success = TRUE; - LLMenuItemBranchGL::Params p; - p.name = menu->getName(); - p.label = menu->getLabel(); - p.branch = menu; - p.jump_key = menu->getJumpKey(); - p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); - p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); - p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); - p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + LLMenuItemBranchGL::Params p; + p.name = menu->getName(); + p.label = menu->getLabel(); + p.branch = menu; + p.jump_key = menu->getJumpKey(); + p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); + p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); + p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); - LLMenuItemBranchGL* branch = LLUICtrlFactory::create<LLMenuItemBranchGL>(p); - success &= append( branch ); + LLMenuItemBranchGL* branch = LLUICtrlFactory::create<LLMenuItemBranchGL>(p); + success &= append( branch ); - // Inherit colors - menu->setBackgroundColor( mBackgroundColor ); - menu->updateParent(LLMenuGL::sMenuContainer); - return success; + // Inherit colors + menu->setBackgroundColor( mBackgroundColor ); + menu->updateParent(LLMenuGL::sMenuContainer); + return success; } // add a context menu branch BOOL LLMenuGL::appendContextSubMenu(LLMenuGL *menu) { - if (menu == this) - { - LL_ERRS() << "Can't attach a context menu to itself" << LL_ENDL; - } + if (menu == this) + { + LL_ERRS() << "Can't attach a context menu to itself" << LL_ENDL; + } - LLContextMenuBranch *item; - LLContextMenuBranch::Params p; - p.name = menu->getName(); - p.label = menu->getLabel(); - p.branch = (LLContextMenu *)menu; - p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); - p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); - p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); - p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + LLContextMenuBranch *item; + LLContextMenuBranch::Params p; + p.name = menu->getName(); + p.label = menu->getLabel(); + p.branch = (LLContextMenu *)menu; + p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); + p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); + p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); - item = LLUICtrlFactory::create<LLContextMenuBranch>(p); - LLMenuGL::sMenuContainer->addChild(item->getBranch()); + item = LLUICtrlFactory::create<LLContextMenuBranch>(p); + LLMenuGL::sMenuContainer->addChild(item->getBranch()); - return append( item ); + return append( item ); } void LLMenuGL::setEnabledSubMenus(BOOL enable) { - setEnabled(enable); - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - (*item_iter)->setEnabledSubMenus( enable ); - } + setEnabled(enable); + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + (*item_iter)->setEnabledSubMenus( enable ); + } } // setItemEnabled() - pass the label and the enable flag for a menu // item. TRUE will make sure it's enabled, FALSE will disable it. void LLMenuGL::setItemEnabled( const std::string& name, BOOL enable ) { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if( (*item_iter)->getName() == name ) - { - (*item_iter)->setEnabled( enable ); - (*item_iter)->setEnabledSubMenus( enable ); - break; - } - } + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if( (*item_iter)->getName() == name ) + { + (*item_iter)->setEnabled( enable ); + (*item_iter)->setEnabledSubMenus( enable ); + break; + } + } } void LLMenuGL::setItemVisible( const std::string& name, BOOL visible ) { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if( (*item_iter)->getName() == name ) - { - (*item_iter)->setVisible( visible ); - needsArrange(); - break; - } - } + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if( (*item_iter)->getName() == name ) + { + (*item_iter)->setVisible( visible ); + needsArrange(); + break; + } + } } @@ -2791,46 +2791,46 @@ void LLMenuGL::setItemLabel(const std::string &name, const std::string &label) void LLMenuGL::setItemLastSelected(LLMenuItemGL* item) { - if (getVisible()) - { - LLMenuHolderGL::setActivatedItem(item); - } + if (getVisible()) + { + LLMenuHolderGL::setActivatedItem(item); + } - // update enabled and checkmark status - item->buildDrawLabel(); + // update enabled and checkmark status + item->buildDrawLabel(); } -// Set whether drop shadowed +// Set whether drop shadowed void LLMenuGL::setDropShadowed( const BOOL shadowed ) { - mDropShadowed = shadowed; + mDropShadowed = shadowed; } void LLMenuGL::setTornOff(BOOL torn_off) -{ - mTornOff = torn_off; +{ + mTornOff = torn_off; } U32 LLMenuGL::getItemCount() { - return mItems.size(); + return mItems.size(); } LLMenuItemGL* LLMenuGL::getItem(S32 number) { - if (number >= 0 && number < (S32)mItems.size()) - { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if (number == 0) - { - return (*item_iter); - } - number--; - } - } - return NULL; + if (number >= 0 && number < (S32)mItems.size()) + { + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if (number == 0) + { + return (*item_iter); + } + number--; + } + } + return NULL; } LLMenuItemGL* LLMenuGL::getItem(std::string name) @@ -2848,474 +2848,473 @@ LLMenuItemGL* LLMenuGL::getItem(std::string name) LLMenuItemGL* LLMenuGL::getHighlightedItem() { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - if ((*item_iter)->getHighlight()) - { - return (*item_iter); - } - } - return NULL; + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + if ((*item_iter)->getHighlight()) + { + return (*item_iter); + } + } + return NULL; } LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled) { - if (mItems.empty()) return NULL; - // highlighting first item on a torn off menu is the - // same as giving focus to it - if (!cur_item && getTornOff()) - { - LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); - if (parent) - { - parent->setFocus(TRUE); - } - } - - // Current item position in the items list - item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item); - - item_list_t::iterator next_item_iter; - if (cur_item_iter == mItems.end()) - { - next_item_iter = mItems.begin(); - } - else - { - next_item_iter = cur_item_iter; - next_item_iter++; - - // First visible item position in the items list - item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); - - if (next_item_iter == mItems.end()) - { - next_item_iter = mItems.begin(); - - // If current item is the last in the list, the menu is scrolled to the beginning - // and the first item is highlighted. - if (mScrollable && !scrollItems(SD_BEGIN)) - { - return NULL; - } - } - // If current item is the last visible, the menu is scrolled one item down - // and the next item is highlighted. - else if (mScrollable && - (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems) - { - // Call highlightNextItem() recursively only if the menu was successfully scrolled down. - // If scroll timer hasn't expired yet the menu won't be scrolled and calling - // highlightNextItem() will result in an endless recursion. - if (scrollItems(SD_DOWN)) - { - return highlightNextItem(cur_item, skip_disabled); - } - else - { - return NULL; - } - } - } - - // when first highlighting a menu, skip over tear off menu item - if (mTearOffItem && !cur_item) - { - // we know the first item is the tear off menu item - cur_item_iter = mItems.begin(); - next_item_iter++; - if (next_item_iter == mItems.end()) - { - next_item_iter = mItems.begin(); - } - } - - while(1) - { - // skip separators and disabled/invisible items - if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && !dynamic_cast<LLMenuItemSeparatorGL*>(*next_item_iter)) - { - if (cur_item) - { - cur_item->setHighlight(FALSE); - } - (*next_item_iter)->setHighlight(TRUE); - return (*next_item_iter); - } - - - if (!skip_disabled || next_item_iter == cur_item_iter) - { - break; - } - - next_item_iter++; - if (next_item_iter == mItems.end()) - { - if (cur_item_iter == mItems.end()) - { - break; - } - next_item_iter = mItems.begin(); - } - } - - return NULL; + if (mItems.empty()) return NULL; + // highlighting first item on a torn off menu is the + // same as giving focus to it + if (!cur_item && getTornOff()) + { + LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); + if (parent) + { + parent->setFocus(TRUE); + } + } + + // Current item position in the items list + item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item); + + item_list_t::iterator next_item_iter; + if (cur_item_iter == mItems.end()) + { + next_item_iter = mItems.begin(); + } + else + { + next_item_iter = cur_item_iter; + next_item_iter++; + + // First visible item position in the items list + item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); + + if (next_item_iter == mItems.end()) + { + next_item_iter = mItems.begin(); + + // If current item is the last in the list, the menu is scrolled to the beginning + // and the first item is highlighted. + if (mScrollable && !scrollItems(SD_BEGIN)) + { + return NULL; + } + } + // If current item is the last visible, the menu is scrolled one item down + // and the next item is highlighted. + else if (mScrollable && + (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems) + { + // Call highlightNextItem() recursively only if the menu was successfully scrolled down. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_DOWN)) + { + return highlightNextItem(cur_item, skip_disabled); + } + else + { + return NULL; + } + } + } + + // when first highlighting a menu, skip over tear off menu item + if (mTearOffItem && !cur_item) + { + // we know the first item is the tear off menu item + cur_item_iter = mItems.begin(); + next_item_iter++; + if (next_item_iter == mItems.end()) + { + next_item_iter = mItems.begin(); + } + } + + while(1) + { + // skip separators and disabled/invisible items + if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && !dynamic_cast<LLMenuItemSeparatorGL*>(*next_item_iter)) + { + if (cur_item) + { + cur_item->setHighlight(FALSE); + } + (*next_item_iter)->setHighlight(TRUE); + return (*next_item_iter); + } + + + if (!skip_disabled || next_item_iter == cur_item_iter) + { + break; + } + + next_item_iter++; + if (next_item_iter == mItems.end()) + { + if (cur_item_iter == mItems.end()) + { + break; + } + next_item_iter = mItems.begin(); + } + } + + return NULL; } LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled) { - if (mItems.empty()) return NULL; - - // highlighting first item on a torn off menu is the - // same as giving focus to it - if (!cur_item && getTornOff()) - { - LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); - if (parent) - { - parent->setFocus(TRUE); - } - } - - // Current item reverse position from the end of the list - item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item); - - item_list_t::reverse_iterator prev_item_iter; - if (cur_item_iter == mItems.rend()) - { - prev_item_iter = mItems.rbegin(); - } - else - { - prev_item_iter = cur_item_iter; - prev_item_iter++; - - // First visible item reverse position in the items list - item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); - - if (prev_item_iter == mItems.rend()) - { - prev_item_iter = mItems.rbegin(); - - // If current item is the first in the list, the menu is scrolled to the end - // and the last item is highlighted. - if (mScrollable && !scrollItems(SD_END)) - { - return NULL; - } - } - // If current item is the first visible, the menu is scrolled one item up - // and the previous item is highlighted. - else if (mScrollable && - std::distance(first_visible_item_iter, cur_item_iter) <= 0) - { - // Call highlightNextItem() only if the menu was successfully scrolled up. - // If scroll timer hasn't expired yet the menu won't be scrolled and calling - // highlightNextItem() will result in an endless recursion. - if (scrollItems(SD_UP)) - { - return highlightPrevItem(cur_item, skip_disabled); - } - else - { - return NULL; - } - } - } - - while(1) - { - // skip separators and disabled/invisible items - if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getVisible() && (*prev_item_iter)->getName() != SEPARATOR_NAME) - { - (*prev_item_iter)->setHighlight(TRUE); - return (*prev_item_iter); - } - - if (!skip_disabled || prev_item_iter == cur_item_iter) - { - break; - } - - prev_item_iter++; - if (prev_item_iter == mItems.rend()) - { - if (cur_item_iter == mItems.rend()) - { - break; - } - - prev_item_iter = mItems.rbegin(); - } - } - - return NULL; + if (mItems.empty()) return NULL; + + // highlighting first item on a torn off menu is the + // same as giving focus to it + if (!cur_item && getTornOff()) + { + LLFloater * parent = dynamic_cast<LLFloater *>(getParent()); + if (parent) + { + parent->setFocus(TRUE); + } + } + + // Current item reverse position from the end of the list + item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item); + + item_list_t::reverse_iterator prev_item_iter; + if (cur_item_iter == mItems.rend()) + { + prev_item_iter = mItems.rbegin(); + } + else + { + prev_item_iter = cur_item_iter; + prev_item_iter++; + + // First visible item reverse position in the items list + item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); + + if (prev_item_iter == mItems.rend()) + { + prev_item_iter = mItems.rbegin(); + + // If current item is the first in the list, the menu is scrolled to the end + // and the last item is highlighted. + if (mScrollable && !scrollItems(SD_END)) + { + return NULL; + } + } + // If current item is the first visible, the menu is scrolled one item up + // and the previous item is highlighted. + else if (mScrollable && + std::distance(first_visible_item_iter, cur_item_iter) <= 0) + { + // Call highlightNextItem() only if the menu was successfully scrolled up. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_UP)) + { + return highlightPrevItem(cur_item, skip_disabled); + } + else + { + return NULL; + } + } + } + + while(1) + { + // skip separators and disabled/invisible items + if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getVisible() && (*prev_item_iter)->getName() != SEPARATOR_NAME) + { + (*prev_item_iter)->setHighlight(TRUE); + return (*prev_item_iter); + } + + if (!skip_disabled || prev_item_iter == cur_item_iter) + { + break; + } + + prev_item_iter++; + if (prev_item_iter == mItems.rend()) + { + if (cur_item_iter == mItems.rend()) + { + break; + } + + prev_item_iter = mItems.rbegin(); + } + } + + return NULL; } void LLMenuGL::buildDrawLabels() { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - (*item_iter)->buildDrawLabel(); - } + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + (*item_iter)->buildDrawLabel(); + } } void LLMenuGL::updateParent(LLView* parentp) { - if (getParent()) - { - getParent()->removeChild(this); - } - if (parentp) - { - parentp->addChild(this); - } - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - (*item_iter)->updateBranchParent(parentp); - } + if (getParent()) + { + getParent()->removeChild(this); + } + if (parentp) + { + parentp->addChild(this); + } + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + (*item_iter)->updateBranchParent(parentp); + } } bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const { - if (key == KEY_NONE) - { - return false; - } - // Note: checking this way because mAccelerators seems to be broken - // mAccelerators probably needs to be cleaned up or fixed - // It was used for dupplicate accelerator avoidance. - item_list_t::const_iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - LLMenuItemGL* itemp = *item_iter; - if (itemp->hasAccelerator(key, mask)) - { - return true; - } - } - return false; + if (key == KEY_NONE) + { + return false; + } + // Note: checking this way because mAccelerators seems to be broken + // mAccelerators probably needs to be cleaned up or fixed + // It was used for dupplicate accelerator avoidance. + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL* itemp = *item_iter; + if (itemp->hasAccelerator(key, mask)) + { + return true; + } + } + return false; } BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask) { - // don't handle if not enabled - if(!getEnabled()) - { - return FALSE; - } + // don't handle if not enabled + if(!getEnabled()) + { + return FALSE; + } - // Pass down even if not visible - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - LLMenuItemGL* itemp = *item_iter; - if (itemp->handleAcceleratorKey(key, mask)) - { - return TRUE; - } - } + // Pass down even if not visible + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL* itemp = *item_iter; + if (itemp->handleAcceleratorKey(key, mask)) + { + return TRUE; + } + } - return FALSE; + return FALSE; } BOOL LLMenuGL::handleUnicodeCharHere( llwchar uni_char ) { - if (jumpKeysActive()) - { - return handleJumpKey((KEY)uni_char); - } - return FALSE; + if (jumpKeysActive()) + { + return handleJumpKey((KEY)uni_char); + } + return FALSE; } BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) { - // leave submenu in place if slope of mouse < MAX_MOUSE_SLOPE_SUB_MENU - BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; - S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; - S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; - LLVector2 mouse_dir((F32)mouse_delta_x, (F32)mouse_delta_y); - mouse_dir.normVec(); - LLVector2 mouse_avg_dir((F32)mMouseVelX, (F32)mMouseVelY); - mouse_avg_dir.normVec(); - F32 interp = 0.5f * (llclamp(mouse_dir * mouse_avg_dir, 0.f, 1.f)); - mMouseVelX = ll_round(lerp((F32)mouse_delta_x, (F32)mMouseVelX, interp)); - mMouseVelY = ll_round(lerp((F32)mouse_delta_y, (F32)mMouseVelY, interp)); - mLastMouseX = x; - mLastMouseY = y; - - // don't change menu focus unless mouse is moving or alt key is not held down - if ((llabs(mMouseVelX) > 0 || - llabs(mMouseVelY) > 0) && - (!mHasSelection || - //(mouse_delta_x == 0 && mouse_delta_y == 0) || - (mMouseVelX < 0) || - llabs((F32)mMouseVelY) / llabs((F32)mMouseVelX) > MAX_MOUSE_SLOPE_SUB_MENU)) - { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) - { - // moving mouse always highlights new item - if (mouse_delta_x != 0 || mouse_delta_y != 0) - { - ((LLMenuItemGL*)viewp)->setHighlight(FALSE); - } - } - } - - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - //RN: always call handleHover to track mGotHover status - // but only set highlight when mouse is moving - if( viewp->getVisible() && - //RN: allow disabled items to be highlighted to preserve "active" menus when - // moving mouse through them - //viewp->getEnabled() && - viewp->pointInView(local_x, local_y) && - viewp->handleHover(local_x, local_y, mask)) - { - // moving mouse always highlights new item - if (mouse_delta_x != 0 || mouse_delta_y != 0) - { - ((LLMenuItemGL*)viewp)->setHighlight(TRUE); - LLMenuGL::setKeyboardMode(FALSE); - } - mHasSelection = true; - } - } - } - getWindow()->setCursor(UI_CURSOR_ARROW); - - // *HACK Release the mouse capture - // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button - // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events - // until the user chooses one of the drop-down menu items. - - return TRUE; + // leave submenu in place if slope of mouse < MAX_MOUSE_SLOPE_SUB_MENU + BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; + S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; + S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; + LLVector2 mouse_dir((F32)mouse_delta_x, (F32)mouse_delta_y); + mouse_dir.normVec(); + LLVector2 mouse_avg_dir((F32)mMouseVelX, (F32)mMouseVelY); + mouse_avg_dir.normVec(); + F32 interp = 0.5f * (llclamp(mouse_dir * mouse_avg_dir, 0.f, 1.f)); + mMouseVelX = ll_round(lerp((F32)mouse_delta_x, (F32)mMouseVelX, interp)); + mMouseVelY = ll_round(lerp((F32)mouse_delta_y, (F32)mMouseVelY, interp)); + mLastMouseX = x; + mLastMouseY = y; + + // don't change menu focus unless mouse is moving or alt key is not held down + if ((llabs(mMouseVelX) > 0 || + llabs(mMouseVelY) > 0) && + (!mHasSelection || + //(mouse_delta_x == 0 && mouse_delta_y == 0) || + (mMouseVelX < 0) || + llabs((F32)mMouseVelY) / llabs((F32)mMouseVelX) > MAX_MOUSE_SLOPE_SUB_MENU)) + { + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) + { + // moving mouse always highlights new item + if (mouse_delta_x != 0 || mouse_delta_y != 0) + { + ((LLMenuItemGL*)viewp)->setHighlight(FALSE); + } + } + } + + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + //RN: always call handleHover to track mGotHover status + // but only set highlight when mouse is moving + if( viewp->getVisible() && + //RN: allow disabled items to be highlighted to preserve "active" menus when + // moving mouse through them + //viewp->getEnabled() && + viewp->pointInView(local_x, local_y) && + viewp->handleHover(local_x, local_y, mask)) + { + // moving mouse always highlights new item + if (mouse_delta_x != 0 || mouse_delta_y != 0) + { + ((LLMenuItemGL*)viewp)->setHighlight(TRUE); + LLMenuGL::setKeyboardMode(FALSE); + } + mHasSelection = true; + } + } + } + getWindow()->setCursor(UI_CURSOR_ARROW); + + // *HACK Release the mouse capture + // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button + // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events + // until the user chooses one of the drop-down menu items. + + return TRUE; } BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - if (!mScrollable) - return blockMouseEvent(x, y); + if (!mScrollable) + return blockMouseEvent(x, y); - if( clicks > 0 ) - { - while( clicks-- ) - scrollItems(SD_DOWN); - } - else - { - while( clicks++ ) - scrollItems(SD_UP); - } + if( clicks > 0 ) + { + while( clicks-- ) + scrollItems(SD_DOWN); + } + else + { + while( clicks++ ) + scrollItems(SD_UP); + } - return TRUE; + return TRUE; } void LLMenuGL::draw( void ) { - if (mNeedsArrange) - { - arrange(); - mNeedsArrange = FALSE; - } - if (mDropShadowed && !mTornOff) - { - static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0); - static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); - gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, drop_shadow_floater ); - } - - if( mBgVisible ) - { - gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor.get() ); - } - LLView::draw(); + if (mNeedsArrange) + { + arrange(); + mNeedsArrange = FALSE; + } + if (mDropShadowed && !mTornOff) + { + static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); + gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, + color_drop_shadow, DROP_SHADOW_FLOATER); + } + + if( mBgVisible ) + { + gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor.get() ); + } + LLView::draw(); } void LLMenuGL::drawBackground(LLMenuItemGL* itemp, F32 alpha) { - LLColor4 color = itemp->getHighlightBgColor() % alpha; - gGL.color4fv( color.mV ); - LLRect item_rect = itemp->getRect(); - gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0); + LLColor4 color = itemp->getHighlightBgColor() % alpha; + gGL.color4fv( color.mV ); + LLRect item_rect = itemp->getRect(); + gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0); } void LLMenuGL::setVisible(BOOL visible) { - if (visible != getVisible()) - { - if (!visible) - { - mFadeTimer.start(); - clearHoverItem(); - // reset last known mouse coordinates so - // we don't spoof a mouse move next time we're opened - mLastMouseX = 0; - mLastMouseY = 0; - } - else - { - mHasSelection = true; - mFadeTimer.stop(); - } - - LLView::setVisible(visible); - } + if (visible != getVisible()) + { + if (!visible) + { + mFadeTimer.start(); + clearHoverItem(); + // reset last known mouse coordinates so + // we don't spoof a mouse move next time we're opened + mLastMouseX = 0; + mLastMouseY = 0; + } + else + { + mHasSelection = true; + mFadeTimer.stop(); + } + + LLView::setVisible(visible); + } } LLMenuGL* LLMenuGL::findChildMenuByName(const std::string& name, BOOL recurse) const { - LLView* view = findChildView(name, recurse); - if (view) - { - LLMenuItemBranchGL* branch = dynamic_cast<LLMenuItemBranchGL*>(view); - if (branch) - { - return branch->getBranch(); - } - - LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); - if (menup) - { - return menup; - } - } - LL_WARNS() << "Child Menu " << name << " not found in menu " << getName() << LL_ENDL; - return NULL; + LLView* view = findChildView(name, recurse); + if (view) + { + LLMenuItemBranchGL* branch = dynamic_cast<LLMenuItemBranchGL*>(view); + if (branch) + { + return branch->getBranch(); + } + + LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view); + if (menup) + { + return menup; + } + } + LL_WARNS() << "Child Menu " << name << " not found in menu " << getName() << LL_ENDL; + return NULL; } BOOL LLMenuGL::clearHoverItem() { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLMenuItemGL* itemp = (LLMenuItemGL*)*child_it; - if (itemp->getHighlight()) - { - itemp->setHighlight(FALSE); - return TRUE; - } - } - return FALSE; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLMenuItemGL* itemp = (LLMenuItemGL*)*child_it; + if (itemp->getHighlight()) + { + itemp->setHighlight(FALSE); + return TRUE; + } + } + return FALSE; } void hide_top_view( LLView* view ) { - if( view ) view->setVisible( FALSE ); + if( view ) view->setVisible( FALSE ); } @@ -3324,85 +3323,85 @@ void hide_top_view( LLView* view ) // static void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x, S32 mouse_y) { - const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size - const S32 CURSOR_WIDTH = 12; - - if (menu->getChildList()->empty()) - { - return; - } - - menu->setVisible( TRUE ); - - if(!menu->getAlwaysShowMenu()) - { - //Do not show menu if all menu items are disabled - BOOL item_enabled = false; - for (LLView::child_list_t::const_iterator itor = menu->getChildList()->begin(); - itor != menu->getChildList()->end(); - ++itor) - { - LLView *menu_item = (*itor); - item_enabled = item_enabled || menu_item->getEnabled(); - } - - if(!item_enabled) - { - menu->setVisible( FALSE ); - return; - } - } - - // Resetting scrolling position - if (menu->isScrollable() && menu->isScrollPositionOnShowReset()) - { - menu->mFirstVisibleItem = NULL; - } - - // Fix menu rect if needed. - menu->needsArrange(); - menu->arrangeAndClear(); - - if ((mouse_x == 0) || (mouse_y == 0)) - - { - // Save click point for detecting cursor moves before mouse-up. - // Must be in local coords to compare with mouseUp events. - // If the mouse doesn't move, the menu will stay open ala the Mac. - // See also LLContextMenu::show() - - LLUI::getInstance()->getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y); - } - - - LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y); - - const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getRect(); - - const S32 HPAD = 2; - LLRect rect = menu->getRect(); - S32 left = x + HPAD; - S32 top = y; - spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent()); - rect.setLeftTopAndSize( left, top, - rect.getWidth(), rect.getHeight() ); - menu->setRect( rect ); - - - // Adjust context menu to fit onscreen - LLRect mouse_rect; - const S32 MOUSE_CURSOR_PADDING = 5; - mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, - mouse_y + MOUSE_CURSOR_PADDING, - CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, - CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); - menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect ); - if (menu->getRect().mTop > menu_region_rect.mTop) - { - // not enough space: align with top, ignore exclusion - menu->translateIntoRect( menu_region_rect ); - } - menu->getParent()->sendChildToFront(menu); + const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size + const S32 CURSOR_WIDTH = 12; + + if (menu->getChildList()->empty()) + { + return; + } + + menu->setVisible( TRUE ); + + if(!menu->getAlwaysShowMenu()) + { + //Do not show menu if all menu items are disabled + BOOL item_enabled = false; + for (LLView::child_list_t::const_iterator itor = menu->getChildList()->begin(); + itor != menu->getChildList()->end(); + ++itor) + { + LLView *menu_item = (*itor); + item_enabled = item_enabled || menu_item->getEnabled(); + } + + if(!item_enabled) + { + menu->setVisible( FALSE ); + return; + } + } + + // Resetting scrolling position + if (menu->isScrollable() && menu->isScrollPositionOnShowReset()) + { + menu->mFirstVisibleItem = NULL; + } + + // Fix menu rect if needed. + menu->needsArrange(); + menu->arrangeAndClear(); + + if ((mouse_x == 0) || (mouse_y == 0)) + + { + // Save click point for detecting cursor moves before mouse-up. + // Must be in local coords to compare with mouseUp events. + // If the mouse doesn't move, the menu will stay open ala the Mac. + // See also LLContextMenu::show() + + LLUI::getInstance()->getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y); + } + + + LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y); + + const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getRect(); + + const S32 HPAD = 2; + LLRect rect = menu->getRect(); + S32 left = x + HPAD; + S32 top = y; + spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent()); + rect.setLeftTopAndSize( left, top, + rect.getWidth(), rect.getHeight() ); + menu->setRect( rect ); + + + // Adjust context menu to fit onscreen + LLRect mouse_rect; + const S32 MOUSE_CURSOR_PADDING = 5; + mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, + mouse_y + MOUSE_CURSOR_PADDING, + CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, + CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); + menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect ); + if (menu->getRect().mTop > menu_region_rect.mTop) + { + // not enough space: align with top, ignore exclusion + menu->translateIntoRect( menu_region_rect ); + } + menu->getParent()->sendChildToFront(menu); } ///============================================================================ @@ -3412,320 +3411,320 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S3 static LLDefaultChildRegistry::Register<LLMenuBarGL> r2("menu_bar"); LLMenuBarGL::LLMenuBarGL( const Params& p ) -: LLMenuGL(p), - mAltKeyTrigger(FALSE) +: LLMenuGL(p), + mAltKeyTrigger(FALSE) {} // Default destructor LLMenuBarGL::~LLMenuBarGL() { - std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer()); - mAccelerators.clear(); + std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer()); + mAccelerators.clear(); } BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) { - if (getHighlightedItem() && mask == MASK_NONE) - { - // unmodified key accelerators are ignored when navigating menu - // (but are used as jump keys so will still work when appropriate menu is up) - return FALSE; - } - BOOL result = LLMenuGL::handleAcceleratorKey(key, mask); - if (result && mask & MASK_ALT) - { - // ALT key used to trigger hotkey, don't use as shortcut to open menu - mAltKeyTrigger = FALSE; - } - - if(!result - && (key == KEY_F10 && mask == MASK_CONTROL) - && !gKeyboard->getKeyRepeated(key) - && isInVisibleChain()) - { - if (getHighlightedItem()) - { - clearHoverItem(); - LLMenuGL::setKeyboardMode(FALSE); - } - else - { - // close menus originating from other menu bars when first opening menu via keyboard - LLMenuGL::sMenuContainer->hideMenus(); - highlightNextItem(NULL); - LLMenuGL::setKeyboardMode(TRUE); - } - return TRUE; - } - - if (result && !getHighlightedItem() && LLMenuGL::sMenuContainer->hasVisibleMenu()) - { - // close menus originating from other menu bars - LLMenuGL::sMenuContainer->hideMenus(); - } - - return result; + if (getHighlightedItem() && mask == MASK_NONE) + { + // unmodified key accelerators are ignored when navigating menu + // (but are used as jump keys so will still work when appropriate menu is up) + return FALSE; + } + BOOL result = LLMenuGL::handleAcceleratorKey(key, mask); + if (result && mask & MASK_ALT) + { + // ALT key used to trigger hotkey, don't use as shortcut to open menu + mAltKeyTrigger = FALSE; + } + + if(!result + && (key == KEY_F10 && mask == MASK_CONTROL) + && !gKeyboard->getKeyRepeated(key) + && isInVisibleChain()) + { + if (getHighlightedItem()) + { + clearHoverItem(); + LLMenuGL::setKeyboardMode(FALSE); + } + else + { + // close menus originating from other menu bars when first opening menu via keyboard + LLMenuGL::sMenuContainer->hideMenus(); + highlightNextItem(NULL); + LLMenuGL::setKeyboardMode(TRUE); + } + return TRUE; + } + + if (result && !getHighlightedItem() && LLMenuGL::sMenuContainer->hasVisibleMenu()) + { + // close menus originating from other menu bars + LLMenuGL::sMenuContainer->hideMenus(); + } + + return result; } BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask) { - static LLUICachedControl<bool> use_altkey_for_menus ("UseAltKeyForMenus", 0); - if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus) - { - mAltKeyTrigger = TRUE; - } - else // if any key other than ALT hit, clear out waiting for Alt key mode - { - mAltKeyTrigger = FALSE; - } - - if (key == KEY_ESCAPE && mask == MASK_NONE) - { - LLMenuGL::setKeyboardMode(FALSE); - // if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key - return LLMenuGL::sMenuContainer->hideMenus(); - } - - // before processing any other key, check to see if ALT key has triggered menu access - checkMenuTrigger(); - - return LLMenuGL::handleKeyHere(key, mask); + static LLUICachedControl<bool> use_altkey_for_menus ("UseAltKeyForMenus", 0); + if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus) + { + mAltKeyTrigger = TRUE; + } + else // if any key other than ALT hit, clear out waiting for Alt key mode + { + mAltKeyTrigger = FALSE; + } + + if (key == KEY_ESCAPE && mask == MASK_NONE) + { + LLMenuGL::setKeyboardMode(FALSE); + // if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key + return LLMenuGL::sMenuContainer->hideMenus(); + } + + // before processing any other key, check to see if ALT key has triggered menu access + checkMenuTrigger(); + + return LLMenuGL::handleKeyHere(key, mask); } BOOL LLMenuBarGL::handleJumpKey(KEY key) { - // perform case-insensitive comparison - key = toupper(key); - navigation_key_map_t::iterator found_it = mJumpKeys.find(key); - if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) - { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); + // perform case-insensitive comparison + key = toupper(key); + navigation_key_map_t::iterator found_it = mJumpKeys.find(key); + if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); - found_it->second->setHighlight(TRUE); - found_it->second->onCommit(); - } - return TRUE; + found_it->second->setHighlight(TRUE); + found_it->second->onCommit(); + } + return TRUE; } BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask) { - // clicks on menu bar closes existing menus from other contexts but leave - // own menu open so that we get toggle behavior - if (!getHighlightedItem() || !getHighlightedItem()->isActive()) - { - LLMenuGL::sMenuContainer->hideMenus(); - } + // clicks on menu bar closes existing menus from other contexts but leave + // own menu open so that we get toggle behavior + if (!getHighlightedItem() || !getHighlightedItem()->isActive()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } - return LLMenuGL::handleMouseDown(x, y, mask); + return LLMenuGL::handleMouseDown(x, y, mask); } BOOL LLMenuBarGL::handleDoubleClick(S32 x, S32 y, MASK mask) { - return LLMenuGL::handleMouseDown(x, y, mask); + return LLMenuGL::handleMouseDown(x, y, mask); } void LLMenuBarGL::draw() { - LLMenuItemGL* itemp = getHighlightedItem(); - // If we are in mouse-control mode and the mouse cursor is not hovering over - // the current highlighted menu item and it isn't open, then remove the - // highlight. This is done via a polling mechanism here, as we don't receive + LLMenuItemGL* itemp = getHighlightedItem(); + // If we are in mouse-control mode and the mouse cursor is not hovering over + // the current highlighted menu item and it isn't open, then remove the + // highlight. This is done via a polling mechanism here, as we don't receive // notifications when the mouse cursor moves off of us - if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode()) - { - clearHoverItem(); - } + if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode()) + { + clearHoverItem(); + } - checkMenuTrigger(); + checkMenuTrigger(); - LLMenuGL::draw(); + LLMenuGL::draw(); } void LLMenuBarGL::checkMenuTrigger() { - // has the ALT key been pressed and subsequently released? - if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT)) - { - // if alt key was released quickly, treat it as a menu access key - // otherwise it was probably an Alt-zoom or similar action - static LLUICachedControl<F32> menu_access_key_time ("MenuAccessKeyTime", 0); - if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= menu_access_key_time || - gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2) - { - if (getHighlightedItem()) - { - clearHoverItem(); - } - else - { - // close menus originating from other menu bars - LLMenuGL::sMenuContainer->hideMenus(); - - highlightNextItem(NULL); - LLMenuGL::setKeyboardMode(TRUE); - } - } - mAltKeyTrigger = FALSE; - } + // has the ALT key been pressed and subsequently released? + if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT)) + { + // if alt key was released quickly, treat it as a menu access key + // otherwise it was probably an Alt-zoom or similar action + static LLUICachedControl<F32> menu_access_key_time ("MenuAccessKeyTime", 0); + if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= menu_access_key_time || + gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2) + { + if (getHighlightedItem()) + { + clearHoverItem(); + } + else + { + // close menus originating from other menu bars + LLMenuGL::sMenuContainer->hideMenus(); + + highlightNextItem(NULL); + LLMenuGL::setKeyboardMode(TRUE); + } + } + mAltKeyTrigger = FALSE; + } } BOOL LLMenuBarGL::jumpKeysActive() { - // require user to be in keyboard navigation mode to activate key triggers - // as menu bars are always visible and it is easy to leave the mouse cursor over them - return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive(); + // require user to be in keyboard navigation mode to activate key triggers + // as menu bars are always visible and it is easy to leave the mouse cursor over them + return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive(); } // rearrange the child rects so they fit the shape of the menu bar. void LLMenuBarGL::arrange( void ) { - U32 pos = 0; - LLRect rect( 0, getRect().getHeight(), 0, 0 ); - item_list_t::const_iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - LLMenuItemGL* item = *item_iter; - if (item->getVisible()) - { - rect.mLeft = pos; - pos += item->getNominalWidth(); - rect.mRight = pos; - item->setRect( rect ); - item->buildDrawLabel(); - } - } - reshape(rect.mRight, rect.getHeight()); + U32 pos = 0; + LLRect rect( 0, getRect().getHeight(), 0, 0 ); + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL* item = *item_iter; + if (item->getVisible()) + { + rect.mLeft = pos; + pos += item->getNominalWidth(); + rect.mRight = pos; + item->setRect( rect ); + item->buildDrawLabel(); + } + } + reshape(rect.mRight, rect.getHeight()); } S32 LLMenuBarGL::getRightmostMenuEdge() { - // Find the last visible menu - item_list_t::reverse_iterator item_iter; - for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter) - { - if ((*item_iter)->getVisible()) - { - break; - } - } + // Find the last visible menu + item_list_t::reverse_iterator item_iter; + for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter) + { + if ((*item_iter)->getVisible()) + { + break; + } + } - if (item_iter == mItems.rend()) - { - return 0; - } - return (*item_iter)->getRect().mRight; + if (item_iter == mItems.rend()) + { + return 0; + } + return (*item_iter)->getRect().mRight; } // add a vertical separator to this menu BOOL LLMenuBarGL::addSeparator() { - LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(); - return append( separator ); + LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(); + return append( separator ); } // add a menu - this will create a drop down menu. BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu ) { - if( menu == this ) - { - LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " - << "a logic error." << LL_ENDL; - } - - BOOL success = TRUE; - - // *TODO: Hack! Fix this - LLMenuItemBranchDownGL::Params p; - p.name = menu->getName(); - p.label = menu->getLabel(); - p.visible = menu->getVisible(); - p.branch = menu; - p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); - p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); - p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); - p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + if( menu == this ) + { + LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " + << "a logic error." << LL_ENDL; + } + + BOOL success = TRUE; + + // *TODO: Hack! Fix this + LLMenuItemBranchDownGL::Params p; + p.name = menu->getName(); + p.label = menu->getLabel(); + p.visible = menu->getVisible(); + p.branch = menu; + p.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); + p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); + p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); p.font = menu->getFont(); - LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create<LLMenuItemBranchDownGL>(p); - success &= branch->addToAcceleratorList(&mAccelerators); - success &= append( branch ); - branch->setJumpKey(branch->getJumpKey()); - menu->updateParent(LLMenuGL::sMenuContainer); - - return success; + LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create<LLMenuItemBranchDownGL>(p); + success &= branch->addToAcceleratorList(&mAccelerators); + success &= append( branch ); + branch->setJumpKey(branch->getJumpKey()); + menu->updateParent(LLMenuGL::sMenuContainer); + + return success; } BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; - LLView* active_menu = NULL; - - BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; - S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; - S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; - mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2); - mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2); - mLastMouseX = x; - mLastMouseY = y; - - // if nothing currently selected or mouse has moved since last call, pick menu item via mouse - // otherwise let keyboard control it - if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0) - { - // find current active menu - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (((LLMenuItemGL*)viewp)->isOpen()) - { - active_menu = viewp; - } - } - - // check for new active menu - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if( viewp->getVisible() && - viewp->getEnabled() && - viewp->pointInView(local_x, local_y) && - viewp->handleHover(local_x, local_y, mask)) - { - ((LLMenuItemGL*)viewp)->setHighlight(TRUE); - handled = TRUE; - if (active_menu && active_menu != viewp) - { - ((LLMenuItemGL*)viewp)->onCommit(); - LLMenuGL::setKeyboardMode(FALSE); - } - LLMenuGL::setKeyboardMode(FALSE); - } - } - - if (handled) - { - // set hover false on inactive menus - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) - { - ((LLMenuItemGL*)viewp)->setHighlight(FALSE); - } - } - } - } - - getWindow()->setCursor(UI_CURSOR_ARROW); - - return TRUE; + BOOL handled = FALSE; + LLView* active_menu = NULL; + + BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; + S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; + S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; + mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2); + mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2); + mLastMouseX = x; + mLastMouseY = y; + + // if nothing currently selected or mouse has moved since last call, pick menu item via mouse + // otherwise let keyboard control it + if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0) + { + // find current active menu + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if (((LLMenuItemGL*)viewp)->isOpen()) + { + active_menu = viewp; + } + } + + // check for new active menu + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if( viewp->getVisible() && + viewp->getEnabled() && + viewp->pointInView(local_x, local_y) && + viewp->handleHover(local_x, local_y, mask)) + { + ((LLMenuItemGL*)viewp)->setHighlight(TRUE); + handled = TRUE; + if (active_menu && active_menu != viewp) + { + ((LLMenuItemGL*)viewp)->onCommit(); + LLMenuGL::setKeyboardMode(FALSE); + } + LLMenuGL::setKeyboardMode(FALSE); + } + } + + if (handled) + { + // set hover false on inactive menus + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) + { + ((LLMenuItemGL*)viewp)->setHighlight(FALSE); + } + } + } + } + + getWindow()->setCursor(UI_CURSOR_ARROW); + + return TRUE; } ///============================================================================ @@ -3734,237 +3733,237 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask ) LLCoordGL LLMenuHolderGL::sContextMenuSpawnPos(S32_MAX, S32_MAX); LLMenuHolderGL::LLMenuHolderGL(const LLMenuHolderGL::Params& p) - : LLPanel(p) + : LLPanel(p) { - sItemActivationTimer.stop(); - mCanHide = TRUE; + sItemActivationTimer.stop(); + mCanHide = TRUE; } void LLMenuHolderGL::draw() { - LLView::draw(); - // now draw last selected item as overlay - LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); - if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) - { - // make sure toggle items, for example, show the proper state when fading out - selecteditem->buildDrawLabel(); - - LLRect item_rect; - selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this); - - F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME; - - LLUI::pushMatrix(); - { - LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom); - selecteditem->getMenu()->drawBackground(selecteditem, interpolant); - selecteditem->draw(); - } - LLUI::popMatrix(); - } + LLView::draw(); + // now draw last selected item as overlay + LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); + if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) + { + // make sure toggle items, for example, show the proper state when fading out + selecteditem->buildDrawLabel(); + + LLRect item_rect; + selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this); + + F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME; + + LLUI::pushMatrix(); + { + LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom); + selecteditem->getMenu()->drawBackground(selecteditem, interpolant); + selecteditem->draw(); + } + LLUI::popMatrix(); + } } BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask ) { - BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; - if (!handled) - { - LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu(); - LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL; - if (parent_menu && parent_menu->getVisible()) - { - // don't hide menu if parent was hit - LLRect parent_rect; - parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this); - if (!parent_rect.pointInRect(x, y)) - { - // clicked off of menu and parent, hide them all - hideMenus(); - } - } - else - { - // no visible parent, clicked off of menu, hide them all - hideMenus(); - } - } - return handled; + BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; + if (!handled) + { + LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu(); + LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL; + if (parent_menu && parent_menu->getVisible()) + { + // don't hide menu if parent was hit + LLRect parent_rect; + parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this); + if (!parent_rect.pointInRect(x, y)) + { + // clicked off of menu and parent, hide them all + hideMenus(); + } + } + else + { + // no visible parent, clicked off of menu, hide them all + hideMenus(); + } + } + return handled; } BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask ) { - BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL; - if (!handled) - { - // clicked off of menu, hide them all - hideMenus(); - } - return handled; + BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL; + if (!handled) + { + // clicked off of menu, hide them all + hideMenus(); + } + return handled; } -// This occurs when you mouse-down to spawn a context menu, hold the button +// This occurs when you mouse-down to spawn a context menu, hold the button // down, move off the menu, then mouse-up. We want this to close the menu. BOOL LLMenuHolderGL::handleRightMouseUp( S32 x, S32 y, MASK mask ) { - const S32 SLOP = 2; - S32 spawn_dx = (x - sContextMenuSpawnPos.mX); - S32 spawn_dy = (y - sContextMenuSpawnPos.mY); - if (-SLOP <= spawn_dx && spawn_dx <= SLOP - && -SLOP <= spawn_dy && spawn_dy <= SLOP) - { - // we're still inside the slop region from spawning this menu - // so interpret the mouse-up as a single-click to show and leave on - // screen - sContextMenuSpawnPos.set(S32_MAX, S32_MAX); - return TRUE; - } - - BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL; - if (!handled) - { - // clicked off of menu, hide them all - hideMenus(); - } - return handled; + const S32 SLOP = 2; + S32 spawn_dx = (x - sContextMenuSpawnPos.mX); + S32 spawn_dy = (y - sContextMenuSpawnPos.mY); + if (-SLOP <= spawn_dx && spawn_dx <= SLOP + && -SLOP <= spawn_dy && spawn_dy <= SLOP) + { + // we're still inside the slop region from spawning this menu + // so interpret the mouse-up as a single-click to show and leave on + // screen + sContextMenuSpawnPos.set(S32_MAX, S32_MAX); + return TRUE; + } + + BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL; + if (!handled) + { + // clicked off of menu, hide them all + hideMenus(); + } + return handled; } BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - BOOL handled = false; - LLMenuGL* const pMenu = dynamic_cast<LLMenuGL*>(getVisibleMenu()); - - if (pMenu) - { - //eat TAB key - EXT-7000 - if (key == KEY_TAB && mask == MASK_NONE) - { - return TRUE; - } - - //handle ESCAPE and RETURN key - handled = LLPanel::handleKey(key, mask, called_from_parent); - if (!handled) - { - if (pMenu->getHighlightedItem()) - { - handled = pMenu->handleKey(key, mask, TRUE); - } - else if (mask == MASK_NONE || (key >= KEY_LEFT && key <= KEY_DOWN)) - { - //highlight first enabled one - if(pMenu->highlightNextItem(NULL)) - { - handled = true; - } - } - } - } - - return handled; - + BOOL handled = false; + LLMenuGL* const pMenu = dynamic_cast<LLMenuGL*>(getVisibleMenu()); + + if (pMenu) + { + //eat TAB key - EXT-7000 + if (key == KEY_TAB && mask == MASK_NONE) + { + return TRUE; + } + + //handle ESCAPE and RETURN key + handled = LLPanel::handleKey(key, mask, called_from_parent); + if (!handled) + { + if (pMenu->getHighlightedItem()) + { + handled = pMenu->handleKey(key, mask, TRUE); + } + else if (mask == MASK_NONE || (key >= KEY_LEFT && key <= KEY_DOWN)) + { + //highlight first enabled one + if(pMenu->highlightNextItem(NULL)) + { + handled = true; + } + } + } + } + + return handled; + } void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent) { - if (width != getRect().getWidth() || height != getRect().getHeight()) - { - hideMenus(); - } - LLView::reshape(width, height, called_from_parent); + if (width != getRect().getWidth() || height != getRect().getHeight()) + { + hideMenus(); + } + LLView::reshape(width, height, called_from_parent); } LLView* const LLMenuHolderGL::getVisibleMenu() const { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (viewp->getVisible() && dynamic_cast<LLMenuGL*>(viewp) != NULL) - { - return viewp; - } - } - return NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if (viewp->getVisible() && dynamic_cast<LLMenuGL*>(viewp) != NULL) + { + return viewp; + } + } + return NULL; } BOOL LLMenuHolderGL::hideMenus() { - if (!mCanHide) - { - return FALSE; - } - LLMenuGL::setKeyboardMode(FALSE); - BOOL menu_visible = hasVisibleMenu(); - if (menu_visible) - { - // clicked off of menu, hide them all - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (dynamic_cast<LLMenuGL*>(viewp) != NULL && viewp->getVisible()) - { - viewp->setVisible(FALSE); - } - } - } - //if (gFocusMgr.childHasKeyboardFocus(this)) - //{ - // gFocusMgr.setKeyboardFocus(NULL); - //} - - return menu_visible; + if (!mCanHide) + { + return FALSE; + } + LLMenuGL::setKeyboardMode(FALSE); + BOOL menu_visible = hasVisibleMenu(); + if (menu_visible) + { + // clicked off of menu, hide them all + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if (dynamic_cast<LLMenuGL*>(viewp) != NULL && viewp->getVisible()) + { + viewp->setVisible(FALSE); + } + } + } + //if (gFocusMgr.childHasKeyboardFocus(this)) + //{ + // gFocusMgr.setKeyboardFocus(NULL); + //} + + return menu_visible; } void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item) { - sItemLastSelectedHandle = item->getHandle(); - sItemActivationTimer.start(); + sItemLastSelectedHandle = item->getHandle(); + sItemActivationTimer.start(); } ///============================================================================ /// Class LLTearOffMenu ///============================================================================ -LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : - LLFloater(LLSD()), +LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : + LLFloater(LLSD()), mQuitRequested(false) { - S32 floater_header_size = getHeaderHeight(); + S32 floater_header_size = getHeaderHeight(); - setName(menup->getName()); - setTitle(menup->getLabel()); - setCanMinimize(FALSE); - // flag menu as being torn off - menup->setTornOff(TRUE); - // update menu layout as torn off menu (no spillover menus) - menup->needsArrange(); + setName(menup->getName()); + setTitle(menup->getLabel()); + setCanMinimize(FALSE); + // flag menu as being torn off + menup->setTornOff(TRUE); + // update menu layout as torn off menu (no spillover menus) + menup->needsArrange(); - LLRect rect; - menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView); - // make sure this floater is big enough for menu - mTargetHeight = rect.getHeight() + floater_header_size; - reshape(rect.getWidth(), rect.getHeight()); - setRect(rect); + LLRect rect; + menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView); + // make sure this floater is big enough for menu + mTargetHeight = rect.getHeight() + floater_header_size; + reshape(rect.getWidth(), rect.getHeight()); + setRect(rect); - // attach menu to floater - menup->setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM ); - mOldParent = menup->getParent(); - addChild(menup); - menup->setVisible(TRUE); - LLRect menu_rect = menup->getRect(); - menu_rect.setOriginAndSize( 1, 1, - menu_rect.getWidth(), menu_rect.getHeight()); - menup->setRect(menu_rect); - menup->setDropShadowed(FALSE); + // attach menu to floater + menup->setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM ); + mOldParent = menup->getParent(); + addChild(menup); + menup->setVisible(TRUE); + LLRect menu_rect = menup->getRect(); + menu_rect.setOriginAndSize( 1, 1, + menu_rect.getWidth(), menu_rect.getHeight()); + menup->setRect(menu_rect); + menup->setDropShadowed(FALSE); - mMenu = menup; + mMenu = menup; - // highlight first item (tear off item will be disabled) - mMenu->highlightNextItem(NULL); + // highlight first item (tear off item will be disabled) + mMenu->highlightNextItem(NULL); - // Can't do this in postBuild() because that is only called for floaters - // constructed from XML. - mCloseSignal.connect(boost::bind(&LLTearOffMenu::closeTearOff, this)); + // Can't do this in postBuild() because that is only called for floaters + // constructed from XML. + mCloseSignal.connect(boost::bind(&LLTearOffMenu::closeTearOff, this)); } LLTearOffMenu::~LLTearOffMenu() @@ -3973,15 +3972,15 @@ LLTearOffMenu::~LLTearOffMenu() void LLTearOffMenu::draw() { - mMenu->setBackgroundVisible(isBackgroundOpaque()); + mMenu->setBackgroundVisible(isBackgroundOpaque()); - if (getRect().getHeight() != mTargetHeight) - { - // animate towards target height + if (getRect().getHeight() != mTargetHeight) + { + // animate towards target height reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), (F32)mTargetHeight, LLSmoothInterpolation::getInterpolant(0.05f)))); - } - mMenu->needsArrange(); - LLFloater::draw(); + } + mMenu->needsArrange(); + LLFloater::draw(); } void LLTearOffMenu::onFocusReceived() @@ -3990,81 +3989,81 @@ void LLTearOffMenu::onFocusReceived() { return; } - + // if nothing is highlighted, just highlight first item - if (!mMenu->getHighlightedItem()) - { - mMenu->highlightNextItem(NULL); - } - - // parent menu items get highlights so navigation logic keeps working - LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem(); - while(parent_menu_item) - { - if (parent_menu_item->getMenu()->getVisible()) - { - parent_menu_item->setHighlight(TRUE); - parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem(); - } - else - { - break; - } - } - LLFloater::onFocusReceived(); + if (!mMenu->getHighlightedItem()) + { + mMenu->highlightNextItem(NULL); + } + + // parent menu items get highlights so navigation logic keeps working + LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem(); + while(parent_menu_item) + { + if (parent_menu_item->getMenu()->getVisible()) + { + parent_menu_item->setHighlight(TRUE); + parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem(); + } + else + { + break; + } + } + LLFloater::onFocusReceived(); } void LLTearOffMenu::onFocusLost() { - // remove highlight from parent item and our own menu - mMenu->clearHoverItem(); - LLFloater::onFocusLost(); + // remove highlight from parent item and our own menu + mMenu->clearHoverItem(); + LLFloater::onFocusLost(); } BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { - // pass keystrokes down to menu - return mMenu->handleUnicodeChar(uni_char, TRUE); + // pass keystrokes down to menu + return mMenu->handleUnicodeChar(uni_char, TRUE); } BOOL LLTearOffMenu::handleKeyHere(KEY key, MASK mask) { - if (!mMenu->getHighlightedItem()) - { - if (key == KEY_UP) - { - mMenu->highlightPrevItem(NULL); - return TRUE; - } - else if (key == KEY_DOWN) - { - mMenu->highlightNextItem(NULL); - return TRUE; - } - } - // pass keystrokes down to menu - return mMenu->handleKey(key, mask, TRUE); + if (!mMenu->getHighlightedItem()) + { + if (key == KEY_UP) + { + mMenu->highlightPrevItem(NULL); + return TRUE; + } + else if (key == KEY_DOWN) + { + mMenu->highlightNextItem(NULL); + return TRUE; + } + } + // pass keystrokes down to menu + return mMenu->handleKey(key, mask, TRUE); } void LLTearOffMenu::translate(S32 x, S32 y) { - if (x != 0 && y != 0) - { - // hide open sub-menus by clearing current hover item - mMenu->clearHoverItem(); - } - LLFloater::translate(x, y); + if (x != 0 && y != 0) + { + // hide open sub-menus by clearing current hover item + mMenu->clearHoverItem(); + } + LLFloater::translate(x, y); } //static LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup) { - LLTearOffMenu* tearoffp = new LLTearOffMenu(menup); - // keep onscreen - gFloaterView->adjustToFitScreen(tearoffp, FALSE); - tearoffp->openFloater(LLSD()); + LLTearOffMenu* tearoffp = new LLTearOffMenu(menup); + // keep onscreen + gFloaterView->adjustToFitScreen(tearoffp, FALSE); + tearoffp->openFloater(LLSD()); - return tearoffp; + return tearoffp; } void LLTearOffMenu::updateSize() @@ -4094,108 +4093,108 @@ void LLTearOffMenu::updateSize() void LLTearOffMenu::closeTearOff() { - removeChild(mMenu); - mOldParent->addChild(mMenu); - mMenu->clearHoverItem(); - mMenu->setFollowsNone(); - mMenu->setBackgroundVisible(TRUE); - mMenu->setVisible(FALSE); - mMenu->setTornOff(FALSE); - mMenu->setDropShadowed(TRUE); + removeChild(mMenu); + mOldParent->addChild(mMenu); + mMenu->clearHoverItem(); + mMenu->setFollowsNone(); + mMenu->setBackgroundVisible(TRUE); + mMenu->setVisible(FALSE); + mMenu->setTornOff(FALSE); + mMenu->setDropShadowed(TRUE); mQuitRequested = true; } -LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p) -: LLMenuItemGL(p) +LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p) +: LLMenuItemGL(p) { - LLContextMenu* branch = static_cast<LLContextMenu*>(p.branch); - if (branch) - { - mBranch = branch->getHandle(); - branch->hide(); - branch->setParentMenuItem(this); - } + LLContextMenu* branch = static_cast<LLContextMenu*>(p.branch); + if (branch) + { + mBranch = branch->getHandle(); + branch->hide(); + branch->setParentMenuItem(this); + } } LLContextMenuBranch::~LLContextMenuBranch() { - if (mBranch.get()) - { - mBranch.get()->die(); - } + if (mBranch.get()) + { + mBranch.get()->die(); + } } // called to rebuild the draw label void LLContextMenuBranch::buildDrawLabel( void ) { - auto menu = getBranch(); - if (menu) - { - // default enablement is this -- if any of the subitems are - // enabled, this item is enabled. JC - U32 sub_count = menu->getItemCount(); - U32 i; - BOOL any_enabled = FALSE; - for (i = 0; i < sub_count; i++) - { - LLMenuItemGL* item = menu->getItem(i); - item->buildDrawLabel(); - if (item->getEnabled() && !item->getDrawTextDisabled() ) - { - any_enabled = TRUE; - break; - } - } - setDrawTextDisabled(!any_enabled); - setEnabled(TRUE); - } - - mDrawAccelLabel.clear(); - std::string st = mDrawAccelLabel; - appendAcceleratorString( st ); - mDrawAccelLabel = st; - - mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; -} - -void LLContextMenuBranch::showSubMenu() -{ - auto menu = getBranch(); - if(menu) - { - LLMenuItemGL* menu_item = menu->getParentMenuItem(); - if (menu_item != NULL && menu_item->getVisible()) - { - S32 center_x; - S32 center_y; - localPointToScreen(getRect().getWidth(), getRect().getHeight(), ¢er_x, ¢er_y); - menu->show(center_x, center_y); - } - } + auto menu = getBranch(); + if (menu) + { + // default enablement is this -- if any of the subitems are + // enabled, this item is enabled. JC + U32 sub_count = menu->getItemCount(); + U32 i; + BOOL any_enabled = FALSE; + for (i = 0; i < sub_count; i++) + { + LLMenuItemGL* item = menu->getItem(i); + item->buildDrawLabel(); + if (item->getEnabled() && !item->getDrawTextDisabled() ) + { + any_enabled = TRUE; + break; + } + } + setDrawTextDisabled(!any_enabled); + setEnabled(TRUE); + } + + mDrawAccelLabel.clear(); + std::string st = mDrawAccelLabel; + appendAcceleratorString( st ); + mDrawAccelLabel = st; + + mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; +} + +void LLContextMenuBranch::showSubMenu() +{ + auto menu = getBranch(); + if(menu) + { + LLMenuItemGL* menu_item = menu->getParentMenuItem(); + if (menu_item != NULL && menu_item->getVisible()) + { + S32 center_x; + S32 center_y; + localPointToScreen(getRect().getWidth(), getRect().getHeight(), ¢er_x, ¢er_y); + menu->show(center_x, center_y); + } + } } // onCommit() - do the primary funcationality of the menu item. void LLContextMenuBranch::onCommit( void ) { - showSubMenu(); + showSubMenu(); } void LLContextMenuBranch::setHighlight( BOOL highlight ) { - if (highlight == getHighlight()) return; - LLMenuItemGL::setHighlight(highlight); - auto menu = getBranch(); - if (menu) - { - if (highlight) - { - showSubMenu(); - } - else - { - menu->hide(); - } - } + if (highlight == getHighlight()) return; + LLMenuItemGL::setHighlight(highlight); + auto menu = getBranch(); + if (menu) + { + if (highlight) + { + showSubMenu(); + } + else + { + menu->hide(); + } + } } @@ -4209,140 +4208,140 @@ static MenuRegistry::Register<LLContextMenu> context_menu_register2("context_men LLContextMenu::LLContextMenu(const Params& p) -: LLMenuGL(p), - mHoveredAnyItem(FALSE), - mHoverItem(NULL) +: LLMenuGL(p), + mHoveredAnyItem(FALSE), + mHoverItem(NULL) { - //setBackgroundVisible(TRUE); + //setBackgroundVisible(TRUE); } void LLContextMenu::setVisible(BOOL visible) { - if (!visible) - hide(); + if (!visible) + hide(); } // Takes cursor position in screen space? void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view) { - if (getChildList()->empty()) - { - // nothing to show, so abort - return; - } - // Save click point for detecting cursor moves before mouse-up. - // Must be in local coords to compare with mouseUp events. - // If the mouse doesn't move, the menu will stay open ala the Mac. - // See also LLMenuGL::showPopup() - LLMenuHolderGL::sContextMenuSpawnPos.set(x,y); - - arrangeAndClear(); - - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); - const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); - LLView* parent_view = getParent(); - - // Open upwards if menu extends past bottom - if (y - height < menu_region_rect.mBottom) - { - if (getParentMenuItem()) // Adjust if this is a submenu - { - y += height - getParentMenuItem()->getNominalHeight(); - } - else - { - y += height; - } - } - - // Open out to the left if menu extends past right edge - if (x + width > menu_region_rect.mRight) - { - if (getParentMenuItem()) - { - x -= getParentMenuItem()->getRect().getWidth() + width; - } - else - { - x -= width; - } - } - - S32 local_x, local_y; - parent_view->screenPointToLocal(x, y, &local_x, &local_y); - - LLRect rect; - rect.setLeftTopAndSize(local_x, local_y, width, height); - setRect(rect); - arrange(); - - if (spawning_view) - { - mSpawningViewHandle = spawning_view->getHandle(); - } - else - { - mSpawningViewHandle.markDead(); - } - LLView::setVisible(TRUE); + if (getChildList()->empty()) + { + // nothing to show, so abort + return; + } + // Save click point for detecting cursor moves before mouse-up. + // Must be in local coords to compare with mouseUp events. + // If the mouse doesn't move, the menu will stay open ala the Mac. + // See also LLMenuGL::showPopup() + LLMenuHolderGL::sContextMenuSpawnPos.set(x,y); + + arrangeAndClear(); + + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); + LLView* parent_view = getParent(); + + // Open upwards if menu extends past bottom + if (y - height < menu_region_rect.mBottom) + { + if (getParentMenuItem()) // Adjust if this is a submenu + { + y += height - getParentMenuItem()->getNominalHeight(); + } + else + { + y += height; + } + } + + // Open out to the left if menu extends past right edge + if (x + width > menu_region_rect.mRight) + { + if (getParentMenuItem()) + { + x -= getParentMenuItem()->getRect().getWidth() + width; + } + else + { + x -= width; + } + } + + S32 local_x, local_y; + parent_view->screenPointToLocal(x, y, &local_x, &local_y); + + LLRect rect; + rect.setLeftTopAndSize(local_x, local_y, width, height); + setRect(rect); + arrange(); + + if (spawning_view) + { + mSpawningViewHandle = spawning_view->getHandle(); + } + else + { + mSpawningViewHandle.markDead(); + } + LLView::setVisible(TRUE); } void LLContextMenu::hide() { - if (!getVisible()) return; + if (!getVisible()) return; - LLView::setVisible(FALSE); + LLView::setVisible(FALSE); - if (mHoverItem) - { - mHoverItem->setHighlight( FALSE ); - } - mHoverItem = NULL; + if (mHoverItem) + { + mHoverItem->setHighlight( FALSE ); + } + mHoverItem = NULL; } BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask ) { - LLMenuGL::handleHover(x,y,mask); - - BOOL handled = FALSE; - - LLMenuItemGL *item = getHighlightedItem(); - - if (item && item->getEnabled()) - { - getWindow()->setCursor(UI_CURSOR_ARROW); - handled = TRUE; - - if (item != mHoverItem) - { - if (mHoverItem) - { - mHoverItem->setHighlight( FALSE ); - } - mHoverItem = item; - mHoverItem->setHighlight( TRUE ); - } - mHoveredAnyItem = TRUE; - } - else - { - // clear out our selection - if (mHoverItem) - { - mHoverItem->setHighlight(FALSE); - mHoverItem = NULL; - } - } - - if( !handled && pointInView( x, y ) ) - { - getWindow()->setCursor(UI_CURSOR_ARROW); - handled = TRUE; - } - - return handled; + LLMenuGL::handleHover(x,y,mask); + + BOOL handled = FALSE; + + LLMenuItemGL *item = getHighlightedItem(); + + if (item && item->getEnabled()) + { + getWindow()->setCursor(UI_CURSOR_ARROW); + handled = TRUE; + + if (item != mHoverItem) + { + if (mHoverItem) + { + mHoverItem->setHighlight( FALSE ); + } + mHoverItem = item; + mHoverItem->setHighlight( TRUE ); + } + mHoveredAnyItem = TRUE; + } + else + { + // clear out our selection + if (mHoverItem) + { + mHoverItem->setHighlight(FALSE); + mHoverItem = NULL; + } + } + + if( !handled && pointInView( x, y ) ) + { + getWindow()->setCursor(UI_CURSOR_ARROW); + handled = TRUE; + } + + return handled; } // handleMouseDown and handleMouseUp are handled by LLMenuGL @@ -4350,56 +4349,56 @@ BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask ) BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; + + // The click was somewhere within our rectangle + LLMenuItemGL *item = getHighlightedItem(); - // The click was somewhere within our rectangle - LLMenuItemGL *item = getHighlightedItem(); + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; - S32 local_x = x - getRect().mLeft; - S32 local_y = y - getRect().mBottom; + BOOL clicked_in_menu = pointInView(local_x, local_y) ; - BOOL clicked_in_menu = pointInView(local_x, local_y) ; + // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie + if (clicked_in_menu) + { + // capture mouse cursor as if on initial menu show + handled = TRUE; + } - // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie - if (clicked_in_menu) - { - // capture mouse cursor as if on initial menu show - handled = TRUE; - } - - if (item) - { - // lie to the item about where the click happened - // to make sure it's within the item's rectangle - if (item->handleMouseDown( 0, 0, mask )) - { - handled = TRUE; - } - } + if (item) + { + // lie to the item about where the click happened + // to make sure it's within the item's rectangle + if (item->handleMouseDown( 0, 0, mask )) + { + handled = TRUE; + } + } - return handled; + return handled; } BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask ) { - S32 local_x = x - getRect().mLeft; - S32 local_y = y - getRect().mBottom; + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; + + if (!mHoveredAnyItem && !pointInView(local_x, local_y)) + { + sMenuContainer->hideMenus(); + return TRUE; + } - if (!mHoveredAnyItem && !pointInView(local_x, local_y)) - { - sMenuContainer->hideMenus(); - return TRUE; - } + BOOL result = handleMouseUp( x, y, mask ); + mHoveredAnyItem = FALSE; - BOOL result = handleMouseUp( x, y, mask ); - mHoveredAnyItem = FALSE; - - return result; + return result; } bool LLContextMenu::addChild(LLView* view, S32 tab_group) { - return addContextChild(view, tab_group); + return addContextChild(view, tab_group); } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 44ac61f20d..72e041672a 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmenugl.h * @brief Declaration of the opengl based menu system. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,183 +45,183 @@ extern S32 MENU_BAR_WIDTH; class LLMenuKeyboardBinding { public: - KEY mKey; - MASK mMask; + KEY mKey; + MASK mMask; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemGL // -// The LLMenuItemGL represents a single menu item in a menu. +// The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<std::string> shortcut; - Optional<KEY> jump_key; - Optional<bool> use_mac_ctrl, - allow_key_repeat; - - Ignored rect, - left, - top, - right, - bottom, - width, - height, - bottom_delta, - left_delta; - - Optional<LLUIColor> enabled_color, - disabled_color, - highlight_bg_color, - highlight_fg_color; - - - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<std::string> shortcut; + Optional<KEY> jump_key; + Optional<bool> use_mac_ctrl, + allow_key_repeat; + + Ignored rect, + left, + top, + right, + bottom, + width, + height, + bottom_delta, + left_delta; + + Optional<LLUIColor> enabled_color, + disabled_color, + highlight_bg_color, + highlight_fg_color; + + + Params(); + }; protected: - LLMenuItemGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemGL(const Params&); + friend class LLUICtrlFactory; public: - // LLView overrides - /*virtual*/ void onVisibilityChange(BOOL new_visibility); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - - // LLUICtrl overrides - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ LLSD getValue() const; - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } - - void setJumpKey(KEY key); - KEY getJumpKey() const { return mJumpKey; } - - // set the font used by this item. - void setFont(const LLFontGL* font) { mFont = font; } - const LLFontGL* getFont() const { return mFont; } - - // returns the height in pixels for the current font. - virtual U32 getNominalHeight( void ) const; - - // Marks item as not needing space for check marks or accelerator keys - virtual void setBriefItem(BOOL brief); - virtual BOOL isBriefItem() const; - - virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); - void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } - BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } - - // change the label - void setLabel( const LLStringExplicit& label ) { mLabel = label; } - std::string getLabel( void ) const { return mLabel.getString(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - // Get the parent menu for this item - virtual class LLMenuGL* getMenu() const; - - // returns the normal width of this control in pixels - this is - // used for calculating the widest item, as well as for horizontal - // arrangement. - virtual U32 getNominalWidth( void ) const; - - // buildDrawLabel() - constructs the string used during the draw() - // function. This reduces the overall string manipulation, but can - // lead to visual errors if the state of the object changes - // without the knowledge of the menu item. For example, if a - // boolean being watched is changed outside of the menu item's - // onCommit() function, the draw buffer will not be updated and will - // reflect the wrong value. If this ever becomes an issue, there - // are ways to fix this. - // Returns the enabled state of the item. - virtual void buildDrawLabel( void ); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateBranchParent( LLView* parentp ){}; - - virtual void onCommit( void ); - - virtual void setHighlight( BOOL highlight ); - virtual BOOL getHighlight() const { return mHighlight; } - - // determine if this represents an active sub-menu - virtual BOOL isActive( void ) const { return FALSE; } - - // determine if this represents an open sub-menu - virtual BOOL isOpen( void ) const { return FALSE; } - - virtual void setEnabledSubMenus(BOOL enable){}; - - // LLView Functionality - virtual BOOL handleKeyHere( KEY key, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - virtual void draw( void ); - - BOOL getHover() const { return mGotHover; } - - void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } - BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } + // LLView overrides + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + + // LLUICtrl overrides + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); } + + void setJumpKey(KEY key); + KEY getJumpKey() const { return mJumpKey; } + + // set the font used by this item. + void setFont(const LLFontGL* font) { mFont = font; } + const LLFontGL* getFont() const { return mFont; } + + // returns the height in pixels for the current font. + virtual U32 getNominalHeight( void ) const; + + // Marks item as not needing space for check marks or accelerator keys + virtual void setBriefItem(BOOL brief); + virtual BOOL isBriefItem() const; + + virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp); + void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; } + BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; } + + // change the label + void setLabel( const LLStringExplicit& label ) { mLabel = label; } + std::string getLabel( void ) const { return mLabel.getString(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + // Get the parent menu for this item + virtual class LLMenuGL* getMenu() const; + + // returns the normal width of this control in pixels - this is + // used for calculating the widest item, as well as for horizontal + // arrangement. + virtual U32 getNominalWidth( void ) const; + + // buildDrawLabel() - constructs the string used during the draw() + // function. This reduces the overall string manipulation, but can + // lead to visual errors if the state of the object changes + // without the knowledge of the menu item. For example, if a + // boolean being watched is changed outside of the menu item's + // onCommit() function, the draw buffer will not be updated and will + // reflect the wrong value. If this ever becomes an issue, there + // are ways to fix this. + // Returns the enabled state of the item. + virtual void buildDrawLabel( void ); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateBranchParent( LLView* parentp ){}; + + virtual void onCommit( void ); + + virtual void setHighlight( BOOL highlight ); + virtual BOOL getHighlight() const { return mHighlight; } + + // determine if this represents an active sub-menu + virtual BOOL isActive( void ) const { return FALSE; } + + // determine if this represents an open sub-menu + virtual BOOL isOpen( void ) const { return FALSE; } + + virtual void setEnabledSubMenus(BOOL enable){}; + + // LLView Functionality + virtual BOOL handleKeyHere( KEY key, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + virtual void draw( void ); + + BOOL getHover() const { return mGotHover; } + + void setDrawTextDisabled(BOOL disabled) { mDrawTextDisabled = disabled; } + BOOL getDrawTextDisabled() const { return mDrawTextDisabled; } protected: - void setHover(BOOL hover) { mGotHover = hover; } + void setHover(BOOL hover) { mGotHover = hover; } - // This function appends the character string representation of - // the current accelerator key and mask to the provided string. - void appendAcceleratorString( std::string& st ) const; + // This function appends the character string representation of + // the current accelerator key and mask to the provided string. + void appendAcceleratorString( std::string& st ) const; - virtual std::string _getSearchText() const - { - return mLabel.getString(); - } + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } protected: - KEY mAcceleratorKey; - MASK mAcceleratorMask; - // mLabel contains the actual label specified by the user. - LLUIString mLabel; - - // The draw labels contain some of the labels that we draw during - // the draw() routine. This optimizes away some of the string - // manipulation. - LLUIString mDrawBoolLabel; - LLUIString mDrawAccelLabel; - LLUIString mDrawBranchLabel; - - LLUIColor mEnabledColor; - LLUIColor mDisabledColor; - LLUIColor mHighlightBackground; - LLUIColor mHighlightForeground; - - BOOL mHighlight; + KEY mAcceleratorKey; + MASK mAcceleratorMask; + // mLabel contains the actual label specified by the user. + LLUIString mLabel; + + // The draw labels contain some of the labels that we draw during + // the draw() routine. This optimizes away some of the string + // manipulation. + LLUIString mDrawBoolLabel; + LLUIString mDrawAccelLabel; + LLUIString mDrawBranchLabel; + + LLUIColor mEnabledColor; + LLUIColor mDisabledColor; + LLUIColor mHighlightBackground; + LLUIColor mHighlightForeground; + + BOOL mHighlight; private: - // Keyboard and mouse variables - BOOL mAllowKeyRepeat; - BOOL mGotHover; + // Keyboard and mouse variables + BOOL mAllowKeyRepeat; + BOOL mGotHover; - // If true, suppress normal space for check marks on the left and accelerator - // keys on the right. - BOOL mBriefItem; + // If true, suppress normal space for check marks on the left and accelerator + // keys on the right. + BOOL mBriefItem; - // Font for this item - const LLFontGL* mFont; - BOOL mDrawTextDisabled; + // Font for this item + const LLFontGL* mFont; + BOOL mDrawTextDisabled; - KEY mJumpKey; + KEY mJumpKey; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,22 +232,22 @@ private: class LLMenuItemSeparatorGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { Optional<EnableCallbackParam > on_visible; Params(); - }; + }; LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params()); - /*virtual*/ void draw( void ); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); virtual void buildDrawLabel(); - /*virtual*/ U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; private: enable_signal_t mVisibleSignal; @@ -263,49 +263,49 @@ private: class LLMenuItemCallGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Optional<EnableCallbackParam > on_enable; - Optional<CommitCallbackParam > on_click; - Optional<EnableCallbackParam > on_visible; - Params() - : on_enable("on_enable"), - on_click("on_click"), - on_visible("on_visible") - {} - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Optional<EnableCallbackParam > on_enable; + Optional<CommitCallbackParam > on_click; + Optional<EnableCallbackParam > on_visible; + Params() + : on_enable("on_enable"), + on_click("on_click"), + on_visible("on_visible") + {} + }; protected: - LLMenuItemCallGL(const Params&); - friend class LLUICtrlFactory; - void updateEnabled( void ); - void updateVisible( void ); + LLMenuItemCallGL(const Params&); + friend class LLUICtrlFactory; + void updateEnabled( void ); + void updateVisible( void ); public: - void initFromParams(const Params& p); - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual void onCommit( void ); - - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - - //virtual void draw(); - - boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) - { - return setCommitCallback(cb); - } - - boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) - { - return mEnableSignal.connect(cb); - } - + void initFromParams(const Params& p); + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual void onCommit( void ); + + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + //virtual void draw(); + + boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb ) + { + return setCommitCallback(cb); + } + + boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb ) + { + return mEnableSignal.connect(cb); + } + private: - enable_signal_t mEnableSignal; - enable_signal_t mVisibleSignal; + enable_signal_t mEnableSignal; + enable_signal_t mVisibleSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,40 +318,40 @@ private: // EFFICIENT because it may need to be checked a lot. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemCheckGL -: public LLMenuItemCallGL +class LLMenuItemCheckGL +: public LLMenuItemCallGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> - { - Optional<EnableCallbackParam > on_check; - Params() - : on_check("on_check") - {} - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params> + { + Optional<EnableCallbackParam > on_check; + Params() + : on_check("on_check") + {} + }; protected: - LLMenuItemCheckGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemCheckGL(const Params&); + friend class LLUICtrlFactory; public: - - void initFromParams(const Params& p); - - virtual void onCommit( void ); - - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) - { - return mCheckSignal.connect(cb); - } - + + void initFromParams(const Params& p); + + virtual void onCommit( void ); + + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb ) + { + return mCheckSignal.connect(cb); + } + private: - enable_signal_t mCheckSignal; + enable_signal_t mCheckSignal; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -368,233 +368,233 @@ private: // child widget registry struct MenuRegistry : public LLChildRegistry<MenuRegistry> { - LLSINGLETON_EMPTY_CTOR(MenuRegistry); + LLSINGLETON_EMPTY_CTOR(MenuRegistry); }; -class LLMenuGL -: public LLUICtrl +class LLMenuGL +: public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<KEY> jump_key; - Optional<bool> horizontal_layout, - can_tear_off, - drop_shadow, - bg_visible, - create_jump_keys, - keep_fixed_size, - scrollable; - Optional<U32> max_scrollable_items; - Optional<U32> preferred_width; - Optional<LLUIColor> bg_color; - Optional<S32> shortcut_pad; - - Params() - : jump_key("jump_key", KEY_NONE), - horizontal_layout("horizontal_layout"), - can_tear_off("tear_off", false), - drop_shadow("drop_shadow", true), - bg_visible("bg_visible", true), - create_jump_keys("create_jump_keys", false), - keep_fixed_size("keep_fixed_size", false), - bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), - scrollable("scrollable", false), - max_scrollable_items("max_scrollable_items", U32_MAX), - preferred_width("preferred_width", U32_MAX), - shortcut_pad("shortcut_pad") - { - addSynonym(bg_visible, "opaque"); - addSynonym(bg_color, "color"); - addSynonym(can_tear_off, "can_tear_off"); - } - }; - - // my valid children are contained in MenuRegistry - typedef MenuRegistry child_registry_t; - - void initFromParams(const Params&); - - // textual artwork which menugl-imitators may want to match - static const std::string BOOLEAN_TRUE_PREFIX; - static const std::string BRANCH_SUFFIX; - static const std::string ARROW_UP; - static const std::string ARROW_DOWN; - - // for scrollable menus - typedef enum e_scrolling_direction - { - SD_UP = 0, - SD_DOWN = 1, - SD_BEGIN = 2, - SD_END = 3 - } EScrollingDirection; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<KEY> jump_key; + Optional<bool> horizontal_layout, + can_tear_off, + drop_shadow, + bg_visible, + create_jump_keys, + keep_fixed_size, + scrollable; + Optional<U32> max_scrollable_items; + Optional<U32> preferred_width; + Optional<LLUIColor> bg_color; + Optional<S32> shortcut_pad; + + Params() + : jump_key("jump_key", KEY_NONE), + horizontal_layout("horizontal_layout"), + can_tear_off("tear_off", false), + drop_shadow("drop_shadow", true), + bg_visible("bg_visible", true), + create_jump_keys("create_jump_keys", false), + keep_fixed_size("keep_fixed_size", false), + bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )), + scrollable("scrollable", false), + max_scrollable_items("max_scrollable_items", U32_MAX), + preferred_width("preferred_width", U32_MAX), + shortcut_pad("shortcut_pad") + { + addSynonym(bg_visible, "opaque"); + addSynonym(bg_color, "color"); + addSynonym(can_tear_off, "can_tear_off"); + } + }; + + // my valid children are contained in MenuRegistry + typedef MenuRegistry child_registry_t; + + void initFromParams(const Params&); + + // textual artwork which menugl-imitators may want to match + static const std::string BOOLEAN_TRUE_PREFIX; + static const std::string BRANCH_SUFFIX; + static const std::string ARROW_UP; + static const std::string ARROW_DOWN; + + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; protected: - LLMenuGL(const LLMenuGL::Params& p); - friend class LLUICtrlFactory; - // let branching menu items use my protected traversal methods - friend class LLMenuItemBranchGL; + LLMenuGL(const LLMenuGL::Params& p); + friend class LLUICtrlFactory; + // let branching menu items use my protected traversal methods + friend class LLMenuItemBranchGL; public: - virtual ~LLMenuGL( void ); - - void parseChildXML(LLXMLNodePtr child, LLView* parent); - - // LLView Functionality - /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - /*virtual*/ void draw( void ); - /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + virtual ~LLMenuGL( void ); + + void parseChildXML(LLXMLNodePtr child, LLView* parent); + + // LLView Functionality + /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + /*virtual*/ void draw( void ); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha); + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void deleteAllChildren(); - /*virtual*/ void removeChild( LLView* ctrl); - /*virtual*/ BOOL postBuild(); - - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - - LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; - - BOOL clearHoverItem(); - - // return the name label - const std::string& getLabel( void ) const { return mLabel.getString(); } - void setLabel(const LLStringExplicit& label) { mLabel = label; } - - // background colors - void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } - const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - void setCanTearOff(BOOL tear_off); - - // add a separator to this menu - virtual BOOL addSeparator(); - - // for branching menu items, bring sub menus up to root level of menu hierarchy - virtual void updateParent( LLView* parentp ); - - // setItemEnabled() - pass the name and the enable flag for a - // menu item. TRUE will make sure it's enabled, FALSE will disable - // it. - void setItemEnabled( const std::string& name, BOOL enable ); - - // propagate message to submenus - void setEnabledSubMenus(BOOL enable); - - void setItemVisible( const std::string& name, BOOL visible); + /*virtual*/ void removeChild( LLView* ctrl); + /*virtual*/ BOOL postBuild(); + + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + + LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const; + + BOOL clearHoverItem(); + + // return the name label + const std::string& getLabel( void ) const { return mLabel.getString(); } + void setLabel(const LLStringExplicit& label) { mLabel = label; } + + // background colors + void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; } + const LLUIColor& getBackgroundColor() const { return mBackgroundColor; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + void setCanTearOff(BOOL tear_off); + + // add a separator to this menu + virtual BOOL addSeparator(); + + // for branching menu items, bring sub menus up to root level of menu hierarchy + virtual void updateParent( LLView* parentp ); + + // setItemEnabled() - pass the name and the enable flag for a + // menu item. TRUE will make sure it's enabled, FALSE will disable + // it. + void setItemEnabled( const std::string& name, BOOL enable ); + + // propagate message to submenus + void setEnabledSubMenus(BOOL enable); + + void setItemVisible( const std::string& name, BOOL visible); void setItemLabel(const std::string &name, const std::string &label); - - // sets the left,bottom corner of menu, useful for popups - void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL handleJumpKey(KEY key); + // sets the left,bottom corner of menu, useful for popups + void setLeftAndBottom(S32 left, S32 bottom); - virtual BOOL jumpKeysActive(); + virtual BOOL handleJumpKey(KEY key); - virtual BOOL isOpen(); + virtual BOOL jumpKeysActive(); - void needsArrange() { mNeedsArrange = TRUE; } - // Shape this menu to fit the current state of the children, and - // adjust the child rects to fit. This is called automatically - // when you add items. *FIX: We may need to deal with visibility - // arrangement. - virtual void arrange( void ); - void arrangeAndClear( void ); + virtual BOOL isOpen(); - // remove all items on the menu - void empty( void ); + void needsArrange() { mNeedsArrange = TRUE; } + // Shape this menu to fit the current state of the children, and + // adjust the child rects to fit. This is called automatically + // when you add items. *FIX: We may need to deal with visibility + // arrangement. + virtual void arrange( void ); + void arrangeAndClear( void ); - // erase group of items from menu - void erase( S32 begin, S32 end, bool arrange = true ); + // remove all items on the menu + void empty( void ); - // add new item at position - void insert( S32 begin, LLView * ctrl, bool arrange = true ); + // erase group of items from menu + void erase( S32 begin, S32 end, bool arrange = true ); - void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items - LLMenuItemGL* getItem(S32 number); // 0 = first item + // add new item at position + void insert( S32 begin, LLView * ctrl, bool arrange = true ); + + void setItemLastSelected(LLMenuItemGL* item); // must be in menu + U32 getItemCount(); // number of menu items + LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getItem(std::string name); - LLMenuItemGL* getHighlightedItem(); + LLMenuItemGL* getHighlightedItem(); + + LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); - LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disabled = TRUE); + void buildDrawLabels(); + void createJumpKeys(); - void buildDrawLabels(); - void createJumpKeys(); + // Show popup at a specific location, in the spawn_view's coordinate frame + static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); - // Show popup at a specific location, in the spawn_view's coordinate frame - static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0); + // Whether to drop shadow menu bar + void setDropShadowed( const BOOL shadowed ); - // Whether to drop shadow menu bar - void setDropShadowed( const BOOL shadowed ); + void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } + LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); } - void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); } - LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); } + void setTornOff(BOOL torn_off); + BOOL getTornOff() { return mTornOff; } - void setTornOff(BOOL torn_off); - BOOL getTornOff() { return mTornOff; } + BOOL getCanTearOff() { return mTearOffItem != NULL; } - BOOL getCanTearOff() { return mTearOffItem != NULL; } + KEY getJumpKey() const { return mJumpKey; } + void setJumpKey(KEY key) { mJumpKey = key; } - KEY getJumpKey() const { return mJumpKey; } - void setJumpKey(KEY key) { mJumpKey = key; } + static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } + static BOOL getKeyboardMode() { return sKeyboardMode; } - static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; } - static BOOL getKeyboardMode() { return sKeyboardMode; } + S32 getShortcutPad() { return mShortcutPad; } - S32 getShortcutPad() { return mShortcutPad; } + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } - bool scrollItems(EScrollingDirection direction); - BOOL isScrollable() const { return mScrollable; } + static class LLMenuHolderGL* sMenuContainer; - static class LLMenuHolderGL* sMenuContainer; - - void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } - bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } - void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } - BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } + void setAlwaysShowMenu(BOOL show) { mAlwaysShowMenu = show; } + BOOL getAlwaysShowMenu() { return mAlwaysShowMenu; } - // add a context menu branch - BOOL appendContextSubMenu(LLMenuGL *menu); + // add a context menu branch + BOOL appendContextSubMenu(LLMenuGL *menu); const LLFontGL *getFont() const { return mFont; } protected: - void createSpilloverBranch(); - void cleanupSpilloverBranch(); - // Add the menu item to this menu. - virtual BOOL append( LLMenuItemGL* item ); - - // add a menu - this will create a cascading menu - virtual BOOL appendMenu( LLMenuGL* menu ); - - // Used in LLContextMenu and in LLTogleableMenu - // to add an item of context menu branch - bool addContextChild(LLView* view, S32 tab_group); - - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; - item_list_t mItems; - LLMenuItemGL*mFirstVisibleItem; - LLMenuItemGL *mArrowUpItem, *mArrowDownItem; - - typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t; - navigation_key_map_t mJumpKeys; - S32 mLastMouseX; - S32 mLastMouseY; - S32 mMouseVelX; - S32 mMouseVelY; - U32 mMaxScrollableItems; - U32 mPreferredWidth; - BOOL mHorizontalLayout; - BOOL mScrollable; - BOOL mKeepFixedSize; - BOOL mNeedsArrange; + void createSpilloverBranch(); + void cleanupSpilloverBranch(); + // Add the menu item to this menu. + virtual BOOL append( LLMenuItemGL* item ); + + // add a menu - this will create a cascading menu + virtual BOOL appendMenu( LLMenuGL* menu ); + + // Used in LLContextMenu and in LLTogleableMenu + // to add an item of context menu branch + bool addContextChild(LLView* view, S32 tab_group); + + // TODO: create accessor methods for these? + typedef std::list< LLMenuItemGL* > item_list_t; + item_list_t mItems; + LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; + + typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t; + navigation_key_map_t mJumpKeys; + S32 mLastMouseX; + S32 mLastMouseY; + S32 mMouseVelX; + S32 mMouseVelY; + U32 mMaxScrollableItems; + U32 mPreferredWidth; + BOOL mHorizontalLayout; + BOOL mScrollable; + BOOL mKeepFixedSize; + BOOL mNeedsArrange; // Font for top menu items only const LLFontGL* mFont; @@ -602,27 +602,27 @@ public: private: - static LLColor4 sDefaultBackgroundColor; - static BOOL sKeyboardMode; - - BOOL mAlwaysShowMenu; - - LLUIColor mBackgroundColor; - BOOL mBgVisible; - LLHandle<LLView> mParentMenuItem; - LLUIString mLabel; - BOOL mDropShadowed; // Whether to drop shadow - bool mHasSelection; - LLFrameTimer mFadeTimer; - LLTimer mScrollItemsTimer; - BOOL mTornOff; - class LLMenuItemTearOffGL* mTearOffItem; - class LLMenuItemBranchGL* mSpilloverBranch; - LLMenuGL* mSpilloverMenu; - KEY mJumpKey; - BOOL mCreateJumpKeys; - S32 mShortcutPad; - bool mResetScrollPositionOnShow; + static LLColor4 sDefaultBackgroundColor; + static BOOL sKeyboardMode; + + BOOL mAlwaysShowMenu; + + LLUIColor mBackgroundColor; + BOOL mBgVisible; + LLHandle<LLView> mParentMenuItem; + LLUIString mLabel; + BOOL mDropShadowed; // Whether to drop shadow + bool mHasSelection; + LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; + BOOL mTornOff; + class LLMenuItemTearOffGL* mTearOffItem; + class LLMenuItemBranchGL* mSpilloverBranch; + LLMenuGL* mSpilloverMenu; + KEY mJumpKey; + BOOL mCreateJumpKeys; + S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -637,61 +637,61 @@ private: class LLMenuItemBranchGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Optional<LLMenuGL*> branch; - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Optional<LLMenuGL*> branch; + }; protected: - LLMenuItemBranchGL(const Params&); - friend class LLUICtrlFactory; + LLMenuItemBranchGL(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMenuItemBranchGL(); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual ~LLMenuItemBranchGL(); - virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - // check if we've used these accelerators already - virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); + virtual bool hasAccelerator(const KEY &key, const MASK &mask) const; + virtual BOOL handleAcceleratorKey(KEY key, MASK mask); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // check if we've used these accelerators already + virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp); - virtual void onCommit( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual void onCommit( void ); - // set the hover status (called by it's menu) and if the object is - // active. This is used for behavior transfer. - virtual void setHighlight( BOOL highlight ); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); + // set the hover status (called by it's menu) and if the object is + // active. This is used for behavior transfer. + virtual void setHighlight( BOOL highlight ); - virtual BOOL isActive() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL isOpen() const; + virtual BOOL isActive() const; - LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } + virtual BOOL isOpen() const; - virtual void updateBranchParent( LLView* parentp ); + LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); } - // LLView Functionality - virtual void onVisibilityChange( BOOL curVisibilityIn ); + virtual void updateBranchParent( LLView* parentp ); - virtual void draw(); + // LLView Functionality + virtual void onVisibilityChange( BOOL curVisibilityIn ); - virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } + virtual void draw(); - virtual void openMenu(); + virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); } - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual void openMenu(); + + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; private: - LLHandle<LLView> mBranchHandle; + LLHandle<LLView> mBranchHandle; }; // end class LLMenuItemBranchGL @@ -704,44 +704,44 @@ class LLContextMenu : public LLMenuGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> - { - Params() - { - changeDefault(visible, false); - } - }; + struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> + { + Params() + { + changeDefault(visible, false); + } + }; protected: - LLContextMenu(const Params& p); - friend class LLUICtrlFactory; + LLContextMenu(const Params& p); + friend class LLUICtrlFactory; public: - virtual ~LLContextMenu() {} + virtual ~LLContextMenu() {} + + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible (BOOL visible); - // LLView Functionality - // can't set visibility directly, must call show or hide - virtual void setVisible (BOOL visible); - - virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); - virtual void hide (); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); + virtual void hide (); - virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp ( S32 x, S32 y, MASK mask ); - virtual bool addChild (LLView* view, S32 tab_group = 0); + virtual bool addChild (LLView* view, S32 tab_group = 0); - LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } + LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } - LLView* getSpawningView() const { return mSpawningViewHandle.get(); } - void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; } protected: - BOOL mHoveredAnyItem; - LLMenuItemGL* mHoverItem; - LLRootHandle<LLContextMenu> mHandle; - LLHandle<LLView> mSpawningViewHandle; + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; + LLRootHandle<LLContextMenu> mHandle; + LLHandle<LLView> mSpawningViewHandle; }; //----------------------------------------------------------------------------- @@ -751,28 +751,28 @@ protected: class LLContextMenuBranch : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - { - Mandatory<LLContextMenu*> branch; - }; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + { + Mandatory<LLContextMenu*> branch; + }; - LLContextMenuBranch(const Params&); + LLContextMenuBranch(const Params&); - virtual ~LLContextMenuBranch(); + virtual ~LLContextMenuBranch(); - // called to rebuild the draw label - virtual void buildDrawLabel( void ); + // called to rebuild the draw label + virtual void buildDrawLabel( void ); - // onCommit() - do the primary funcationality of the menu item. - virtual void onCommit( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); - LLContextMenu* getBranch() { return mBranch.get(); } - void setHighlight( BOOL highlight ); + LLContextMenu* getBranch() { return mBranch.get(); } + void setHighlight( BOOL highlight ); protected: - void showSubMenu(); + void showSubMenu(); - LLHandle<LLContextMenu> mBranch; + LLHandle<LLContextMenu> mBranch; }; @@ -785,42 +785,42 @@ protected: class LLMenuBarGL : public LLMenuGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> - {}; - LLMenuBarGL( const Params& p ); - virtual ~LLMenuBarGL(); + struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> + {}; + LLMenuBarGL( const Params& p ); + virtual ~LLMenuBarGL(); - /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleJumpKey(KEY key); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleJumpKey(KEY key); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL jumpKeysActive(); + /*virtual*/ void draw(); + /*virtual*/ BOOL jumpKeysActive(); - // add a vertical separator to this menu - virtual BOOL addSeparator(); + // add a vertical separator to this menu + virtual BOOL addSeparator(); - // LLView Functionality - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + // LLView Functionality + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - // Returns x position of rightmost child, usually Help menu - S32 getRightmostMenuEdge(); + // Returns x position of rightmost child, usually Help menu + S32 getRightmostMenuEdge(); - void resetMenuTrigger() { mAltKeyTrigger = FALSE; } + void resetMenuTrigger() { mAltKeyTrigger = FALSE; } private: - // add a menu - this will create a drop down menu. - virtual BOOL appendMenu( LLMenuGL* menu ); - // rearrange the child rects so they fit the shape of the menu - // bar. - virtual void arrange( void ); + // add a menu - this will create a drop down menu. + virtual BOOL appendMenu( LLMenuGL* menu ); + // rearrange the child rects so they fit the shape of the menu + // bar. + virtual void arrange( void ); - void checkMenuTrigger(); + void checkMenuTrigger(); - std::list <LLMenuKeyboardBinding*> mAccelerators; - BOOL mAltKeyTrigger; + std::list <LLMenuKeyboardBinding*> mAccelerators; + BOOL mAltKeyTrigger; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -831,39 +831,39 @@ private: class LLMenuHolderGL : public LLPanel { public: - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - {}; - LLMenuHolderGL(const Params& p); - virtual ~LLMenuHolderGL() {} + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + {}; + LLMenuHolderGL(const Params& p); + virtual ~LLMenuHolderGL() {} - virtual BOOL hideMenus(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - void setCanHide(BOOL can_hide) { mCanHide = can_hide; } + virtual BOOL hideMenus(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + void setCanHide(BOOL can_hide) { mCanHide = can_hide; } - // LLView functionality - virtual void draw(); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + // LLView functionality + virtual void draw(); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - // Close context menus on right mouse up not handled by menus. - /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + // Close context menus on right mouse up not handled by menus. + /*virtual*/ BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - virtual const LLRect getMenuRect() const { return getLocalRect(); } - LLView*const getVisibleMenu() const; - virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual const LLRect getMenuRect() const { return getLocalRect(); } + LLView*const getVisibleMenu() const; + virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} - static void setActivatedItem(LLMenuItemGL* item); + static void setActivatedItem(LLMenuItemGL* item); - // Need to detect if mouse-up after context menu spawn has moved. - // If not, need to keep the menu up. - static LLCoordGL sContextMenuSpawnPos; + // Need to detect if mouse-up after context menu spawn has moved. + // If not, need to keep the menu up. + static LLCoordGL sContextMenuSpawnPos; private: - static LLHandle<LLView> sItemLastSelectedHandle; - static LLFrameTimer sItemActivationTimer; + static LLHandle<LLView> sItemLastSelectedHandle; + static LLFrameTimer sItemActivationTimer; - BOOL mCanHide; + BOOL mCanHide; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -875,26 +875,26 @@ private: class LLTearOffMenu : public LLFloater { public: - static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu(); + static LLTearOffMenu* create(LLMenuGL* menup); + virtual ~LLTearOffMenu(); - virtual void draw(void); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void translate(S32 x, S32 y); + virtual void draw(void); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual void translate(S32 x, S32 y); - void updateSize(); + void updateSize(); private: - LLTearOffMenu(LLMenuGL* menup); - - void closeTearOff(); - - LLView* mOldParent; - LLMenuGL* mMenu; - S32 mTargetHeight; + LLTearOffMenu(LLMenuGL* menup); + + void closeTearOff(); + + LLView* mOldParent; + LLMenuGL* mMenu; + S32 mTargetHeight; bool mQuitRequested; }; @@ -907,16 +907,16 @@ private: class LLMenuItemTearOffGL : public LLMenuItemGL { public: - struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> - {}; + struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params> + {}; + + LLMenuItemTearOffGL( const Params& ); - LLMenuItemTearOffGL( const Params& ); - - virtual void onCommit(void); - virtual void draw(void); - virtual U32 getNominalHeight() const; + virtual void onCommit(void); + virtual void draw(void); + virtual U32 getNominalHeight() const; - LLFloater* getParentFloater(); + LLFloater* getParentFloater(); }; @@ -924,13 +924,13 @@ public: class LLEditMenuHandlerMgr { public: - LLEditMenuHandlerMgr& getInstance() { - static LLEditMenuHandlerMgr instance; - return instance; - } - virtual ~LLEditMenuHandlerMgr() {} + LLEditMenuHandlerMgr& getInstance() { + static LLEditMenuHandlerMgr instance; + return instance; + } + virtual ~LLEditMenuHandlerMgr() {} private: - LLEditMenuHandlerMgr() {}; + LLEditMenuHandlerMgr() {}; }; @@ -939,40 +939,40 @@ private: class view_listener_t : public boost::signals2::trackable { public: - virtual bool handleEvent(const LLSD& userdata) = 0; - view_listener_t() { sListeners.insert(this); } - virtual ~view_listener_t() { sListeners.erase(this); } - - static void addEnable(view_listener_t* listener, const std::string& name) - { - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addCommit(view_listener_t* listener, const std::string& name) - { - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); - } - - static void addMenu(view_listener_t* listener, const std::string& name) - { - // For now, add to both click and enable registries - addEnable(listener, name); - addCommit(listener, name); - } - - static void cleanup() - { - listener_vector_t listeners(sListeners.begin(), sListeners.end()); - sListeners.clear(); - - std::for_each(listeners.begin(), listeners.end(), DeletePointer()); - listeners.clear(); - } + virtual bool handleEvent(const LLSD& userdata) = 0; + view_listener_t() { sListeners.insert(this); } + virtual ~view_listener_t() { sListeners.erase(this); } + + static void addEnable(view_listener_t* listener, const std::string& name) + { + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addCommit(view_listener_t* listener, const std::string& name) + { + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2)); + } + + static void addMenu(view_listener_t* listener, const std::string& name) + { + // For now, add to both click and enable registries + addEnable(listener, name); + addCommit(listener, name); + } + + static void cleanup() + { + listener_vector_t listeners(sListeners.begin(), sListeners.end()); + sListeners.clear(); + + std::for_each(listeners.begin(), listeners.end(), DeletePointer()); + listeners.clear(); + } private: - typedef std::set<view_listener_t*> listener_map_t; - typedef std::vector<view_listener_t*> listener_vector_t; - static listener_map_t sListeners; + typedef std::set<view_listener_t*> listener_map_t; + typedef std::vector<view_listener_t*> listener_vector_t; + static listener_map_t sListeners; }; #endif // LL_LLMENUGL_H diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp index 3e5978eb59..eac43900f6 100644 --- a/indra/llui/llmodaldialog.cpp +++ b/indra/llui/llmodaldialog.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmodaldialog.cpp * @brief LLModalDialog base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,77 +39,79 @@ std::list<LLModalDialog*> LLModalDialog::sModalStack; LLModalDialog::LLModalDialog( const LLSD& key, BOOL modal ) - : LLFloater(key), - mModal( modal ) + : LLFloater(key), + mModal( modal ) { - if (modal) - { - setCanMinimize(FALSE); - setCanClose(FALSE); - } - setVisible( FALSE ); - setBackgroundVisible(TRUE); - setBackgroundOpaque(TRUE); - centerOnScreen(); // default position - mCloseSignal.connect(boost::bind(&LLModalDialog::stopModal, this)); + if (modal) + { + setCanMinimize(FALSE); + setCanClose(FALSE); + } + setVisible( FALSE ); + setBackgroundVisible(TRUE); + setBackgroundOpaque(TRUE); + centerOnScreen(); // default position + mCloseSignal.connect(boost::bind(&LLModalDialog::stopModal, this)); } LLModalDialog::~LLModalDialog() { - // don't unlock focus unless we have it - if (gFocusMgr.childHasKeyboardFocus(this)) - { - gFocusMgr.unlockFocus(); - } - - std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); - if (iter != sModalStack.end()) - { - LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL; - } + // don't unlock focus unless we have it + if (gFocusMgr.childHasKeyboardFocus(this)) + { + gFocusMgr.unlockFocus(); + } + + std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); + if (iter != sModalStack.end()) + { + LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL; + } + + LLUI::getInstance()->removePopup(this); } // virtual BOOL LLModalDialog::postBuild() { - return LLFloater::postBuild(); + return LLFloater::postBuild(); } // virtual void LLModalDialog::openFloater(const LLSD& key) { - // SJB: Hack! Make sure we don't ever host a modal dialog - LLMultiFloater* thost = LLFloater::getFloaterHost(); - LLFloater::setFloaterHost(NULL); - LLFloater::openFloater(key); - LLFloater::setFloaterHost(thost); + // SJB: Hack! Make sure we don't ever host a modal dialog + LLMultiFloater* thost = LLFloater::getFloaterHost(); + LLFloater::setFloaterHost(NULL); + LLFloater::openFloater(key); + LLFloater::setFloaterHost(thost); } void LLModalDialog::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLFloater::reshape(width, height, called_from_parent); - centerOnScreen(); + LLFloater::reshape(width, height, called_from_parent); + centerOnScreen(); } // virtual void LLModalDialog::onOpen(const LLSD& key) { - if (mModal) - { - // If Modal, Hide the active modal dialog - if (!sModalStack.empty()) - { - LLModalDialog* front = sModalStack.front(); + if (mModal) + { + // If Modal, Hide the active modal dialog + if (!sModalStack.empty()) + { + LLModalDialog* front = sModalStack.front(); if (front != this) { front->setVisible(FALSE); } - } - - // This is a modal dialog. It sucks up all mouse and keyboard operations. - gFocusMgr.setMouseCapture( this ); - LLUI::getInstance()->addPopup(this); - setFocus(TRUE); + } + + // This is a modal dialog. It sucks up all mouse and keyboard operations. + gFocusMgr.setMouseCapture( this ); + LLUI::getInstance()->addPopup(this); + setFocus(TRUE); std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); if (iter != sModalStack.end()) @@ -119,229 +121,228 @@ void LLModalDialog::onOpen(const LLSD& key) } sModalStack.push_front(this); - } + } } void LLModalDialog::stopModal() { - gFocusMgr.unlockFocus(); - gFocusMgr.releaseFocusIfNeeded( this ); - - if (mModal) - { - std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); - if (iter != sModalStack.end()) - { - sModalStack.erase(iter); - } - else - { - LL_WARNS() << "LLModalDialog::stopModal not in list!" << LL_ENDL; - } - } - if (!sModalStack.empty()) - { - LLModalDialog* front = sModalStack.front(); - front->setVisible(TRUE); - } + gFocusMgr.unlockFocus(); + gFocusMgr.releaseFocusIfNeeded( this ); + + if (mModal) + { + std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); + if (iter != sModalStack.end()) + { + sModalStack.erase(iter); + } + else + { + LL_WARNS() << "LLModalDialog::stopModal not in list!" << LL_ENDL; + } + } + if (!sModalStack.empty()) + { + LLModalDialog* front = sModalStack.front(); + front->setVisible(TRUE); + } } void LLModalDialog::setVisible( BOOL visible ) { - if (mModal) - { - if( visible ) - { - // This is a modal dialog. It sucks up all mouse and keyboard operations. - gFocusMgr.setMouseCapture( this ); - - // The dialog view is a root view - LLUI::getInstance()->addPopup(this); - setFocus( TRUE ); - } - else - { - gFocusMgr.releaseFocusIfNeeded( this ); - } - } - - LLFloater::setVisible( visible ); + if (mModal) + { + if( visible ) + { + // This is a modal dialog. It sucks up all mouse and keyboard operations. + gFocusMgr.setMouseCapture( this ); + + // The dialog view is a root view + LLUI::getInstance()->addPopup(this); + setFocus( TRUE ); + } + else + { + gFocusMgr.releaseFocusIfNeeded( this ); + } + } + + LLFloater::setVisible( visible ); } BOOL LLModalDialog::handleMouseDown(S32 x, S32 y, MASK mask) { - LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu(); - if (popup_menu != NULL) - { - S32 mx, my; - LLUI::getInstance()->getMousePositionScreen(&mx, &my); - LLRect menu_screen_rc = popup_menu->calcScreenRect(); - if(!menu_screen_rc.pointInRect(mx, my)) - { - LLMenuGL::sMenuContainer->hideMenus(); - } - } - - if (mModal) - { - if (!LLFloater::handleMouseDown(x, y, mask)) - { - // Click was outside the panel - make_ui_sound("UISndInvalidOp"); - } - } - else - { - LLFloater::handleMouseDown(x, y, mask); - } - - - return TRUE; + LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu(); + if (popup_menu != NULL) + { + S32 mx, my; + LLUI::getInstance()->getMousePositionScreen(&mx, &my); + LLRect menu_screen_rc = popup_menu->calcScreenRect(); + if(!menu_screen_rc.pointInRect(mx, my)) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + } + + if (mModal) + { + if (!LLFloater::handleMouseDown(x, y, mask)) + { + // Click was outside the panel + make_ui_sound("UISndInvalidOp"); + } + } + else + { + LLFloater::handleMouseDown(x, y, mask); + } + + + return TRUE; } -BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask) -{ - if( childrenHandleHover(x, y, mask) == NULL ) - { - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; - } - - LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu(); - if (popup_menu != NULL) - { - S32 mx, my; - LLUI::getInstance()->getMousePositionScreen(&mx, &my); - LLRect menu_screen_rc = popup_menu->calcScreenRect(); - if(menu_screen_rc.pointInRect(mx, my)) - { - S32 local_x = mx - popup_menu->getRect().mLeft; - S32 local_y = my - popup_menu->getRect().mBottom; - popup_menu->handleHover(local_x, local_y, mask); - gFocusMgr.setMouseCapture(NULL); - } - } - - return TRUE; +BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask) +{ + if( childrenHandleHover(x, y, mask) == NULL ) + { + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; + } + + LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu(); + if (popup_menu != NULL) + { + S32 mx, my; + LLUI::getInstance()->getMousePositionScreen(&mx, &my); + LLRect menu_screen_rc = popup_menu->calcScreenRect(); + if(menu_screen_rc.pointInRect(mx, my)) + { + S32 local_x = mx - popup_menu->getRect().mLeft; + S32 local_y = my - popup_menu->getRect().mBottom; + popup_menu->handleHover(local_x, local_y, mask); + gFocusMgr.setMouseCapture(NULL); + } + } + + return TRUE; } BOOL LLModalDialog::handleMouseUp(S32 x, S32 y, MASK mask) { - childrenHandleMouseUp(x, y, mask); - return TRUE; + childrenHandleMouseUp(x, y, mask); + return TRUE; } BOOL LLModalDialog::handleScrollWheel(S32 x, S32 y, S32 clicks) { - childrenHandleScrollWheel(x, y, clicks); - return TRUE; + childrenHandleScrollWheel(x, y, clicks); + return TRUE; } BOOL LLModalDialog::handleDoubleClick(S32 x, S32 y, MASK mask) { - if (!LLFloater::handleDoubleClick(x, y, mask)) - { - // Click outside the panel - make_ui_sound("UISndInvalidOp"); - } - return TRUE; + if (!LLFloater::handleDoubleClick(x, y, mask)) + { + // Click outside the panel + make_ui_sound("UISndInvalidOp"); + } + return TRUE; } BOOL LLModalDialog::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLMenuGL::sMenuContainer->hideMenus(); - childrenHandleRightMouseDown(x, y, mask); - return TRUE; + LLMenuGL::sMenuContainer->hideMenus(); + childrenHandleRightMouseDown(x, y, mask); + return TRUE; } BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask ) { - LLFloater::handleKeyHere(key, mask ); - - if (mModal) - { - // Suck up all keystokes except CTRL-Q. - BOOL is_quit = ('Q' == key) && (MASK_CONTROL == mask); - return !is_quit; - } - else - { - // don't process escape key until message box has been on screen a minimal amount of time - // to avoid accidentally destroying the message box when user is hitting escape at the time it appears - BOOL enough_time_elapsed = mVisibleTime.getElapsedTimeF32() > 1.0f; - if (enough_time_elapsed && key == KEY_ESCAPE) - { - closeFloater(); - return TRUE; - } - return FALSE; - } + LLFloater::handleKeyHere(key, mask ); + + if (mModal) + { + // Suck up all keystokes except CTRL-Q. + BOOL is_quit = ('Q' == key) && (MASK_CONTROL == mask); + return !is_quit; + } + else + { + // don't process escape key until message box has been on screen a minimal amount of time + // to avoid accidentally destroying the message box when user is hitting escape at the time it appears + BOOL enough_time_elapsed = mVisibleTime.getElapsedTimeF32() > 1.0f; + if (enough_time_elapsed && key == KEY_ESCAPE) + { + closeFloater(); + return TRUE; + } + return FALSE; + } } // virtual void LLModalDialog::draw() { - static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); - static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0); + static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); + + gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0, + shadow_color, DROP_SHADOW_FLOATER); - gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0, - shadow_color, shadow_lines); + LLFloater::draw(); - LLFloater::draw(); - - // Focus retrieval moved to LLFloaterView::refresh() + // Focus retrieval moved to LLFloaterView::refresh() } void LLModalDialog::centerOnScreen() { - LLVector2 window_size = LLUI::getInstance()->getWindowSize(); - centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); + LLVector2 window_size = LLUI::getInstance()->getWindowSize(); + centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); } -// static +// static void LLModalDialog::onAppFocusLost() { - if( !sModalStack.empty() ) - { - LLModalDialog* instance = LLModalDialog::sModalStack.front(); - if( gFocusMgr.childHasMouseCapture( instance ) ) - { - gFocusMgr.setMouseCapture( NULL ); - } - - instance->setFocus(FALSE); - } + if( !sModalStack.empty() ) + { + LLModalDialog* instance = LLModalDialog::sModalStack.front(); + if( gFocusMgr.childHasMouseCapture( instance ) ) + { + gFocusMgr.setMouseCapture( NULL ); + } + + instance->setFocus(FALSE); + } } -// static +// static void LLModalDialog::onAppFocusGained() { - if( !sModalStack.empty() ) - { - LLModalDialog* instance = LLModalDialog::sModalStack.front(); + if( !sModalStack.empty() ) + { + LLModalDialog* instance = LLModalDialog::sModalStack.front(); - // This is a modal dialog. It sucks up all mouse and keyboard operations. - gFocusMgr.setMouseCapture( instance ); - instance->setFocus(TRUE); - LLUI::getInstance()->addPopup(instance); + // This is a modal dialog. It sucks up all mouse and keyboard operations. + gFocusMgr.setMouseCapture( instance ); + instance->setFocus(TRUE); + LLUI::getInstance()->addPopup(instance); - instance->centerOnScreen(); - } + instance->centerOnScreen(); + } } void LLModalDialog::shutdownModals() { - // This method is only for use during app shutdown. ~LLModalDialog() - // checks sModalStack, and if the dialog instance is still there, it - // crumps with "Attempt to delete dialog while still in sModalStack!" But - // at app shutdown, all bets are off. If the user asks to shut down the - // app, we shouldn't have to care WHAT's open. Put differently, if a modal - // dialog is so crucial that we can't let the user terminate until s/he - // addresses it, we should reject a termination request. The current state - // of affairs is that we accept it, but then produce an LL_ERRS() popup that - // simply makes our software look unreliable. - sModalStack.clear(); + // This method is only for use during app shutdown. ~LLModalDialog() + // checks sModalStack, and if the dialog instance is still there, it + // crumps with "Attempt to delete dialog while still in sModalStack!" But + // at app shutdown, all bets are off. If the user asks to shut down the + // app, we shouldn't have to care WHAT's open. Put differently, if a modal + // dialog is so crucial that we can't let the user terminate until s/he + // addresses it, we should reject a termination request. The current state + // of affairs is that we accept it, but then produce an LL_ERRS() popup that + // simply makes our software look unreliable. + sModalStack.clear(); } diff --git a/indra/llui/llmodaldialog.h b/indra/llui/llmodaldialog.h index f81273b96a..bf729c61bf 100644 --- a/indra/llui/llmodaldialog.h +++ b/indra/llui/llmodaldialog.h @@ -1,25 +1,25 @@ -/** +/** * @file llmodaldialog.h * @brief LLModalDialog base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,45 +39,45 @@ class LLModalDialog; class LLModalDialog : public LLFloater { public: - LLModalDialog( const LLSD& key, BOOL modal = true ); - virtual ~LLModalDialog(); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void openFloater(const LLSD& key = LLSD()); - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); - - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ void draw(); - - BOOL isModal() const { return mModal; } - void stopModal(); - - static void onAppFocusLost(); - static void onAppFocusGained(); - - static S32 activeCount() { return sModalStack.size(); } - static void shutdownModals(); + LLModalDialog( const LLSD& key, BOOL modal = true ); + virtual ~LLModalDialog(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void openFloater(const LLSD& key = LLSD()); + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); + + /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ void draw(); + + BOOL isModal() const { return mModal; } + void stopModal(); + + static void onAppFocusLost(); + static void onAppFocusGained(); + + static S32 activeCount() { return sModalStack.size(); } + static void shutdownModals(); protected: - void centerOnScreen(); + void centerOnScreen(); private: - - LLFrameTimer mVisibleTime; - const BOOL mModal; - static std::list<LLModalDialog*> sModalStack; // Top of stack is currently being displayed + LLFrameTimer mVisibleTime; + const BOOL mModal; + + static std::list<LLModalDialog*> sModalStack; // Top of stack is currently being displayed }; #endif // LL_LLMODALDIALOG_H diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index d1a597511e..17f24a0f87 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmultifloater.cpp * @brief LLFloater that hosts other floaters * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,91 +37,91 @@ // LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params) - : LLFloater(key), - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(TRUE), - mOrigMinWidth(params.min_width), - mOrigMinHeight(params.min_height) + : LLFloater(key), + mTabContainer(NULL), + mTabPos(LLTabContainer::TOP), + mAutoResize(TRUE), + mOrigMinWidth(params.min_width), + mOrigMinHeight(params.min_height) { } void LLMultiFloater::buildTabContainer() { - const LLFloater::Params& default_params = LLFloater::getDefaultParams(); - S32 floater_header_size = default_params.header_height; - - LLTabContainer::Params p; - p.name(std::string("Preview Tabs")); - p.rect(LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - floater_header_size, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0)); - p.tab_position(mTabPos); - p.follows.flags(FOLLOWS_ALL); - p.commit_callback.function(boost::bind(&LLMultiFloater::onTabSelected, this)); - - mTabContainer = LLUICtrlFactory::create<LLTabContainer>(p); - addChild(mTabContainer); - - if (isResizable()) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } + const LLFloater::Params& default_params = LLFloater::getDefaultParams(); + S32 floater_header_size = default_params.header_height; + + LLTabContainer::Params p; + p.name(std::string("Preview Tabs")); + p.rect(LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - floater_header_size, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0)); + p.tab_position(mTabPos); + p.follows.flags(FOLLOWS_ALL); + p.commit_callback.function(boost::bind(&LLMultiFloater::onTabSelected, this)); + + mTabContainer = LLUICtrlFactory::create<LLTabContainer>(p); + addChild(mTabContainer); + + if (isResizable()) + { + mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); + } } void LLMultiFloater::onClose(bool app_quitting) { - if(isMinimized()) - { - setMinimized(FALSE); - } - LLFloater::onClose(app_quitting); + if(isMinimized()) + { + setMinimized(FALSE); + } + LLFloater::onClose(app_quitting); } void LLMultiFloater::draw() { - if (mTabContainer->getTabCount() == 0) - { - //RN: could this potentially crash in draw hierarchy? - closeFloater(); - } - else - { - LLFloater::draw(); - } + if (mTabContainer->getTabCount() == 0) + { + //RN: could this potentially crash in draw hierarchy? + closeFloater(); + } + else + { + LLFloater::draw(); + } } BOOL LLMultiFloater::closeAllFloaters() { - S32 tabToClose = 0; - S32 lastTabCount = mTabContainer->getTabCount(); - while (tabToClose < mTabContainer->getTabCount()) - { - LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose); - first_floater->closeFloater(); - if(lastTabCount == mTabContainer->getTabCount()) - { - //Tab did not actually close, possibly due to a pending Save Confirmation dialog.. - //so try and close the next one in the list... - tabToClose++; - } - else - { - //Tab closed ok. - lastTabCount = mTabContainer->getTabCount(); - } - } - if( mTabContainer->getTabCount() != 0 ) - return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE. - return TRUE; //else all tabs were successfully closed... + S32 tabToClose = 0; + S32 lastTabCount = mTabContainer->getTabCount(); + while (tabToClose < mTabContainer->getTabCount()) + { + LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose); + first_floater->closeFloater(); + if(lastTabCount == mTabContainer->getTabCount()) + { + //Tab did not actually close, possibly due to a pending Save Confirmation dialog.. + //so try and close the next one in the list... + tabToClose++; + } + else + { + //Tab closed ok. + lastTabCount = mTabContainer->getTabCount(); + } + } + if( mTabContainer->getTabCount() != 0 ) + return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE. + return TRUE; //else all tabs were successfully closed... } void LLMultiFloater::growToFit(S32 content_width, S32 content_height) { - static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0); - const LLFloater::Params& default_params = LLFloater::getDefaultParams(); - S32 floater_header_size = default_params.header_height; - S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size; - S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2); - S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height); + static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0); + const LLFloater::Params& default_params = LLFloater::getDefaultParams(); + S32 floater_header_size = default_params.header_height; + S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size; + S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2); + S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height); if (isMinimized()) { @@ -129,13 +129,13 @@ void LLMultiFloater::growToFit(S32 content_width, S32 content_height) newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height); setExpandedRect(newrect); } - else - { - S32 old_height = getRect().getHeight(); - reshape(new_width, new_height); - // keep top left corner in same position - translate(0, old_height - new_height); - } + else + { + S32 old_height = getRect().getHeight(); + reshape(new_width, new_height); + // keep top left corner in same position + translate(0, old_height - new_height); + } } /** @@ -151,372 +151,372 @@ void LLMultiFloater::growToFit(S32 content_width, S32 content_height) **/ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point) { - if (!floaterp) - { - return; - } - - if (!mTabContainer) - { - LL_ERRS() << "Tab Container used without having been initialized." << LL_ENDL; - return; - } - - if (floaterp->getHost() == this) - { - // already hosted by me, remove - // do this so we get updated title, etc. - mFloaterDataMap.erase(floaterp->getHandle()); - mTabContainer->removeTabPanel(floaterp); - } - else if (floaterp->getHost()) - { - // floaterp is hosted by somebody else and - // this is adding it, so remove it from its old host - floaterp->getHost()->removeFloater(floaterp); - } - else if (floaterp->getParent() == gFloaterView) - { - // rehost preview floater as child panel - gFloaterView->removeChild(floaterp); - } - - // store original configuration - LLFloaterData floater_data; - floater_data.mWidth = floaterp->getRect().getWidth(); - floater_data.mHeight = floaterp->getRect().getHeight(); - floater_data.mCanMinimize = floaterp->isMinimizeable(); - floater_data.mCanResize = floaterp->isResizable(); + if (!floaterp) + { + return; + } + + if (!mTabContainer) + { + LL_ERRS() << "Tab Container used without having been initialized." << LL_ENDL; + return; + } + + if (floaterp->getHost() == this) + { + // already hosted by me, remove + // do this so we get updated title, etc. + mFloaterDataMap.erase(floaterp->getHandle()); + mTabContainer->removeTabPanel(floaterp); + } + else if (floaterp->getHost()) + { + // floaterp is hosted by somebody else and + // this is adding it, so remove it from its old host + floaterp->getHost()->removeFloater(floaterp); + } + else if (floaterp->getParent() == gFloaterView) + { + // rehost preview floater as child panel + gFloaterView->removeChild(floaterp); + } + + // store original configuration + LLFloaterData floater_data; + floater_data.mWidth = floaterp->getRect().getWidth(); + floater_data.mHeight = floaterp->getRect().getHeight(); + floater_data.mCanMinimize = floaterp->isMinimizeable(); + floater_data.mCanResize = floaterp->isResizable(); floater_data.mSaveRect = floaterp->mSaveRect; - // remove minimize and close buttons - floaterp->setCanMinimize(FALSE); - floaterp->setCanResize(FALSE); - floaterp->setCanDrag(FALSE); - floaterp->mSaveRect = FALSE; - floaterp->storeRectControl(); - // avoid double rendering of floater background (makes it more opaque) - floaterp->setBackgroundVisible(FALSE); - - if (mAutoResize) - { - growToFit(floater_data.mWidth, floater_data.mHeight); - } - - //add the panel, add it to proper maps - mTabContainer->addTabPanel( - LLTabContainer::TabPanelParams() - .panel(floaterp) - .label(floaterp->getShortTitle()) - .insert_at(insertion_point)); - mFloaterDataMap[floaterp->getHandle()] = floater_data; - - updateResizeLimits(); - - if ( select_added_floater ) - { - mTabContainer->selectTabPanel(floaterp); - } - else - { - // reassert visible tab (hiding new floater if necessary) - mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex()); - } - - floaterp->setHost(this); - if (isMinimized()) - { - floaterp->setVisible(FALSE); - } - - // Tabs sometimes overlap resize handle - moveResizeHandlesToFront(); + // remove minimize and close buttons + floaterp->setCanMinimize(FALSE); + floaterp->setCanResize(FALSE); + floaterp->setCanDrag(FALSE); + floaterp->mSaveRect = FALSE; + floaterp->storeRectControl(); + // avoid double rendering of floater background (makes it more opaque) + floaterp->setBackgroundVisible(FALSE); + + if (mAutoResize) + { + growToFit(floater_data.mWidth, floater_data.mHeight); + } + + //add the panel, add it to proper maps + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams() + .panel(floaterp) + .label(floaterp->getShortTitle()) + .insert_at(insertion_point)); + mFloaterDataMap[floaterp->getHandle()] = floater_data; + + updateResizeLimits(); + + if ( select_added_floater ) + { + mTabContainer->selectTabPanel(floaterp); + } + else + { + // reassert visible tab (hiding new floater if necessary) + mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex()); + } + + floaterp->setHost(this); + if (isMinimized()) + { + floaterp->setVisible(FALSE); + } + + // Tabs sometimes overlap resize handle + moveResizeHandlesToFront(); } void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp) { - S32 index = mTabContainer->getIndexForPanel(floaterp); - if (index != -1) - { - mTabContainer->setPanelTitle(index, floaterp->getShortTitle()); - } + S32 index = mTabContainer->getIndexForPanel(floaterp); + if (index != -1) + { + mTabContainer->setPanelTitle(index, floaterp->getShortTitle()); + } } /** - BOOL selectFloater(LLFloater* floaterp) + BOOL selectFloater(LLFloater* floaterp) - If the LLFloater pointed to by floaterp is hosted by this, - then its tab is selected and returns true. Otherwise returns false. + If the LLFloater pointed to by floaterp is hosted by this, + then its tab is selected and returns true. Otherwise returns false. - Affects: mTabContainer + Affects: mTabContainer **/ BOOL LLMultiFloater::selectFloater(LLFloater* floaterp) { - return mTabContainer->selectTabPanel(floaterp); + return mTabContainer->selectTabPanel(floaterp); } // virtual void LLMultiFloater::selectNextFloater() { - mTabContainer->selectNextTab(); + mTabContainer->selectNextTab(); } // virtual void LLMultiFloater::selectPrevFloater() { - mTabContainer->selectPrevTab(); + mTabContainer->selectPrevTab(); } void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point) { - if(!floaterp) return; - // we won't select a panel that already is selected - // it is hard to do this internally to tab container - // as tab selection is handled via index and the tab at a given - // index might have changed - if (floaterp != mTabContainer->getCurrentPanel() && - !mTabContainer->selectTabPanel(floaterp)) - { - addFloater(floaterp, TRUE, insertion_point); - } + if(!floaterp) return; + // we won't select a panel that already is selected + // it is hard to do this internally to tab container + // as tab selection is handled via index and the tab at a given + // index might have changed + if (floaterp != mTabContainer->getCurrentPanel() && + !mTabContainer->selectTabPanel(floaterp)) + { + addFloater(floaterp, TRUE, insertion_point); + } } void LLMultiFloater::removeFloater(LLFloater* floaterp) { - if (!floaterp || floaterp->getHost() != this ) - return; - - floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle()); - if (found_data_it != mFloaterDataMap.end()) - { - LLFloaterData& floater_data = found_data_it->second; - floaterp->setCanMinimize(floater_data.mCanMinimize); - floaterp->mSaveRect = floater_data.mSaveRect; - if (!floater_data.mCanResize) - { - // restore original size - floaterp->reshape(floater_data.mWidth, floater_data.mHeight); - } - floaterp->setCanResize(floater_data.mCanResize); - mFloaterDataMap.erase(found_data_it); - } - mTabContainer->removeTabPanel(floaterp); - floaterp->setBackgroundVisible(TRUE); - floaterp->setCanDrag(TRUE); - floaterp->setHost(NULL); - floaterp->applyRectControl(); - - updateResizeLimits(); - - tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); + if (!floaterp || floaterp->getHost() != this ) + return; + + floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle()); + if (found_data_it != mFloaterDataMap.end()) + { + LLFloaterData& floater_data = found_data_it->second; + floaterp->setCanMinimize(floater_data.mCanMinimize); + floaterp->mSaveRect = floater_data.mSaveRect; + if (!floater_data.mCanResize) + { + // restore original size + floaterp->reshape(floater_data.mWidth, floater_data.mHeight); + } + floaterp->setCanResize(floater_data.mCanResize); + mFloaterDataMap.erase(found_data_it); + } + mTabContainer->removeTabPanel(floaterp); + floaterp->setBackgroundVisible(TRUE); + floaterp->setCanDrag(TRUE); + floaterp->setHost(NULL); + floaterp->applyRectControl(); + + updateResizeLimits(); + + tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); } void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) { - // default implementation does nothing + // default implementation does nothing } void LLMultiFloater::tabClose() { - if (mTabContainer->getTabCount() == 0) - { - // no more children, close myself - closeFloater(); - } + if (mTabContainer->getTabCount() == 0) + { + // no more children, close myself + closeFloater(); + } } void LLMultiFloater::setVisible(BOOL visible) { - // *FIX: shouldn't have to do this, fix adding to minimized multifloater - LLFloater::setVisible(visible); - - if (mTabContainer) - { - LLPanel* cur_floaterp = mTabContainer->getCurrentPanel(); - - if (cur_floaterp) - { - cur_floaterp->setVisible(visible); - } - - // if no tab selected, and we're being shown, - // select last tab to be added - if (visible && !cur_floaterp) - { - mTabContainer->selectLastTab(); - } - } + // *FIX: shouldn't have to do this, fix adding to minimized multifloater + LLFloater::setVisible(visible); + + if (mTabContainer) + { + LLPanel* cur_floaterp = mTabContainer->getCurrentPanel(); + + if (cur_floaterp) + { + cur_floaterp->setVisible(visible); + } + + // if no tab selected, and we're being shown, + // select last tab to be added + if (visible && !cur_floaterp) + { + mTabContainer->selectLastTab(); + } + } } BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask) { - if (key == 'W' && mask == MASK_CONTROL) - { - LLFloater* floater = getActiveFloater(); - // is user closeable and is system closeable - if (floater && floater->canClose() && floater->isCloseable()) - { - floater->closeFloater(); - - // EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W) - // bring back focus on tab container if there are any tab left - if(mTabContainer->getTabCount() > 0) - { - mTabContainer->setFocus(TRUE); - } - } - return TRUE; - } - - return LLFloater::handleKeyHere(key, mask); + if (key == 'W' && mask == MASK_CONTROL) + { + LLFloater* floater = getActiveFloater(); + // is user closeable and is system closeable + if (floater && floater->canClose() && floater->isCloseable()) + { + floater->closeFloater(); + + // EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W) + // bring back focus on tab container if there are any tab left + if(mTabContainer->getTabCount() > 0) + { + mTabContainer->setFocus(TRUE); + } + } + return TRUE; + } + + return LLFloater::handleKeyHere(key, mask); } bool LLMultiFloater::addChild(LLView* child, S32 tab_group) { - LLTabContainer* tab_container = dynamic_cast<LLTabContainer*>(child); - if (tab_container) - { - // store pointer to tab container - setTabContainer(tab_container); - } - - // then go ahead and add child as usual - return LLFloater::addChild(child, tab_group); + LLTabContainer* tab_container = dynamic_cast<LLTabContainer*>(child); + if (tab_container) + { + // store pointer to tab container + setTabContainer(tab_container); + } + + // then go ahead and add child as usual + return LLFloater::addChild(child, tab_group); } LLFloater* LLMultiFloater::getActiveFloater() { - return (LLFloater*)mTabContainer->getCurrentPanel(); + return (LLFloater*)mTabContainer->getCurrentPanel(); } -S32 LLMultiFloater::getFloaterCount() +S32 LLMultiFloater::getFloaterCount() { - return mTabContainer->getTabCount(); + return mTabContainer->getTabCount(); } /** - BOOL isFloaterFlashing(LLFloater* floaterp) + BOOL isFloaterFlashing(LLFloater* floaterp) - Returns true if the LLFloater pointed to by floaterp - is currently in a flashing state and is hosted by this. - False otherwise. + Returns true if the LLFloater pointed to by floaterp + is currently in a flashing state and is hosted by this. + False otherwise. - Requires: floaterp != NULL + Requires: floaterp != NULL **/ BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp) { - if ( floaterp && floaterp->getHost() == this ) - return mTabContainer->getTabPanelFlashing(floaterp); + if ( floaterp && floaterp->getHost() == this ) + return mTabContainer->getTabPanelFlashing(floaterp); - return FALSE; + return FALSE; } /** - BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing) + BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing) - Sets the current flashing state of the LLFloater pointed - to by floaterp to be the BOOL flashing if the LLFloater pointed - to by floaterp is hosted by this. + Sets the current flashing state of the LLFloater pointed + to by floaterp to be the BOOL flashing if the LLFloater pointed + to by floaterp is hosted by this. - Requires: floaterp != NULL + Requires: floaterp != NULL **/ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) { - if ( floaterp && floaterp->getHost() == this ) - mTabContainer->setTabPanelFlashing(floaterp, flashing); + if ( floaterp && floaterp->getHost() == this ) + mTabContainer->setTabPanelFlashing(floaterp, flashing); } void LLMultiFloater::onTabSelected() { - LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel()); - if (floaterp) - { - tabOpen(floaterp, true); - } + LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel()); + if (floaterp) + { + tabOpen(floaterp, true); + } } void LLMultiFloater::setCanResize(BOOL can_resize) { - LLFloater::setCanResize(can_resize); - if (!mTabContainer) return; - if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - else - { - mTabContainer->setRightTabBtnOffset(0); - } + LLFloater::setCanResize(can_resize); + if (!mTabContainer) return; + if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM) + { + mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); + } + else + { + mTabContainer->setRightTabBtnOffset(0); + } } BOOL LLMultiFloater::postBuild() { - mCloseSignal.connect(boost::bind(&LLMultiFloater::closeAllFloaters, this)); - - // remember any original xml minimum size - getResizeLimits(&mOrigMinWidth, &mOrigMinHeight); - - if (mTabContainer) - { - return TRUE; - } - - mTabContainer = getChild<LLTabContainer>("Preview Tabs"); - - setCanResize(mResizable); - return TRUE; + mCloseSignal.connect(boost::bind(&LLMultiFloater::closeAllFloaters, this)); + + // remember any original xml minimum size + getResizeLimits(&mOrigMinWidth, &mOrigMinHeight); + + if (mTabContainer) + { + return TRUE; + } + + mTabContainer = getChild<LLTabContainer>("Preview Tabs"); + + setCanResize(mResizable); + return TRUE; } void LLMultiFloater::updateResizeLimits() { - // initialize minimum size constraint to the original xml values. - S32 new_min_width = mOrigMinWidth; - S32 new_min_height = mOrigMinHeight; - - computeResizeLimits(new_min_width, new_min_height); - - setResizeLimits(new_min_width, new_min_height); - - S32 cur_height = getRect().getHeight(); - S32 new_width = llmax(getRect().getWidth(), new_min_width); - S32 new_height = llmax(getRect().getHeight(), new_min_height); - - if (isMinimized()) - { - const LLRect& expanded = getExpandedRect(); - LLRect newrect; - newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height)); - setExpandedRect(newrect); - } - else - { - reshape(new_width, new_height); - - // make sure upper left corner doesn't move - translate(0, cur_height - getRect().getHeight()); - - // make sure this window is visible on screen when it has been modified - // (tab added, etc) - gFloaterView->adjustToFitScreen(this, TRUE); - } + // initialize minimum size constraint to the original xml values. + S32 new_min_width = mOrigMinWidth; + S32 new_min_height = mOrigMinHeight; + + computeResizeLimits(new_min_width, new_min_height); + + setResizeLimits(new_min_width, new_min_height); + + S32 cur_height = getRect().getHeight(); + S32 new_width = llmax(getRect().getWidth(), new_min_width); + S32 new_height = llmax(getRect().getHeight(), new_min_height); + + if (isMinimized()) + { + const LLRect& expanded = getExpandedRect(); + LLRect newrect; + newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height)); + setExpandedRect(newrect); + } + else + { + reshape(new_width, new_height); + + // make sure upper left corner doesn't move + translate(0, cur_height - getRect().getHeight()); + + // make sure this window is visible on screen when it has been modified + // (tab added, etc) + gFloaterView->adjustToFitScreen(this, TRUE); + } } void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height) { - static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0); - const LLFloater::Params& default_params = LLFloater::getDefaultParams(); - S32 floater_header_size = default_params.header_height; - S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size; - - // possibly increase minimum size constraint due to children's minimums. - for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) - { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); - if (floaterp) - { - new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); - new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height); - } - } + static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0); + const LLFloater::Params& default_params = LLFloater::getDefaultParams(); + S32 floater_header_size = default_params.header_height; + S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size; + + // possibly increase minimum size constraint due to children's minimums. + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); + if (floaterp) + { + new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); + new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height); + } + } } diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index c106a62527..f2d83f4449 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -1,25 +1,25 @@ -/** +/** * @file llmultifloater.h * @brief LLFloater that hosts other floaters * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,65 +38,65 @@ class LLMultiFloater : public LLFloater { public: - LLMultiFloater(const LLSD& key, const Params& params = getDefaultParams()); - virtual ~LLMultiFloater() {}; - - void buildTabContainer(); - - virtual BOOL postBuild(); - /*virtual*/ void onClose(bool app_quitting); - virtual void draw(); - virtual void setVisible(BOOL visible); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); - - virtual void setCanResize(BOOL can_resize); - virtual void growToFit(S32 content_width, S32 content_height); - virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); - - virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); - virtual void removeFloater(LLFloater* floaterp); - - virtual void tabOpen(LLFloater* opened_floater, bool from_click); - virtual void tabClose(); - - virtual BOOL selectFloater(LLFloater* floaterp); - virtual void selectNextFloater(); - virtual void selectPrevFloater(); - - virtual LLFloater* getActiveFloater(); - virtual BOOL isFloaterFlashing(LLFloater* floaterp); - virtual S32 getFloaterCount(); - - virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); - virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs - void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } - void onTabSelected(); - - virtual void updateResizeLimits(); - virtual void updateFloaterTitle(LLFloater* floaterp); + LLMultiFloater(const LLSD& key, const Params& params = getDefaultParams()); + virtual ~LLMultiFloater() {}; + + void buildTabContainer(); + + virtual BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + virtual void draw(); + virtual void setVisible(BOOL visible); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + + virtual void setCanResize(BOOL can_resize); + virtual void growToFit(S32 content_width, S32 content_height); + virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); + + virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); + virtual void removeFloater(LLFloater* floaterp); + + virtual void tabOpen(LLFloater* opened_floater, bool from_click); + virtual void tabClose(); + + virtual BOOL selectFloater(LLFloater* floaterp); + virtual void selectNextFloater(); + virtual void selectPrevFloater(); + + virtual LLFloater* getActiveFloater(); + virtual BOOL isFloaterFlashing(LLFloater* floaterp); + virtual S32 getFloaterCount(); + + virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); + virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs + void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } + void onTabSelected(); + + virtual void updateResizeLimits(); + virtual void updateFloaterTitle(LLFloater* floaterp); protected: - struct LLFloaterData - { - S32 mWidth; - S32 mHeight; - BOOL mCanMinimize; - BOOL mCanResize; - BOOL mSaveRect; - }; - - LLTabContainer* mTabContainer; - - typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t; - floater_data_map_t mFloaterDataMap; - - LLTabContainer::TabPosition mTabPos; - BOOL mAutoResize; - S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late + struct LLFloaterData + { + S32 mWidth; + S32 mHeight; + BOOL mCanMinimize; + BOOL mCanResize; + BOOL mSaveRect; + }; + + LLTabContainer* mTabContainer; + + typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t; + floater_data_map_t mFloaterDataMap; + + LLTabContainer::TabPosition mTabPos; + BOOL mAutoResize; + S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late private: - virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height); + virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height); }; #endif // LL_MULTI_FLOATER_H diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 604d246f12..26882ba8ec 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmultisldr.cpp * @brief LLMultiSlider base class * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "llgl.h" #include "llwindow.h" #include "llfocusmgr.h" -#include "llkeyboard.h" // for the MASK constants +#include "llkeyboard.h" // for the MASK constants #include "llcontrol.h" #include "lluictrlfactory.h" #include "lluiimage.h" @@ -46,74 +46,74 @@ const F32 FLOAT_THRESHOLD = 0.00001f; S32 LLMultiSlider::mNameCounter = 0; LLMultiSlider::SliderParams::SliderParams() -: name("name"), - value("value", 0.f) +: name("name"), + value("value", 0.f) { } LLMultiSlider::Params::Params() -: max_sliders("max_sliders", 1), - allow_overlap("allow_overlap", false), - loop_overlap("loop_overlap", false), - orientation("orientation"), - overlap_threshold("overlap_threshold", 0), - draw_track("draw_track", true), - use_triangle("use_triangle", false), - track_color("track_color"), - thumb_disabled_color("thumb_disabled_color"), - thumb_highlight_color("thumb_highlight_color"), - thumb_outline_color("thumb_outline_color"), - thumb_center_color("thumb_center_color"), - thumb_center_selected_color("thumb_center_selected_color"), - thumb_image("thumb_image"), - triangle_color("triangle_color"), - mouse_down_callback("mouse_down_callback"), - mouse_up_callback("mouse_up_callback"), - thumb_width("thumb_width"), - sliders("slider") +: max_sliders("max_sliders", 1), + allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + orientation("orientation"), + overlap_threshold("overlap_threshold", 0), + draw_track("draw_track", true), + use_triangle("use_triangle", false), + track_color("track_color"), + thumb_disabled_color("thumb_disabled_color"), + thumb_highlight_color("thumb_highlight_color"), + thumb_outline_color("thumb_outline_color"), + thumb_center_color("thumb_center_color"), + thumb_center_selected_color("thumb_center_selected_color"), + thumb_image("thumb_image"), + triangle_color("triangle_color"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + thumb_width("thumb_width"), + sliders("slider") {} LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) -: LLF32UICtrl(p), - mMouseOffset( 0 ), - mMaxNumSliders(p.max_sliders), - mAllowOverlap(p.allow_overlap), - mLoopOverlap(p.loop_overlap), - mDrawTrack(p.draw_track), - mUseTriangle(p.use_triangle), - mTrackColor(p.track_color()), - mThumbOutlineColor(p.thumb_outline_color()), - mThumbCenterColor(p.thumb_center_color()), - mThumbCenterSelectedColor(p.thumb_center_selected_color()), - mDisabledThumbColor(p.thumb_disabled_color()), - mTriangleColor(p.triangle_color()), - mThumbWidth(p.thumb_width), - mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL) +: LLF32UICtrl(p), + mMouseOffset( 0 ), + mMaxNumSliders(p.max_sliders), + mAllowOverlap(p.allow_overlap), + mLoopOverlap(p.loop_overlap), + mDrawTrack(p.draw_track), + mUseTriangle(p.use_triangle), + mTrackColor(p.track_color()), + mThumbOutlineColor(p.thumb_outline_color()), + mThumbCenterColor(p.thumb_center_color()), + mThumbCenterSelectedColor(p.thumb_center_selected_color()), + mDisabledThumbColor(p.thumb_disabled_color()), + mTriangleColor(p.triangle_color()), + mThumbWidth(p.thumb_width), + mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL) { - mValue = LLSD::emptyMap(); - mCurSlider = LLStringUtil::null; - - if (mOrientation == HORIZONTAL) - { - mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0); - } - else - { - mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0); - } - - if (p.mouse_down_callback.isProvided()) - { - setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); - } - if (p.mouse_up_callback.isProvided()) - { - setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); - } - - if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement) + mValue = LLSD::emptyMap(); + mCurSlider = LLStringUtil::null; + + if (mOrientation == HORIZONTAL) + { + mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0); + } + else + { + mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0); + } + + if (p.mouse_down_callback.isProvided()) + { + setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); + } + if (p.mouse_up_callback.isProvided()) + { + setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); + } + + if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement) { mOverlapThreshold = p.overlap_threshold - mIncrement; } @@ -122,32 +122,32 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) mOverlapThreshold = 0; } - for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin(); - it != p.sliders.end(); - ++it) - { - if (it->name.isProvided()) - { - addSlider(it->value, it->name); - } - else - { - addSlider(it->value); - } - } + for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin(); + it != p.sliders.end(); + ++it) + { + if (it->name.isProvided()) + { + addSlider(it->value, it->name); + } + else + { + addSlider(it->value); + } + } mRoundedSquareImgp = LLUI::getUIImage("Rounded_Square"); - if (p.thumb_image.isProvided()) - { - mThumbImagep = LLUI::getUIImage(p.thumb_image()); - } - mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor()); + if (p.thumb_image.isProvided()) + { + mThumbImagep = LLUI::getUIImage(p.thumb_image()); + } + mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor()); } LLMultiSlider::~LLMultiSlider() { - delete mMouseDownSignal; - delete mMouseUpSignal; + delete mMouseDownSignal; + delete mMouseUpSignal; } F32 LLMultiSlider::getNearestIncrement(F32 value) const @@ -163,125 +163,125 @@ F32 LLMultiSlider::getNearestIncrement(F32 value) const void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event) { - // exit if not there - if(!mValue.has(name)) { - return; - } + // exit if not there + if(!mValue.has(name)) { + return; + } F32 newValue = getNearestIncrement(value); - // now, make sure no overlap - // if we want that - if(!mAllowOverlap) { - bool hit = false; - - // look at the current spot - // and see if anything is there - LLSD::map_iterator mIt = mValue.beginMap(); - - // increment is our distance between points, use to eliminate round error - F32 threshold = mOverlapThreshold + (mIncrement / 4); - // If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower) - F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : mMinValue - 1.0f; - // If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper) - F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : mMaxValue + 1.0f; - - for(;mIt != mValue.endMap(); mIt++) - { - F32 locationVal = (F32)mIt->second.asReal(); - // Check nearby values - F32 testVal = locationVal - newValue; - if (testVal > -threshold - && testVal < threshold - && mIt->first != name) - { - hit = true; - break; - } - if (mLoopOverlap) - { - // Check edge overlap values - if (locationVal < loop_up_check) - { - hit = true; - break; - } - if (locationVal > loop_down_check) - { - hit = true; - break; - } - } - } - - // if none found, stop - if(hit) { - return; - } - } - - - // now set it in the map - mValue[name] = newValue; - - // set the control if it's the current slider and not from an event - if (!from_event && name == mCurSlider) - { - setControlValue(mValue); - } - - F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue); - if (mOrientation == HORIZONTAL) - { - S32 left_edge = mThumbWidth/2; - S32 right_edge = getRect().getWidth() - (mThumbWidth/2); - - S32 x = left_edge + S32( t * (right_edge - left_edge) ); - - mThumbRects[name].mLeft = x - (mThumbWidth / 2); - mThumbRects[name].mRight = x + (mThumbWidth / 2); - } - else - { - S32 bottom_edge = mThumbWidth/2; - S32 top_edge = getRect().getHeight() - (mThumbWidth/2); - - S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) ); - - mThumbRects[name].mTop = x + (mThumbWidth / 2); - mThumbRects[name].mBottom = x - (mThumbWidth / 2); - } + // now, make sure no overlap + // if we want that + if(!mAllowOverlap) { + bool hit = false; + + // look at the current spot + // and see if anything is there + LLSD::map_iterator mIt = mValue.beginMap(); + + // increment is our distance between points, use to eliminate round error + F32 threshold = mOverlapThreshold + (mIncrement / 4); + // If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower) + F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : mMinValue - 1.0f; + // If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper) + F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : mMaxValue + 1.0f; + + for(;mIt != mValue.endMap(); mIt++) + { + F32 locationVal = (F32)mIt->second.asReal(); + // Check nearby values + F32 testVal = locationVal - newValue; + if (testVal > -threshold + && testVal < threshold + && mIt->first != name) + { + hit = true; + break; + } + if (mLoopOverlap) + { + // Check edge overlap values + if (locationVal < loop_up_check) + { + hit = true; + break; + } + if (locationVal > loop_down_check) + { + hit = true; + break; + } + } + } + + // if none found, stop + if(hit) { + return; + } + } + + + // now set it in the map + mValue[name] = newValue; + + // set the control if it's the current slider and not from an event + if (!from_event && name == mCurSlider) + { + setControlValue(mValue); + } + + F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue); + if (mOrientation == HORIZONTAL) + { + S32 left_edge = mThumbWidth/2; + S32 right_edge = getRect().getWidth() - (mThumbWidth/2); + + S32 x = left_edge + S32( t * (right_edge - left_edge) ); + + mThumbRects[name].mLeft = x - (mThumbWidth / 2); + mThumbRects[name].mRight = x + (mThumbWidth / 2); + } + else + { + S32 bottom_edge = mThumbWidth/2; + S32 top_edge = getRect().getHeight() - (mThumbWidth/2); + + S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) ); + + mThumbRects[name].mTop = x + (mThumbWidth / 2); + mThumbRects[name].mBottom = x - (mThumbWidth / 2); + } } void LLMultiSlider::setValue(const LLSD& value) { - // only do if it's a map - if(value.isMap()) { - - // add each value... the first in the map becomes the current - LLSD::map_const_iterator mIt = value.beginMap(); - mCurSlider = mIt->first; - - for(; mIt != value.endMap(); mIt++) { - setSliderValue(mIt->first, (F32)mIt->second.asReal(), TRUE); - } - } + // only do if it's a map + if(value.isMap()) { + + // add each value... the first in the map becomes the current + LLSD::map_const_iterator mIt = value.beginMap(); + mCurSlider = mIt->first; + + for(; mIt != value.endMap(); mIt++) { + setSliderValue(mIt->first, (F32)mIt->second.asReal(), TRUE); + } + } } F32 LLMultiSlider::getSliderValue(const std::string& name) const { - if (mValue.has(name)) - { - return (F32)mValue[name].asReal(); - } - return 0; + if (mValue.has(name)) + { + return (F32)mValue[name].asReal(); + } + return 0; } void LLMultiSlider::setCurSlider(const std::string& name) { - if(mValue.has(name)) { - mCurSlider = name; - } + if(mValue.has(name)) { + mCurSlider = name; + } } F32 LLMultiSlider::getSliderValueFromPos(S32 xpos, S32 ypos) const @@ -337,179 +337,179 @@ void LLMultiSlider::clearSliderThumbImage() void LLMultiSlider::resetCurSlider() { - mCurSlider = LLStringUtil::null; + mCurSlider = LLStringUtil::null; } const std::string& LLMultiSlider::addSlider() { - return addSlider(mInitialValue); + return addSlider(mInitialValue); } const std::string& LLMultiSlider::addSlider(F32 val) { - std::stringstream newName; - F32 initVal = val; - - if(mValue.size() >= mMaxNumSliders) { - return LLStringUtil::null; - } - - // create a new name - newName << "sldr" << mNameCounter; - mNameCounter++; - - bool foundOne = findUnusedValue(initVal); - if(!foundOne) { - return LLStringUtil::null; - } - - // add a new thumb rect - if (mOrientation == HORIZONTAL) - { - mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); - } - else - { - mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); - } - - // add the value and set the current slider to this one - mValue.insert(newName.str(), initVal); - mCurSlider = newName.str(); - - // move the slider - setSliderValue(mCurSlider, initVal, TRUE); - - return mCurSlider; + std::stringstream newName; + F32 initVal = val; + + if(mValue.size() >= mMaxNumSliders) { + return LLStringUtil::null; + } + + // create a new name + newName << "sldr" << mNameCounter; + mNameCounter++; + + bool foundOne = findUnusedValue(initVal); + if(!foundOne) { + return LLStringUtil::null; + } + + // add a new thumb rect + if (mOrientation == HORIZONTAL) + { + mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); + } + else + { + mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); + } + + // add the value and set the current slider to this one + mValue.insert(newName.str(), initVal); + mCurSlider = newName.str(); + + // move the slider + setSliderValue(mCurSlider, initVal, TRUE); + + return mCurSlider; } bool LLMultiSlider::addSlider(F32 val, const std::string& name) { - F32 initVal = val; - - if(mValue.size() >= mMaxNumSliders) { - return false; - } - - bool foundOne = findUnusedValue(initVal); - if(!foundOne) { - return false; - } - - // add a new thumb rect - if (mOrientation == HORIZONTAL) - { - mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); - } - else - { - mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); - } - - // add the value and set the current slider to this one - mValue.insert(name, initVal); - mCurSlider = name; - - // move the slider - setSliderValue(mCurSlider, initVal, TRUE); - - return true; + F32 initVal = val; + + if(mValue.size() >= mMaxNumSliders) { + return false; + } + + bool foundOne = findUnusedValue(initVal); + if(!foundOne) { + return false; + } + + // add a new thumb rect + if (mOrientation == HORIZONTAL) + { + mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0); + } + else + { + mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0); + } + + // add the value and set the current slider to this one + mValue.insert(name, initVal); + mCurSlider = name; + + // move the slider + setSliderValue(mCurSlider, initVal, TRUE); + + return true; } bool LLMultiSlider::findUnusedValue(F32& initVal) { - bool firstTry = true; - - // find the first open slot starting with - // the initial value - while(true) { - - bool hit = false; - - // look at the current spot - // and see if anything is there - F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4); - LLSD::map_iterator mIt = mValue.beginMap(); - for(;mIt != mValue.endMap(); mIt++) { - - F32 testVal = (F32)mIt->second.asReal() - initVal; - if(testVal > -threshold && testVal < threshold) - { - hit = true; - break; - } - } - - // if we found one - if(!hit) { - break; - } - - // increment and wrap if need be - initVal += mIncrement; - if(initVal > mMaxValue) { - initVal = mMinValue; - } - - // stop if it's filled - if(initVal == mInitialValue && !firstTry) { - LL_WARNS() << "Whoa! Too many multi slider elements to add one to" << LL_ENDL; - return false; - } - - firstTry = false; - continue; - } - - return true; + bool firstTry = true; + + // find the first open slot starting with + // the initial value + while(true) { + + bool hit = false; + + // look at the current spot + // and see if anything is there + F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4); + LLSD::map_iterator mIt = mValue.beginMap(); + for(;mIt != mValue.endMap(); mIt++) { + + F32 testVal = (F32)mIt->second.asReal() - initVal; + if(testVal > -threshold && testVal < threshold) + { + hit = true; + break; + } + } + + // if we found one + if(!hit) { + break; + } + + // increment and wrap if need be + initVal += mIncrement; + if(initVal > mMaxValue) { + initVal = mMinValue; + } + + // stop if it's filled + if(initVal == mInitialValue && !firstTry) { + LL_WARNS() << "Whoa! Too many multi slider elements to add one to" << LL_ENDL; + return false; + } + + firstTry = false; + continue; + } + + return true; } void LLMultiSlider::deleteSlider(const std::string& name) { - // can't delete last slider - if(mValue.size() <= 0) { - return; - } - - // get rid of value from mValue and its thumb rect - mValue.erase(name); - mThumbRects.erase(name); - - // set to the last created - if(mValue.size() > 0) { - std::map<std::string, LLRect>::iterator mIt = mThumbRects.end(); - mIt--; - mCurSlider = mIt->first; - } + // can't delete last slider + if(mValue.size() <= 0) { + return; + } + + // get rid of value from mValue and its thumb rect + mValue.erase(name); + mThumbRects.erase(name); + + // set to the last created + if(mValue.size() > 0) { + std::map<std::string, LLRect>::iterator mIt = mThumbRects.end(); + mIt--; + mCurSlider = mIt->first; + } } void LLMultiSlider::clear() { - while(mThumbRects.size() > 0 && mValue.size() > 0) { - deleteCurSlider(); - } + while(mThumbRects.size() > 0 && mValue.size() > 0) { + deleteCurSlider(); + } - if (mThumbRects.size() > 0 || mValue.size() > 0) - { - LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL; - } + if (mThumbRects.size() > 0 || mValue.size() > 0) + { + LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL; + } - LLF32UICtrl::clear(); + LLF32UICtrl::clear(); } BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) { - if( gFocusMgr.getMouseCapture() == this ) - { - setCurSliderValue(getSliderValueFromPos(x, y)); - onCommit(); - - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - } - else - { + if( gFocusMgr.getMouseCapture() == this ) + { + setCurSliderValue(getSliderValueFromPos(x, y)); + onCommit(); + + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + } + else + { if (getEnabled()) { mHoverSlider.clear(); @@ -528,116 +528,116 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) mHoverSlider.clear(); } - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; - } - return TRUE; + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + } + return TRUE; } BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - if( gFocusMgr.getMouseCapture() == this ) - { - gFocusMgr.setMouseCapture( NULL ); + if( gFocusMgr.getMouseCapture() == this ) + { + gFocusMgr.setMouseCapture( NULL ); - if (mMouseUpSignal) - (*mMouseUpSignal)( this, LLSD() ); + if (mMouseUpSignal) + (*mMouseUpSignal)( this, LLSD() ); - handled = TRUE; - make_ui_sound("UISndClickRelease"); - } - else - { - handled = TRUE; - } + handled = TRUE; + make_ui_sound("UISndClickRelease"); + } + else + { + handled = TRUE; + } - return handled; + return handled; } BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask) { - // only do sticky-focus on non-chrome widgets - if (!getIsChrome()) - { - setFocus(TRUE); - } - if (mMouseDownSignal) - (*mMouseDownSignal)( this, LLSD() ); - - if (MASK_CONTROL & mask) // if CTRL is modifying - { - setCurSliderValue(mInitialValue); - onCommit(); - } - else - { - // scroll through thumbs to see if we have a new one selected and select that one - std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin(); - for(; mIt != mThumbRects.end(); mIt++) { - - // check if inside. If so, set current slider and continue - if(mIt->second.pointInRect(x,y)) { - mCurSlider = mIt->first; - break; - } - } - - if (!mCurSlider.empty()) - { - // Find the offset of the actual mouse location from the center of the thumb. - if (mThumbRects[mCurSlider].pointInRect(x,y)) - { - if (mOrientation == HORIZONTAL) - { - mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x; - } - else - { - mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y; - } - } - else - { - mMouseOffset = 0; - } - - // Start dragging the thumb - // No handler needed for focus lost since this class has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - mDragStartThumbRect = mThumbRects[mCurSlider]; - } - } - make_ui_sound("UISndClick"); - - return TRUE; + // only do sticky-focus on non-chrome widgets + if (!getIsChrome()) + { + setFocus(TRUE); + } + if (mMouseDownSignal) + (*mMouseDownSignal)( this, LLSD() ); + + if (MASK_CONTROL & mask) // if CTRL is modifying + { + setCurSliderValue(mInitialValue); + onCommit(); + } + else + { + // scroll through thumbs to see if we have a new one selected and select that one + std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin(); + for(; mIt != mThumbRects.end(); mIt++) { + + // check if inside. If so, set current slider and continue + if(mIt->second.pointInRect(x,y)) { + mCurSlider = mIt->first; + break; + } + } + + if (!mCurSlider.empty()) + { + // Find the offset of the actual mouse location from the center of the thumb. + if (mThumbRects[mCurSlider].pointInRect(x,y)) + { + if (mOrientation == HORIZONTAL) + { + mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x; + } + else + { + mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y; + } + } + else + { + mMouseOffset = 0; + } + + // Start dragging the thumb + // No handler needed for focus lost since this class has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + mDragStartThumbRect = mThumbRects[mCurSlider]; + } + } + make_ui_sound("UISndClick"); + + return TRUE; } -BOOL LLMultiSlider::handleKeyHere(KEY key, MASK mask) +BOOL LLMultiSlider::handleKeyHere(KEY key, MASK mask) { - BOOL handled = FALSE; - switch(key) - { - case KEY_UP: - case KEY_DOWN: - // eat up and down keys to be consistent - handled = TRUE; - break; - case KEY_LEFT: - setCurSliderValue(getCurSliderValue() - getIncrement()); - onCommit(); - handled = TRUE; - break; - case KEY_RIGHT: - setCurSliderValue(getCurSliderValue() + getIncrement()); - onCommit(); - handled = TRUE; - break; - default: - break; - } - return handled; + BOOL handled = FALSE; + switch(key) + { + case KEY_UP: + case KEY_DOWN: + // eat up and down keys to be consistent + handled = TRUE; + break; + case KEY_LEFT: + setCurSliderValue(getCurSliderValue() - getIncrement()); + onCommit(); + handled = TRUE; + break; + case KEY_RIGHT: + setCurSliderValue(getCurSliderValue() + getIncrement()); + onCommit(); + handled = TRUE; + break; + default: + break; + } + return handled; } /*virtual*/ @@ -649,132 +649,132 @@ void LLMultiSlider::onMouseLeave(S32 x, S32 y, MASK mask) void LLMultiSlider::draw() { - static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0); - static LLUICachedControl<S32> extra_triangle_width ("UIExtraTriangleWidth", 0); - LLColor4 curThumbColor; - - std::map<std::string, LLRect>::iterator mIt; - std::map<std::string, LLRect>::iterator curSldrIt; - std::map<std::string, LLRect>::iterator hoverSldrIt; - - // Draw background and thumb. - - // drawing solids requires texturing be disabled - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLRect rect(mDragStartThumbRect); - - F32 opacity = getEnabled() ? 1.f : 0.3f; - - // Track - static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0); - S32 height_offset = 0; - S32 width_offset = 0; - if (mOrientation == HORIZONTAL) - { - height_offset = (getRect().getHeight() - multi_track_height_width) / 2; - } - else - { - width_offset = (getRect().getWidth() - multi_track_height_width) / 2; - } - LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset); - - - if(mDrawTrack) - { - track_rect.stretch(-1); - mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity); - } - - // if we're supposed to use a drawn triangle - // simple gl call for the triangle - if(mUseTriangle) { - - for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { - - gl_triangle_2d( - mIt->second.mLeft - extra_triangle_width, - mIt->second.mTop + extra_triangle_height, - mIt->second.mRight + extra_triangle_width, - mIt->second.mTop + extra_triangle_height, - mIt->second.mLeft + mIt->second.getWidth() / 2, - mIt->second.mBottom - extra_triangle_height, - mTriangleColor.get() % opacity, TRUE); - } - } - else if (!mRoundedSquareImgp && !mThumbImagep) - { - // draw all the thumbs - curSldrIt = mThumbRects.end(); - hoverSldrIt = mThumbRects.end(); - for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { - - // choose the color - curThumbColor = mThumbCenterColor.get(); - if(mIt->first == mCurSlider) { - - curSldrIt = mIt; - continue; - } - if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) - { - // draw last, after current one - hoverSldrIt = mIt; - continue; - } - - // the draw command - gl_rect_2d(mIt->second, curThumbColor, TRUE); - } - - // now draw the current and hover sliders - if(curSldrIt != mThumbRects.end()) - { - gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); - } - - // and draw the drag start - if (gFocusMgr.getMouseCapture() == this) - { - gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE); - } - else if (hoverSldrIt != mThumbRects.end()) - { - gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); - } - } - else - { - LLMouseHandler* capture = gFocusMgr.getMouseCapture(); - if (capture == this) - { - // draw drag start (ghost) - if (mThumbImagep) - { - mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); - } - else - { + static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0); + static LLUICachedControl<S32> extra_triangle_width ("UIExtraTriangleWidth", 0); + LLColor4 curThumbColor; + + std::map<std::string, LLRect>::iterator mIt; + std::map<std::string, LLRect>::iterator curSldrIt; + std::map<std::string, LLRect>::iterator hoverSldrIt; + + // Draw background and thumb. + + // drawing solids requires texturing be disabled + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLRect rect(mDragStartThumbRect); + + F32 opacity = getEnabled() ? 1.f : 0.3f; + + // Track + static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0); + S32 height_offset = 0; + S32 width_offset = 0; + if (mOrientation == HORIZONTAL) + { + height_offset = (getRect().getHeight() - multi_track_height_width) / 2; + } + else + { + width_offset = (getRect().getWidth() - multi_track_height_width) / 2; + } + LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset); + + + if(mDrawTrack) + { + track_rect.stretch(-1); + mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity); + } + + // if we're supposed to use a drawn triangle + // simple gl call for the triangle + if(mUseTriangle) { + + for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { + + gl_triangle_2d( + mIt->second.mLeft - extra_triangle_width, + mIt->second.mTop + extra_triangle_height, + mIt->second.mRight + extra_triangle_width, + mIt->second.mTop + extra_triangle_height, + mIt->second.mLeft + mIt->second.getWidth() / 2, + mIt->second.mBottom - extra_triangle_height, + mTriangleColor.get() % opacity, TRUE); + } + } + else if (!mRoundedSquareImgp && !mThumbImagep) + { + // draw all the thumbs + curSldrIt = mThumbRects.end(); + hoverSldrIt = mThumbRects.end(); + for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { + + // choose the color + curThumbColor = mThumbCenterColor.get(); + if(mIt->first == mCurSlider) { + + curSldrIt = mIt; + continue; + } + if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) + { + // draw last, after current one + hoverSldrIt = mIt; + continue; + } + + // the draw command + gl_rect_2d(mIt->second, curThumbColor, TRUE); + } + + // now draw the current and hover sliders + if(curSldrIt != mThumbRects.end()) + { + gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); + } + + // and draw the drag start + if (gFocusMgr.getMouseCapture() == this) + { + gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE); + } + else if (hoverSldrIt != mThumbRects.end()) + { + gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), TRUE); + } + } + else + { + LLMouseHandler* capture = gFocusMgr.getMouseCapture(); + if (capture == this) + { + // draw drag start (ghost) + if (mThumbImagep) + { + mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); + } + else + { mRoundedSquareImgp->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); - } - } - - // draw the highlight - if (hasFocus()) - { - if (!mCurSlider.empty()) - { - if (mThumbImagep) - { - mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); - } - else - { + } + } + + // draw the highlight + if (hasFocus()) + { + if (!mCurSlider.empty()) + { + if (mThumbImagep) + { + mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth()); + } + else + { mRoundedSquareImgp->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); - } - } - } + } + } + } if (!mHoverSlider.empty()) { if (mThumbImagep) @@ -787,94 +787,94 @@ void LLMultiSlider::draw() } } - // draw the thumbs - curSldrIt = mThumbRects.end(); - hoverSldrIt = mThumbRects.end(); - for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) - { - // choose the color - curThumbColor = mThumbCenterColor.get(); - if(mIt->first == mCurSlider) - { - // don't draw now, draw last - curSldrIt = mIt; - continue; - } - if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) - { - // don't draw now, draw last, after current one - hoverSldrIt = mIt; - continue; - } - - // the draw command - if (mThumbImagep) - { - if (getEnabled()) - { - mThumbImagep->draw(mIt->second); - } - else - { - mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f); - } - } - else if (capture == this) - { + // draw the thumbs + curSldrIt = mThumbRects.end(); + hoverSldrIt = mThumbRects.end(); + for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) + { + // choose the color + curThumbColor = mThumbCenterColor.get(); + if(mIt->first == mCurSlider) + { + // don't draw now, draw last + curSldrIt = mIt; + continue; + } + if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this) + { + // don't draw now, draw last, after current one + hoverSldrIt = mIt; + continue; + } + + // the draw command + if (mThumbImagep) + { + if (getEnabled()) + { + mThumbImagep->draw(mIt->second); + } + else + { + mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f); + } + } + else if (capture == this) + { mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor); - } - else - { + } + else + { mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor % opacity); - } - } - - // draw cur and hover slider last - if(curSldrIt != mThumbRects.end()) - { - if (mThumbImagep) - { - if (getEnabled()) - { - mThumbImagep->draw(curSldrIt->second); - } - else - { - mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f); - } - } - else if (capture == this) - { + } + } + + // draw cur and hover slider last + if(curSldrIt != mThumbRects.end()) + { + if (mThumbImagep) + { + if (getEnabled()) + { + mThumbImagep->draw(curSldrIt->second); + } + else + { + mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f); + } + } + else if (capture == this) + { mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); - } - else - { + } + else + { mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); - } - } - if(hoverSldrIt != mThumbRects.end()) - { - if (mThumbImagep) - { - mThumbImagep->draw(hoverSldrIt->second); - } - else - { + } + } + if(hoverSldrIt != mThumbRects.end()) + { + if (mThumbImagep) + { + mThumbImagep->draw(hoverSldrIt->second); + } + else + { mRoundedSquareImgp->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get()); - } - } - } + } + } + } - LLF32UICtrl::draw(); + LLF32UICtrl::draw(); } -boost::signals2::connection LLMultiSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); - return mMouseDownSignal->connect(cb); +boost::signals2::connection LLMultiSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); + return mMouseDownSignal->connect(cb); } -boost::signals2::connection LLMultiSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); - return mMouseUpSignal->connect(cb); +boost::signals2::connection LLMultiSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); + return mMouseUpSignal->connect(cb); } diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index 3cb4b760b0..963c6e5fab 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -1,25 +1,25 @@ -/** +/** * @file llmultislider.h * @brief A simple multislider * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,127 +35,127 @@ class LLUICtrlFactory; class LLMultiSlider : public LLF32UICtrl { public: - struct SliderParams : public LLInitParam::Block<SliderParams> - { - Optional<std::string> name; - Mandatory<F32> value; - SliderParams(); - }; - - struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> - { - Optional<S32> max_sliders; - - Optional<bool> allow_overlap, - loop_overlap, - draw_track, - use_triangle; - - Optional<F32> overlap_threshold; - - Optional<LLUIColor> track_color, - thumb_disabled_color, - thumb_highlight_color, - thumb_outline_color, - thumb_center_color, - thumb_center_selected_color, - triangle_color; - - Optional<std::string> orientation, - thumb_image; - - Optional<CommitCallbackParam> mouse_down_callback, - mouse_up_callback; - Optional<S32> thumb_width; - - Multiple<SliderParams> sliders; - Params(); - }; + struct SliderParams : public LLInitParam::Block<SliderParams> + { + Optional<std::string> name; + Mandatory<F32> value; + SliderParams(); + }; + + struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> + { + Optional<S32> max_sliders; + + Optional<bool> allow_overlap, + loop_overlap, + draw_track, + use_triangle; + + Optional<F32> overlap_threshold; + + Optional<LLUIColor> track_color, + thumb_disabled_color, + thumb_highlight_color, + thumb_outline_color, + thumb_center_color, + thumb_center_selected_color, + triangle_color; + + Optional<std::string> orientation, + thumb_image; + + Optional<CommitCallbackParam> mouse_down_callback, + mouse_up_callback; + Optional<S32> thumb_width; + + Multiple<SliderParams> sliders; + Params(); + }; protected: - LLMultiSlider(const Params&); - friend class LLUICtrlFactory; + LLMultiSlider(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMultiSlider(); + virtual ~LLMultiSlider(); // Multi-slider rounds values to nearest increments (bias towards rounding down) - F32 getNearestIncrement(F32 value) const; + F32 getNearestIncrement(F32 value) const; - void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE); - F32 getSliderValue(const std::string& name) const; - F32 getSliderValueFromPos(S32 xpos, S32 ypos) const; + void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE); + F32 getSliderValue(const std::string& name) const; + F32 getSliderValueFromPos(S32 xpos, S32 ypos) const; LLRect getSliderThumbRect(const std::string& name) const; void setSliderThumbImage(const std::string &name); void clearSliderThumbImage(); - const std::string& getCurSlider() const { return mCurSlider; } - F32 getCurSliderValue() const { return getSliderValue(mCurSlider); } - void setCurSlider(const std::string& name); - void resetCurSlider(); - void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); } + const std::string& getCurSlider() const { return mCurSlider; } + F32 getCurSliderValue() const { return getSliderValue(mCurSlider); } + void setCurSlider(const std::string& name); + void resetCurSlider(); + void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); } - /*virtual*/ void setValue(const LLSD& value) override; - /*virtual*/ LLSD getValue() const override { return mValue; } + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLSD getValue() const override { return mValue; } - boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); - bool findUnusedValue(F32& initVal); - const std::string& addSlider(); - const std::string& addSlider(F32 val); - bool addSlider(F32 val, const std::string& name); - void deleteSlider(const std::string& name); - void deleteCurSlider() { deleteSlider(mCurSlider); } - /*virtual*/ void clear() override; + bool findUnusedValue(F32& initVal); + const std::string& addSlider(); + const std::string& addSlider(F32 val); + bool addSlider(F32 val, const std::string& name); + void deleteSlider(const std::string& name); + void deleteCurSlider() { deleteSlider(mCurSlider); } + /*virtual*/ void clear() override; - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; - /*virtual*/ void draw() override; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; + /*virtual*/ void draw() override; - S32 getMaxNumSliders() { return mMaxNumSliders; } - S32 getCurNumSliders() { return mValue.size(); } - F32 getOverlapThreshold() { return mOverlapThreshold; } - bool canAddSliders() { return mValue.size() < mMaxNumSliders; } + S32 getMaxNumSliders() { return mMaxNumSliders; } + S32 getCurNumSliders() { return mValue.size(); } + F32 getOverlapThreshold() { return mOverlapThreshold; } + bool canAddSliders() { return mValue.size() < mMaxNumSliders; } protected: - LLSD mValue; - std::string mCurSlider; - std::string mHoverSlider; - static S32 mNameCounter; - - S32 mMaxNumSliders; - BOOL mAllowOverlap; - BOOL mLoopOverlap; - F32 mOverlapThreshold; - BOOL mDrawTrack; - BOOL mUseTriangle; /// hacked in toggle to use a triangle - - S32 mMouseOffset; - LLRect mDragStartThumbRect; - S32 mThumbWidth; - - std::map<std::string, LLRect> - mThumbRects; - LLUIColor mTrackColor; - LLUIColor mThumbOutlineColor; - LLUIColor mThumbHighlightColor; - LLUIColor mThumbCenterColor; - LLUIColor mThumbCenterSelectedColor; - LLUIColor mDisabledThumbColor; - LLUIColor mTriangleColor; - LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support - LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support - - const EOrientation mOrientation; - - commit_signal_t* mMouseDownSignal; - commit_signal_t* mMouseUpSignal; + LLSD mValue; + std::string mCurSlider; + std::string mHoverSlider; + static S32 mNameCounter; + + S32 mMaxNumSliders; + BOOL mAllowOverlap; + BOOL mLoopOverlap; + F32 mOverlapThreshold; + BOOL mDrawTrack; + BOOL mUseTriangle; /// hacked in toggle to use a triangle + + S32 mMouseOffset; + LLRect mDragStartThumbRect; + S32 mThumbWidth; + + std::map<std::string, LLRect> + mThumbRects; + LLUIColor mTrackColor; + LLUIColor mThumbOutlineColor; + LLUIColor mThumbHighlightColor; + LLUIColor mThumbCenterColor; + LLUIColor mThumbCenterSelectedColor; + LLUIColor mDisabledThumbColor; + LLUIColor mTriangleColor; + LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support + LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support + + const EOrientation mOrientation; + + commit_signal_t* mMouseDownSignal; + commit_signal_t* mMouseUpSignal; }; #endif // LL_MULTI_SLIDER_H diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index b3df7c154b..b0598b4388 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmultisliderctrl.cpp * @brief LLMultiSliderCtrl base class * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,479 +47,479 @@ static LLDefaultChildRegistry::Register<LLMultiSliderCtrl> r("multi_slider"); const U32 MAX_STRING_LENGTH = 10; LLMultiSliderCtrl::Params::Params() -: text_width("text_width"), - label_width("label_width"), - show_text("show_text", true), - can_edit_text("can_edit_text", false), - max_sliders("max_sliders", 1), - allow_overlap("allow_overlap", false), - loop_overlap("loop_overlap", false), - orientation("orientation"), - thumb_image("thumb_image"), - thumb_width("thumb_width"), - thumb_highlight_color("thumb_highlight_color"), - overlap_threshold("overlap_threshold", 0), - draw_track("draw_track", true), - use_triangle("use_triangle", false), - decimal_digits("decimal_digits", 3), - text_color("text_color"), - text_disabled_color("text_disabled_color"), - mouse_down_callback("mouse_down_callback"), - mouse_up_callback("mouse_up_callback"), - sliders("slider") +: text_width("text_width"), + label_width("label_width"), + show_text("show_text", true), + can_edit_text("can_edit_text", false), + max_sliders("max_sliders", 1), + allow_overlap("allow_overlap", false), + loop_overlap("loop_overlap", false), + orientation("orientation"), + thumb_image("thumb_image"), + thumb_width("thumb_width"), + thumb_highlight_color("thumb_highlight_color"), + overlap_threshold("overlap_threshold", 0), + draw_track("draw_track", true), + use_triangle("use_triangle", false), + decimal_digits("decimal_digits", 3), + text_color("text_color"), + text_disabled_color("text_disabled_color"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + sliders("slider") { - mouse_opaque = true; + mouse_opaque = true; } - + LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p) -: LLF32UICtrl(p), - mLabelBox( NULL ), - mEditor( NULL ), - mTextBox( NULL ), - mTextEnabledColor(p.text_color()), - mTextDisabledColor(p.text_disabled_color()) +: LLF32UICtrl(p), + mLabelBox( NULL ), + mEditor( NULL ), + mTextBox( NULL ), + mTextEnabledColor(p.text_color()), + mTextDisabledColor(p.text_disabled_color()) { - static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0); - - S32 top = getRect().getHeight(); - S32 bottom = 0; - S32 left = 0; - - S32 label_width = p.label_width; - S32 text_width = p.text_width; - - // Label - if( !p.label().empty() ) - { - if (p.label_width == 0) - { - label_width = p.font()->getWidth(p.label); - } - LLRect label_rect( left, top, label_width, bottom ); - LLTextBox::Params params; - params.name("MultiSliderCtrl Label"); - params.rect(label_rect); - params.initial_value(p.label()); - params.font(p.font); - mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mLabelBox); - } - - S32 slider_right = getRect().getWidth(); - - if (p.show_text) - { - if (!p.text_width.isProvided()) - { - text_width = 0; - // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) - if ( p.max_value() ) - text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 ); - - if ( p.increment < 1.0f ) - text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value - - if ( p.min_value < 0.0f || p.max_value < 0.0f ) - text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign - - // padding to make things look nicer - text_width += 8; - } - S32 text_left = getRect().getWidth() - text_width; - - slider_right = text_left - multi_sliderctrl_spacing; - - LLRect text_rect( text_left, top, getRect().getWidth(), bottom ); - if( p.can_edit_text ) - { - LLLineEditor::Params params; - params.name("MultiSliderCtrl Editor"); - params.rect(text_rect); - params.font(p.font); - params.max_length.bytes(MAX_STRING_LENGTH); - params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit); - 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) ); - // don't do this, as selecting the entire text is single clicking in some cases - // and double clicking in others - //mEditor->setSelectAllonFocusReceived(TRUE); - addChild(mEditor); - } - else - { - LLTextBox::Params params; - params.name("MultiSliderCtrl Text"); - params.rect(text_rect); - params.font(p.font); - params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - mTextBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mTextBox); - } - } - - S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0; - LLRect slider_rect( slider_left, top, slider_right, bottom ); - LLMultiSlider::Params params; - params.sliders = p.sliders; - params.rect(slider_rect); - params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit ); - params.mouse_down_callback( p.mouse_down_callback ); - params.mouse_up_callback( p.mouse_up_callback ); - params.initial_value(p.initial_value()); - params.min_value(p.min_value); - params.max_value(p.max_value); - params.increment(p.increment); - params.max_sliders(p.max_sliders); - params.allow_overlap(p.allow_overlap); - params.loop_overlap(p.loop_overlap); - if (p.overlap_threshold.isProvided()) - { - params.overlap_threshold = p.overlap_threshold; - } - params.orientation(p.orientation); - params.thumb_image(p.thumb_image); - params.thumb_highlight_color(p.thumb_highlight_color); - if (p.thumb_width.isProvided()) - { - // otherwise should be provided by template - params.thumb_width(p.thumb_width); - } - params.draw_track(p.draw_track); - params.use_triangle(p.use_triangle); - params.control_name(p.control_name); - mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params); - addChild( mMultiSlider ); - mCurValue = mMultiSlider->getCurSliderValue(); - - - updateText(); + static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0); + + S32 top = getRect().getHeight(); + S32 bottom = 0; + S32 left = 0; + + S32 label_width = p.label_width; + S32 text_width = p.text_width; + + // Label + if( !p.label().empty() ) + { + if (p.label_width == 0) + { + label_width = p.font()->getWidth(p.label); + } + LLRect label_rect( left, top, label_width, bottom ); + LLTextBox::Params params; + params.name("MultiSliderCtrl Label"); + params.rect(label_rect); + params.initial_value(p.label()); + params.font(p.font); + mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mLabelBox); + } + + S32 slider_right = getRect().getWidth(); + + if (p.show_text) + { + if (!p.text_width.isProvided()) + { + text_width = 0; + // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) + if ( p.max_value() ) + text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 ); + + if ( p.increment < 1.0f ) + text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value + + if ( p.min_value < 0.0f || p.max_value < 0.0f ) + text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign + + // padding to make things look nicer + text_width += 8; + } + S32 text_left = getRect().getWidth() - text_width; + + slider_right = text_left - multi_sliderctrl_spacing; + + LLRect text_rect( text_left, top, getRect().getWidth(), bottom ); + if( p.can_edit_text ) + { + LLLineEditor::Params params; + params.name("MultiSliderCtrl Editor"); + params.rect(text_rect); + params.font(p.font); + params.max_length.bytes(MAX_STRING_LENGTH); + params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit); + params.prevalidator(&LLTextValidate::validateFloat); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + mEditor = LLUICtrlFactory::create<LLLineEditor> (params); + mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) ); + // don't do this, as selecting the entire text is single clicking in some cases + // and double clicking in others + //mEditor->setSelectAllonFocusReceived(TRUE); + addChild(mEditor); + } + else + { + LLTextBox::Params params; + params.name("MultiSliderCtrl Text"); + params.rect(text_rect); + params.font(p.font); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + mTextBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mTextBox); + } + } + + S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0; + LLRect slider_rect( slider_left, top, slider_right, bottom ); + LLMultiSlider::Params params; + params.sliders = p.sliders; + params.rect(slider_rect); + params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit ); + params.mouse_down_callback( p.mouse_down_callback ); + params.mouse_up_callback( p.mouse_up_callback ); + params.initial_value(p.initial_value()); + params.min_value(p.min_value); + params.max_value(p.max_value); + params.increment(p.increment); + params.max_sliders(p.max_sliders); + params.allow_overlap(p.allow_overlap); + params.loop_overlap(p.loop_overlap); + if (p.overlap_threshold.isProvided()) + { + params.overlap_threshold = p.overlap_threshold; + } + params.orientation(p.orientation); + params.thumb_image(p.thumb_image); + params.thumb_highlight_color(p.thumb_highlight_color); + if (p.thumb_width.isProvided()) + { + // otherwise should be provided by template + params.thumb_width(p.thumb_width); + } + params.draw_track(p.draw_track); + params.use_triangle(p.use_triangle); + params.control_name(p.control_name); + mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params); + addChild( mMultiSlider ); + mCurValue = mMultiSlider->getCurSliderValue(); + + + updateText(); } LLMultiSliderCtrl::~LLMultiSliderCtrl() { - // Children all cleaned up by default view destructor. + // Children all cleaned up by default view destructor. } // static void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) { - LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; - llassert( caller == self->mEditor ); + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + llassert( caller == self->mEditor ); - self->onFocusReceived(); + self->onFocusReceived(); } void LLMultiSliderCtrl::setValue(const LLSD& value) { - mMultiSlider->setValue(value); - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); + mMultiSlider->setValue(value); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); } void LLMultiSliderCtrl::setSliderValue(const std::string& name, F32 v, BOOL from_event) { - mMultiSlider->setSliderValue(name, v, from_event ); - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); + mMultiSlider->setSliderValue(name, v, from_event ); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); } void LLMultiSliderCtrl::setCurSlider(const std::string& name) { - mMultiSlider->setCurSlider(name); - mCurValue = mMultiSlider->getCurSliderValue(); + mMultiSlider->setCurSlider(name); + mCurValue = mMultiSlider->getCurSliderValue(); } void LLMultiSliderCtrl::resetCurSlider() { - mMultiSlider->resetCurSlider(); + mMultiSlider->resetCurSlider(); } BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - BOOL res = FALSE; - if (mLabelBox) - { - res = mLabelBox->setTextArg(key, text); - if (res && mLabelWidth == 0) - { - S32 label_width = mFont->getWidth(mLabelBox->getText()); - LLRect rect = mLabelBox->getRect(); - S32 prev_right = rect.mRight; - rect.mRight = rect.mLeft + label_width; - mLabelBox->setRect(rect); - - S32 delta = rect.mRight - prev_right; - rect = mMultiSlider->getRect(); - S32 left = rect.mLeft + delta; - static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0); - left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing); - rect.mLeft = left; - mMultiSlider->setRect(rect); - } - } - return res; + BOOL res = FALSE; + if (mLabelBox) + { + res = mLabelBox->setTextArg(key, text); + if (res && mLabelWidth == 0) + { + S32 label_width = mFont->getWidth(mLabelBox->getText()); + LLRect rect = mLabelBox->getRect(); + S32 prev_right = rect.mRight; + rect.mRight = rect.mLeft + label_width; + mLabelBox->setRect(rect); + + S32 delta = rect.mRight - prev_right; + rect = mMultiSlider->getRect(); + S32 left = rect.mLeft + delta; + static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0); + left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing); + rect.mLeft = left; + mMultiSlider->setRect(rect); + } + } + return res; } const std::string& LLMultiSliderCtrl::addSlider() { - const std::string& name = mMultiSlider->addSlider(); - - // if it returns null, pass it on - if(name == LLStringUtil::null) { - return LLStringUtil::null; - } - - // otherwise, update stuff - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); - return name; + const std::string& name = mMultiSlider->addSlider(); + + // if it returns null, pass it on + if(name == LLStringUtil::null) { + return LLStringUtil::null; + } + + // otherwise, update stuff + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + return name; } const std::string& LLMultiSliderCtrl::addSlider(F32 val) { - const std::string& name = mMultiSlider->addSlider(val); + const std::string& name = mMultiSlider->addSlider(val); - // if it returns null, pass it on - if(name == LLStringUtil::null) { - return LLStringUtil::null; - } + // if it returns null, pass it on + if(name == LLStringUtil::null) { + return LLStringUtil::null; + } - // otherwise, update stuff - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); - return name; + // otherwise, update stuff + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + return name; } bool LLMultiSliderCtrl::addSlider(F32 val, const std::string& name) { - bool res = mMultiSlider->addSlider(val, name); - if (res) - { - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); - } - return res; + bool res = mMultiSlider->addSlider(val, name); + if (res) + { + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + } + return res; } void LLMultiSliderCtrl::deleteSlider(const std::string& name) { - mMultiSlider->deleteSlider(name); - mCurValue = mMultiSlider->getCurSliderValue(); - updateText(); + mMultiSlider->deleteSlider(name); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); } void LLMultiSliderCtrl::clear() { - setCurSliderValue(0.0f); - if( mEditor ) - { - mEditor->setText(std::string("")); - } - if( mTextBox ) - { - mTextBox->setText(std::string("")); - } - - // get rid of sliders - mMultiSlider->clear(); + setCurSliderValue(0.0f); + if( mEditor ) + { + mEditor->setText(std::string("")); + } + if( mTextBox ) + { + mTextBox->setText(std::string("")); + } + + // get rid of sliders + mMultiSlider->clear(); } BOOL LLMultiSliderCtrl::isMouseHeldDown() { - return gFocusMgr.getMouseCapture() == mMultiSlider; + return gFocusMgr.getMouseCapture() == mMultiSlider; } void LLMultiSliderCtrl::updateText() { - if( mEditor || mTextBox ) - { - LLLocale locale(LLLocale::USER_LOCALE); - - // Don't display very small negative values as -0.000 - F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision)); - - std::string format = llformat("%%.%df", mPrecision); - std::string text = llformat(format.c_str(), displayed_value); - if( mEditor ) - { - mEditor->setText( text ); - } - else - { - mTextBox->setText( text ); - } - } + if( mEditor || mTextBox ) + { + LLLocale locale(LLLocale::USER_LOCALE); + + // Don't display very small negative values as -0.000 + F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision)); + + std::string format = llformat("%%.%df", mPrecision); + std::string text = llformat(format.c_str(), displayed_value); + if( mEditor ) + { + mEditor->setText( text ); + } + else + { + mTextBox->setText( text ); + } + } } // static void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata) { - llassert(ctrl); - if (!ctrl) - return; - - LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); - llassert(self); - if (!self) // cast failed - wrong type! :O - return; - - BOOL success = FALSE; - F32 val = self->mCurValue; - F32 saved_val = self->mCurValue; - - std::string text = self->mEditor->getText(); - if( LLLineEditor::postvalidateFloat( text ) ) - { - LLLocale locale(LLLocale::USER_LOCALE); - val = (F32) atof( text.c_str() ); - if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() ) - { - self->setCurSliderValue( val ); // set the value temporarily so that the callback can retrieve it. - if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) ) - { - success = TRUE; - } - } - } - - if( success ) - { - self->onCommit(); - } - else - { - if( self->getCurSliderValue() != saved_val ) - { - self->setCurSliderValue( saved_val ); - } - self->reportInvalidData(); - } - self->updateText(); + llassert(ctrl); + if (!ctrl) + return; + + LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); + llassert(self); + if (!self) // cast failed - wrong type! :O + return; + + BOOL success = FALSE; + F32 val = self->mCurValue; + F32 saved_val = self->mCurValue; + + std::string text = self->mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + LLLocale locale(LLLocale::USER_LOCALE); + val = (F32) atof( text.c_str() ); + if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() ) + { + self->setCurSliderValue( val ); // set the value temporarily so that the callback can retrieve it. + if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) ) + { + success = TRUE; + } + } + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->getCurSliderValue() != saved_val ) + { + self->setCurSliderValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); } // static void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata) { - LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); - if (!self) - return; - - BOOL success = FALSE; - F32 saved_val = self->mCurValue; - F32 new_val = self->mMultiSlider->getCurSliderValue(); - - self->mCurValue = new_val; // set the value temporarily so that the callback can retrieve it. - if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) ) - { - success = TRUE; - } - - if( success ) - { - self->onCommit(); - } - else - { - if( self->mCurValue != saved_val ) - { - self->setCurSliderValue( saved_val ); - } - self->reportInvalidData(); - } - self->updateText(); + LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent()); + if (!self) + return; + + BOOL success = FALSE; + F32 saved_val = self->mCurValue; + F32 new_val = self->mMultiSlider->getCurSliderValue(); + + self->mCurValue = new_val; // set the value temporarily so that the callback can retrieve it. + if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) ) + { + success = TRUE; + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->mCurValue != saved_val ) + { + self->setCurSliderValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); } void LLMultiSliderCtrl::setEnabled(BOOL b) { - LLF32UICtrl::setEnabled( b ); + LLF32UICtrl::setEnabled( b ); - if( mLabelBox ) - { - mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + if( mLabelBox ) + { + mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } - mMultiSlider->setEnabled( b ); + mMultiSlider->setEnabled( b ); - if( mEditor ) - { - mEditor->setEnabled( b ); - } + if( mEditor ) + { + mEditor->setEnabled( b ); + } - if( mTextBox ) - { - mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + if( mTextBox ) + { + mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } } void LLMultiSliderCtrl::setTentative(BOOL b) { - if( mEditor ) - { - mEditor->setTentative(b); - } - LLF32UICtrl::setTentative(b); + if( mEditor ) + { + mEditor->setTentative(b); + } + LLF32UICtrl::setTentative(b); } void LLMultiSliderCtrl::onCommit() { - setTentative(FALSE); + setTentative(FALSE); - if( mEditor ) - { - mEditor->setTentative(FALSE); - } + if( mEditor ) + { + mEditor->setTentative(FALSE); + } - setControlValue(getValueF32()); - LLF32UICtrl::onCommit(); + setControlValue(getValueF32()); + LLF32UICtrl::onCommit(); } void LLMultiSliderCtrl::setPrecision(S32 precision) { - if (precision < 0 || precision > 10) - { - LL_ERRS() << "LLMultiSliderCtrl::setPrecision - precision out of range" << LL_ENDL; - return; - } - - mPrecision = precision; - updateText(); + if (precision < 0 || precision > 10) + { + LL_ERRS() << "LLMultiSliderCtrl::setPrecision - precision out of range" << LL_ENDL; + return; + } + + mPrecision = precision; + updateText(); } boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ) { - return mMultiSlider->setMouseDownCallback( cb ); + return mMultiSlider->setMouseDownCallback( cb ); } boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ) { - return mMultiSlider->setMouseUpCallback( cb ); + return mMultiSlider->setMouseUpCallback( cb ); } void LLMultiSliderCtrl::onTabInto() { - if( mEditor ) - { - mEditor->onTabInto(); - } + if( mEditor ) + { + mEditor->onTabInto(); + } LLF32UICtrl::onTabInto(); } void LLMultiSliderCtrl::reportInvalidData() { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } // virtual void LLMultiSliderCtrl::setControlName(const std::string& control_name, LLView* context) { - mMultiSlider->setControlName(control_name, context); + mMultiSlider->setControlName(control_name, context); } diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index adb28676ec..e3b190a938 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file llmultisliderctrl.h * @brief LLMultiSliderCtrl base class * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,130 +45,130 @@ class LLSlider; class LLMultiSliderCtrl : public LLF32UICtrl { public: - struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> - { - Optional<S32> label_width, - text_width; - Optional<bool> show_text, - can_edit_text; - Optional<S32> decimal_digits, - thumb_width; - Optional<S32> max_sliders; - Optional<bool> allow_overlap, - loop_overlap, - draw_track, - use_triangle; + struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> + { + Optional<S32> label_width, + text_width; + Optional<bool> show_text, + can_edit_text; + Optional<S32> decimal_digits, + thumb_width; + Optional<S32> max_sliders; + Optional<bool> allow_overlap, + loop_overlap, + draw_track, + use_triangle; - Optional<std::string> orientation, - thumb_image; + Optional<std::string> orientation, + thumb_image; - Optional<F32> overlap_threshold; + Optional<F32> overlap_threshold; - Optional<LLUIColor> text_color, - text_disabled_color, - thumb_highlight_color; + Optional<LLUIColor> text_color, + text_disabled_color, + thumb_highlight_color; - Optional<CommitCallbackParam> mouse_down_callback, - mouse_up_callback; + Optional<CommitCallbackParam> mouse_down_callback, + mouse_up_callback; - Multiple<LLMultiSlider::SliderParams> sliders; + Multiple<LLMultiSlider::SliderParams> sliders; - Params(); - }; + Params(); + }; protected: - LLMultiSliderCtrl(const Params&); - friend class LLUICtrlFactory; + LLMultiSliderCtrl(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLMultiSliderCtrl(); + virtual ~LLMultiSliderCtrl(); - F32 getSliderValue(const std::string& name) const { return mMultiSlider->getSliderValue(name); } - void setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE); + F32 getSliderValue(const std::string& name) const { return mMultiSlider->getSliderValue(name); } + void setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE); - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const { return mMultiSlider->getValue(); } - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const { return mMultiSlider->getValue(); } + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - const std::string& getCurSlider() const { return mMultiSlider->getCurSlider(); } - F32 getCurSliderValue() const { return mCurValue; } - void setCurSlider(const std::string& name); - void resetCurSlider(); - void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); } + const std::string& getCurSlider() const { return mMultiSlider->getCurSlider(); } + F32 getCurSliderValue() const { return mCurValue; } + void setCurSlider(const std::string& name); + void resetCurSlider(); + void setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); } - virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } - virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } - BOOL isMouseHeldDown(); + BOOL isMouseHeldDown(); - virtual void setEnabled( BOOL b ); - virtual void clear(); - virtual void setPrecision(S32 precision); - void setMinValue(F32 min_value) {mMultiSlider->setMinValue(min_value);} - void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);} - void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);} + virtual void setEnabled( BOOL b ); + virtual void clear(); + virtual void setPrecision(S32 precision); + void setMinValue(F32 min_value) {mMultiSlider->setMinValue(min_value);} + void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);} + void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);} - F32 getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); } - F32 getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); } + F32 getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); } + F32 getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); } LLRect getSliderThumbRect(const std::string &name) const { return mMultiSlider->getSliderThumbRect(name); } void setSliderThumbImage(const std::string &name) { mMultiSlider->setSliderThumbImage(name); } void clearSliderThumbImage() { mMultiSlider->clearSliderThumbImage(); } - /// for adding and deleting sliders - const std::string& addSlider(); - const std::string& addSlider(F32 val); - bool addSlider(F32 val, const std::string& name); - void deleteSlider(const std::string& name); - void deleteCurSlider() { deleteSlider(mMultiSlider->getCurSlider()); } + /// for adding and deleting sliders + const std::string& addSlider(); + const std::string& addSlider(F32 val); + bool addSlider(F32 val, const std::string& name); + void deleteSlider(const std::string& name); + void deleteCurSlider() { deleteSlider(mMultiSlider->getCurSlider()); } + + F32 getMinValue() const { return mMultiSlider->getMinValue(); } + F32 getMaxValue() const { return mMultiSlider->getMaxValue(); } + + S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); } + S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); } + F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); } + bool canAddSliders() { return mMultiSlider->canAddSliders(); } - F32 getMinValue() const { return mMultiSlider->getMinValue(); } - F32 getMaxValue() const { return mMultiSlider->getMaxValue(); } + void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); } + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } - S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); } - S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); } - F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); } - bool canAddSliders() { return mMultiSlider->canAddSliders(); } + boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ); - void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); } - void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } - void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } + virtual void onTabInto(); - boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ); + virtual void setTentative(BOOL b); // marks value as tentative + virtual void onCommit(); // mark not tentative, then commit - virtual void onTabInto(); + virtual void setControlName(const std::string& control_name, LLView* context); - virtual void setTentative(BOOL b); // marks value as tentative - virtual void onCommit(); // mark not tentative, then commit + static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata); - virtual void setControlName(const std::string& control_name, LLView* context); - - static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata); - - static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); + static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); + static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); + static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); private: - void updateText(); - void reportInvalidData(); + void updateText(); + void reportInvalidData(); private: - const LLFontGL* mFont; - BOOL mShowText; - BOOL mCanEditText; + const LLFontGL* mFont; + BOOL mShowText; + BOOL mCanEditText; - S32 mPrecision; - LLTextBox* mLabelBox; - S32 mLabelWidth; + S32 mPrecision; + LLTextBox* mLabelBox; + S32 mLabelWidth; - F32 mCurValue; - LLMultiSlider* mMultiSlider; - LLLineEditor* mEditor; - LLTextBox* mTextBox; + F32 mCurValue; + LLMultiSlider* mMultiSlider; + LLLineEditor* mEditor; + LLTextBox* mTextBox; - LLUIColor mTextEnabledColor; - LLUIColor mTextDisabledColor; + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; }; #endif // LL_MULTI_SLIDERCTRL_H diff --git a/indra/llui/llnotificationptr.h b/indra/llui/llnotificationptr.h index 580f353c7d..60ff7711a0 100644 --- a/indra/llui/llnotificationptr.h +++ b/indra/llui/llnotificationptr.h @@ -4,21 +4,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 907408f309..2fbae73b65 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,241 +51,242 @@ const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; void NotificationPriorityValues::declareValues() { - declare("low", NOTIFICATION_PRIORITY_LOW); - declare("normal", NOTIFICATION_PRIORITY_NORMAL); - declare("high", NOTIFICATION_PRIORITY_HIGH); - declare("critical", NOTIFICATION_PRIORITY_CRITICAL); + declare("low", NOTIFICATION_PRIORITY_LOW); + declare("normal", NOTIFICATION_PRIORITY_NORMAL); + declare("high", NOTIFICATION_PRIORITY_HIGH); + declare("critical", NOTIFICATION_PRIORITY_CRITICAL); } LLNotificationForm::FormElementBase::FormElementBase() -: name("name"), - enabled("enabled", true) +: name("name"), + enabled("enabled", true) {} LLNotificationForm::FormIgnore::FormIgnore() -: text("text"), - control("control"), - invert_control("invert_control", false), - save_option("save_option", false), - session_only("session_only", false), - checkbox_only("checkbox_only", false) +: text("text"), + control("control"), + invert_control("invert_control", false), + save_option("save_option", false), + session_only("session_only", false), + checkbox_only("checkbox_only", false) {} LLNotificationForm::FormButton::FormButton() -: index("index"), - text("text"), - ignore("ignore"), - is_default("default"), - width("width", 0), - type("type") +: index("index"), + text("text"), + ignore("ignore"), + is_default("default"), + width("width", 0), + type("type") { - // set type here so it gets serialized - type = "button"; + // set type here so it gets serialized + type = "button"; } LLNotificationForm::FormInput::FormInput() -: type("type"), - text("text"), - max_length_chars("max_length_chars"), - width("width", 0), - value("value") +: type("type"), + text("text"), + max_length_chars("max_length_chars"), + allow_emoji("allow_emoji"), + width("width", 0), + value("value") {} LLNotificationForm::FormElement::FormElement() -: button("button"), - input("input") +: button("button"), + input("input") {} LLNotificationForm::FormElements::FormElements() -: elements("") +: elements("") {} LLNotificationForm::Params::Params() -: name("name"), - ignore("ignore"), - form_elements("") +: name("name"), + ignore("ignore"), + form_elements("") {} bool filterIgnoredNotifications(LLNotificationPtr notification) { - LLNotificationFormPtr form = notification->getForm(); - // Check to see if the user wants to ignore this alert - return !notification->getForm()->getIgnored(); + LLNotificationFormPtr form = notification->getForm(); + // Check to see if the user wants to ignore this alert + return !notification->getForm()->getIgnored(); } bool handleIgnoredNotification(const LLSD& payload) { - if (payload["sigtype"].asString() == "add") - { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (!pNotif) return false; - - LLNotificationFormPtr form = pNotif->getForm(); - LLSD response; - switch(form->getIgnoreType()) - { - case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE: - case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY: - response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); - break; - case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: - response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); - break; - case LLNotificationForm::IGNORE_SHOW_AGAIN: - break; - default: - return false; - } - pNotif->setIgnored(true); - pNotif->respond(response); - return true; // don't process this item any further - } - return false; + if (payload["sigtype"].asString() == "add") + { + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (!pNotif) return false; + + LLNotificationFormPtr form = pNotif->getForm(); + LLSD response; + switch(form->getIgnoreType()) + { + case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE: + case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY: + response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); + break; + case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: + response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); + break; + case LLNotificationForm::IGNORE_SHOW_AGAIN: + break; + default: + return false; + } + pNotif->setIgnored(true); + pNotif->respond(response); + return true; // don't process this item any further + } + return false; } bool defaultResponse(const LLSD& payload) { - if (payload["sigtype"].asString() == "add") - { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (pNotif) - { - // supply default response - pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); - } - } - return false; + if (payload["sigtype"].asString() == "add") + { + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (pNotif) + { + // supply default response + pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); + } + } + return false; } bool visibilityRuleMached(const LLSD& payload) { - // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification. - // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order. - return true; + // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification. + // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order. + return true; } namespace LLNotificationFilters { - // a sample filter - bool includeEverything(LLNotificationPtr p) - { - return true; - } + // a sample filter + bool includeEverything(LLNotificationPtr p) + { + return true; + } }; LLNotificationForm::LLNotificationForm() -: mIgnore(IGNORE_NO) +: mIgnore(IGNORE_NO) { } LLNotificationForm::LLNotificationForm( const LLNotificationForm& other ) { - mFormData = other.mFormData; - mIgnore = other.mIgnore; - mIgnoreMsg = other.mIgnoreMsg; - mIgnoreSetting = other.mIgnoreSetting; - mInvertSetting = other.mInvertSetting; -} - -LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p) -: mIgnore(IGNORE_NO), - mInvertSetting(false) // ignore settings by default mean true=show, false=ignore -{ - if (p.ignore.isProvided()) - { - // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences - mIgnoreMsg = p.ignore.text; - - LLUI *ui_inst = LLUI::getInstance(); - if (p.ignore.checkbox_only) - { - mIgnore = IGNORE_CHECKBOX_ONLY; - } - else if (!p.ignore.save_option) - { - mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; - } - else - { - // remember last option chosen by user and automatically respond with that in the future - mIgnore = IGNORE_WITH_LAST_RESPONSE; - ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); - } - - BOOL show_notification = TRUE; - if (p.ignore.control.isProvided()) - { - mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); - mInvertSetting = p.ignore.invert_control; - } - else if (mIgnore > IGNORE_NO) - { - ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); - mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); - } - } - - LLParamSDParser parser; - parser.writeSD(mFormData, p.form_elements); - - for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray(); - it != end_it; - ++it) - { - // lift contents of form element up a level, since element type is already encoded in "type" param - if (it->isMap() && it->beginMap() != it->endMap()) - { - *it = it->beginMap()->second; - } - } - - LL_DEBUGS("Notifications") << name << LL_ENDL; - LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL; + mFormData = other.mFormData; + mIgnore = other.mIgnore; + mIgnoreMsg = other.mIgnoreMsg; + mIgnoreSetting = other.mIgnoreSetting; + mInvertSetting = other.mInvertSetting; +} + +LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p) +: mIgnore(IGNORE_NO), + mInvertSetting(false) // ignore settings by default mean true=show, false=ignore +{ + if (p.ignore.isProvided()) + { + // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences + mIgnoreMsg = p.ignore.text; + + LLUI *ui_inst = LLUI::getInstance(); + if (p.ignore.checkbox_only) + { + mIgnore = IGNORE_CHECKBOX_ONLY; + } + else if (!p.ignore.save_option) + { + mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; + } + else + { + // remember last option chosen by user and automatically respond with that in the future + mIgnore = IGNORE_WITH_LAST_RESPONSE; + ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); + } + + BOOL show_notification = TRUE; + if (p.ignore.control.isProvided()) + { + mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); + mInvertSetting = p.ignore.invert_control; + } + else if (mIgnore > IGNORE_NO) + { + ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); + mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); + } + } + + LLParamSDParser parser; + parser.writeSD(mFormData, p.form_elements); + + for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray(); + it != end_it; + ++it) + { + // lift contents of form element up a level, since element type is already encoded in "type" param + if (it->isMap() && it->beginMap() != it->endMap()) + { + *it = it->beginMap()->second; + } + } + + LL_DEBUGS("Notifications") << name << LL_ENDL; + LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL; } LLNotificationForm::LLNotificationForm(const LLSD& sd) - : mIgnore(IGNORE_NO) + : mIgnore(IGNORE_NO) { - if (sd.isArray()) - { - mFormData = sd; - } - else - { - LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL; - mFormData = LLSD::emptyArray(); - } + if (sd.isArray()) + { + mFormData = sd; + } + else + { + LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL; + mFormData = LLSD::emptyArray(); + } } LLSD LLNotificationForm::asLLSD() const -{ - return mFormData; +{ + return mFormData; } LLSD LLNotificationForm::getElement(const std::string& element_name) { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) return (*it); - } - return LLSD(); + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return (*it); + } + return LLSD(); } bool LLNotificationForm::hasElement(const std::string& element_name) const { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) return true; - } - return false; + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return true; + } + return false; } void LLNotificationForm::getElements(LLSD& elements, S32 offset) @@ -302,241 +303,241 @@ void LLNotificationForm::getElements(LLSD& elements, S32 offset) bool LLNotificationForm::getElementEnabled(const std::string& element_name) const { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) - { - return (*it)["enabled"].asBoolean(); - } - } + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) + { + return (*it)["enabled"].asBoolean(); + } + } - return false; + return false; } void LLNotificationForm::setElementEnabled(const std::string& element_name, bool enabled) { - for (LLSD::array_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) - { - (*it)["enabled"] = enabled; - } - } + for (LLSD::array_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) + { + (*it)["enabled"] = enabled; + } + } } void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value, bool enabled) { - LLSD element; - element["type"] = type; - element["name"] = name; - element["text"] = name; - element["value"] = value; - element["index"] = LLSD::Integer(mFormData.size()); - element["enabled"] = enabled; - mFormData.append(element); + LLSD element; + element["type"] = type; + element["name"] = name; + element["text"] = name; + element["value"] = value; + element["index"] = LLSD::Integer(mFormData.size()); + element["enabled"] = enabled; + mFormData.append(element); } void LLNotificationForm::append(const LLSD& sub_form) { - if (sub_form.isArray()) - { - for (LLSD::array_const_iterator it = sub_form.beginArray(); - it != sub_form.endArray(); - ++it) - { - mFormData.append(*it); - } - } + if (sub_form.isArray()) + { + for (LLSD::array_const_iterator it = sub_form.beginArray(); + it != sub_form.endArray(); + ++it) + { + mFormData.append(*it); + } + } } void LLNotificationForm::formatElements(const LLSD& substitutions) { - for (LLSD::array_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - // format "text" component of each form element - if ((*it).has("text")) - { - std::string text = (*it)["text"].asString(); - LLStringUtil::format(text, substitutions); - (*it)["text"] = text; - } - if ((*it)["type"].asString() == "text" && (*it).has("value")) - { - std::string value = (*it)["value"].asString(); - LLStringUtil::format(value, substitutions); - (*it)["value"] = value; - } - } + for (LLSD::array_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + // format "text" component of each form element + if ((*it).has("text")) + { + std::string text = (*it)["text"].asString(); + LLStringUtil::format(text, substitutions); + (*it)["text"] = text; + } + if ((*it)["type"].asString() == "text" && (*it).has("value")) + { + std::string value = (*it)["value"].asString(); + LLStringUtil::format(value, substitutions); + (*it)["value"] = value; + } + } } std::string LLNotificationForm::getDefaultOption() { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["default"]) return (*it)["name"].asString(); - } - return ""; + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["default"]) return (*it)["name"].asString(); + } + return ""; } -LLControlVariablePtr LLNotificationForm::getIgnoreSetting() -{ - return mIgnoreSetting; +LLControlVariablePtr LLNotificationForm::getIgnoreSetting() +{ + return mIgnoreSetting; } bool LLNotificationForm::getIgnored() { - bool show = true; - if (mIgnore > LLNotificationForm::IGNORE_NO - && mIgnoreSetting) - { - show = mIgnoreSetting->getValue().asBoolean(); - if (mInvertSetting) show = !show; - } - return !show; + bool show = true; + if (mIgnore > LLNotificationForm::IGNORE_NO + && mIgnoreSetting) + { + show = mIgnoreSetting->getValue().asBoolean(); + if (mInvertSetting) show = !show; + } + return !show; } void LLNotificationForm::setIgnored(bool ignored) { - if (mIgnoreSetting) - { - if (mInvertSetting) ignored = !ignored; - mIgnoreSetting->setValue(!ignored); - } + if (mIgnoreSetting) + { + if (mInvertSetting) ignored = !ignored; + mIgnoreSetting->setValue(!ignored); + } } LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p) -: mName(p.name), - mType(p.type), - mMessage(p.value), - mFooter(p.footer.value), - mLabel(p.label), - mIcon(p.icon), - mURL(p.url.value), - mExpireSeconds(p.duration), - mExpireOption(p.expire_option), - mURLOption(p.url.option), - mURLTarget(p.url.target), - mForceUrlsExternal(p.force_urls_external), - mUnique(p.unique.isProvided()), - mCombineBehavior(p.unique.combine), - mPriority(p.priority), - mPersist(p.persist), - mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()), - mLogToChat(p.log_to_chat), - mLogToIM(p.log_to_im), - mShowToast(p.show_toast), - mFadeToast(p.fade_toast), +: mName(p.name), + mType(p.type), + mMessage(p.value), + mFooter(p.footer.value), + mLabel(p.label), + mIcon(p.icon), + mURL(p.url.value), + mExpireSeconds(p.duration), + mExpireOption(p.expire_option), + mURLOption(p.url.option), + mURLTarget(p.url.target), + mForceUrlsExternal(p.force_urls_external), + mUnique(p.unique.isProvided()), + mCombineBehavior(p.unique.combine), + mPriority(p.priority), + mPersist(p.persist), + mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()), + mLogToChat(p.log_to_chat), + mLogToIM(p.log_to_im), + mShowToast(p.show_toast), + mFadeToast(p.fade_toast), mSoundName("") { - if (p.sound.isProvided() - && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound)) - { - mSoundName = p.sound; - } + if (p.sound.isProvided() + && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound)) + { + mSoundName = p.sound; + } + + for (const LLNotificationTemplate::UniquenessContext& context : p.unique.contexts) + { + mUniqueContext.push_back(context.value); + } - for (const LLNotificationTemplate::UniquenessContext& context : p.unique.contexts) - { - mUniqueContext.push_back(context.value); - } - - LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; - - for (const LLNotificationTemplate::Tag& tag : p.tags) - { - LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; - mTags.push_back(tag.value); - } + LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; - mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); + for (const LLNotificationTemplate::Tag& tag : p.tags) + { + LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; + mTags.push_back(tag.value); + } + + mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); } LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p) { - if (p.show.isChosen()) - { - mType = p.show.type; - mTag = p.show.tag; - mName = p.show.name; - mVisible = true; - } - else if (p.hide.isChosen()) - { - mType = p.hide.type; - mTag = p.hide.tag; - mName = p.hide.name; - mVisible = false; - } - else if (p.respond.isChosen()) - { - mType = p.respond.type; - mTag = p.respond.tag; - mName = p.respond.name; - mVisible = false; - mResponse = p.respond.response; - } -} - -LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) : - mTimestamp(p.time_stamp), - mSubstitutions(p.substitutions), - mPayload(p.payload), - mExpiresAt(p.expiry), - mTemporaryResponder(false), - mRespondedTo(false), - mPriority(p.priority), - mCancelled(false), - mIgnored(false), - mResponderObj(NULL), - mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()), - mOfferFromAgent(p.offer_from_agent), + if (p.show.isChosen()) + { + mType = p.show.type; + mTag = p.show.tag; + mName = p.show.name; + mVisible = true; + } + else if (p.hide.isChosen()) + { + mType = p.hide.type; + mTag = p.hide.tag; + mName = p.hide.name; + mVisible = false; + } + else if (p.respond.isChosen()) + { + mType = p.respond.type; + mTag = p.respond.tag; + mName = p.respond.name; + mVisible = false; + mResponse = p.respond.response; + } +} + +LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) : + mTimestamp(p.time_stamp), + mSubstitutions(p.substitutions), + mPayload(p.payload), + mExpiresAt(p.expiry), + mTemporaryResponder(false), + mRespondedTo(false), + mPriority(p.priority), + mCancelled(false), + mIgnored(false), + mResponderObj(NULL), + mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()), + mOfferFromAgent(p.offer_from_agent), mIsDND(p.is_dnd) { - if (p.functor.name.isChosen()) - { - mResponseFunctorName = p.functor.name; - } - else if (p.functor.function.isChosen()) - { - mResponseFunctorName = LLUUID::generateNewID().asString(); - LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function()); + if (p.functor.name.isChosen()) + { + mResponseFunctorName = p.functor.name; + } + else if (p.functor.function.isChosen()) + { + mResponseFunctorName = LLUUID::generateNewID().asString(); + LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function()); - mTemporaryResponder = true; - } - else if(p.functor.responder.isChosen()) - { - mResponder = p.functor.responder; - } + mTemporaryResponder = true; + } + else if(p.functor.responder.isChosen()) + { + mResponder = p.functor.responder; + } - if(p.responder.isProvided()) - { - mResponderObj = p.responder; - } + if(p.responder.isProvided()) + { + mResponderObj = p.responder; + } - init(p.name, p.form_elements); + init(p.name, p.form_elements); } LLSD LLNotification::asLLSD(bool excludeTemplateElements) -{ - LLParamSDParser parser; - - Params p; - p.id = mId; - p.name = mTemplatep->mName; - p.substitutions = mSubstitutions; - p.payload = mPayload; - p.time_stamp = mTimestamp; - p.expiry = mExpiresAt; - p.priority = mPriority; +{ + LLParamSDParser parser; + + Params p; + p.id = mId; + p.name = mTemplatep->mName; + p.substitutions = mSubstitutions; + p.payload = mPayload; + p.time_stamp = mTimestamp; + p.expiry = mExpiresAt; + p.priority = mPriority; LLNotificationFormPtr templateForm = mTemplatep->mForm; LLSD formElements = mForm->asLLSD(); @@ -560,202 +561,202 @@ LLSD LLNotification::asLLSD(bool excludeTemplateElements) p.functor.responder_sd = mResponder->asLLSD(); } - if(!mResponseFunctorName.empty()) - { - p.functor.name = mResponseFunctorName; - } + if(!mResponseFunctorName.empty()) + { + p.functor.name = mResponseFunctorName; + } - LLSD output; - parser.writeSD(output, p); - return output; + LLSD output; + parser.writeSD(output, p); + return output; } void LLNotification::update() { - LLNotifications::instance().update(shared_from_this()); + LLNotifications::instance().update(shared_from_this()); } void LLNotification::updateFrom(LLNotificationPtr other) { - // can only update from the same notification type - if (mTemplatep != other->mTemplatep) return; + // can only update from the same notification type + if (mTemplatep != other->mTemplatep) return; - // NOTE: do NOT change the ID, since it is the key to - // this given instance, just update all the metadata - //mId = other->mId; + // NOTE: do NOT change the ID, since it is the key to + // this given instance, just update all the metadata + //mId = other->mId; - mPayload = other->mPayload; - mSubstitutions = other->mSubstitutions; - mTimestamp = other->mTimestamp; - mExpiresAt = other->mExpiresAt; - mCancelled = other->mCancelled; - mIgnored = other->mIgnored; - mPriority = other->mPriority; - mForm = other->mForm; - mResponseFunctorName = other->mResponseFunctorName; - mRespondedTo = other->mRespondedTo; - mResponse = other->mResponse; - mTemporaryResponder = other->mTemporaryResponder; + mPayload = other->mPayload; + mSubstitutions = other->mSubstitutions; + mTimestamp = other->mTimestamp; + mExpiresAt = other->mExpiresAt; + mCancelled = other->mCancelled; + mIgnored = other->mIgnored; + mPriority = other->mPriority; + mForm = other->mForm; + mResponseFunctorName = other->mResponseFunctorName; + mRespondedTo = other->mRespondedTo; + mResponse = other->mResponse; + mTemporaryResponder = other->mTemporaryResponder; - update(); + update(); } const LLNotificationFormPtr LLNotification::getForm() { - return mForm; + return mForm; } void LLNotification::cancel() { - mCancelled = true; + mCancelled = true; } LLSD LLNotification::getResponseTemplate(EResponseTemplateType type) { - LLSD response = LLSD::emptyMap(); - for (S32 element_idx = 0; - element_idx < mForm->getNumElements(); - ++element_idx) - { - LLSD element = mForm->getElement(element_idx); - if (element.has("name")) - { - response[element["name"].asString()] = element["value"]; - } - - if ((type == WITH_DEFAULT_BUTTON) - && element["default"].asBoolean()) - { - response[element["name"].asString()] = true; - } - } - return response; + LLSD response = LLSD::emptyMap(); + for (S32 element_idx = 0; + element_idx < mForm->getNumElements(); + ++element_idx) + { + LLSD element = mForm->getElement(element_idx); + if (element.has("name")) + { + response[element["name"].asString()] = element["value"]; + } + + if ((type == WITH_DEFAULT_BUTTON) + && element["default"].asBoolean()) + { + response[element["name"].asString()] = true; + } + } + return response; } //static S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) { - LLNotificationForm form(notification["form"]); - - for (S32 element_idx = 0; - element_idx < form.getNumElements(); - ++element_idx) - { - LLSD element = form.getElement(element_idx); + LLNotificationForm form(notification["form"]); - // only look at buttons - if (element["type"].asString() == "button" - && response[element["name"].asString()].asBoolean()) - { - return element["index"].asInteger(); - } - } + for (S32 element_idx = 0; + element_idx < form.getNumElements(); + ++element_idx) + { + LLSD element = form.getElement(element_idx); + + // only look at buttons + if (element["type"].asString() == "button" + && response[element["name"].asString()].asBoolean()) + { + return element["index"].asInteger(); + } + } - return -1; + return -1; } //static std::string LLNotification::getSelectedOptionName(const LLSD& response) { - for (LLSD::map_const_iterator response_it = response.beginMap(); - response_it != response.endMap(); - ++response_it) - { - if (response_it->second.isBoolean() && response_it->second.asBoolean()) - { - return response_it->first; - } - } - return ""; + for (LLSD::map_const_iterator response_it = response.beginMap(); + response_it != response.endMap(); + ++response_it) + { + if (response_it->second.isBoolean() && response_it->second.asBoolean()) + { + return response_it->first; + } + } + return ""; } void LLNotification::respond(const LLSD& response) { - // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() - mRespondedTo = true; - mResponse = response; - - if(mResponder) - { - mResponder->handleRespond(asLLSD(), response); - } - else if (!mResponseFunctorName.empty()) - { - // look up the functor - LLNotificationFunctorRegistry::ResponseFunctor functor = - LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); - // and then call it - functor(asLLSD(), response); - } - else if (mCombinedNotifications.empty()) - { - // no registered responder - return; - } - - if (mTemporaryResponder) - { - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - mResponseFunctorName = ""; - mTemporaryResponder = false; - } - - if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - mForm->setIgnored(mIgnored); - if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response); - } - } - - for (std::vector<LLNotificationPtr>::const_iterator it = mCombinedNotifications.begin(); it != mCombinedNotifications.end(); ++it) - { - if ((*it)) - { - (*it)->respond(response); - } - } - - update(); + // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() + mRespondedTo = true; + mResponse = response; + + if(mResponder) + { + mResponder->handleRespond(asLLSD(), response); + } + else if (!mResponseFunctorName.empty()) + { + // look up the functor + LLNotificationFunctorRegistry::ResponseFunctor functor = + LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); + // and then call it + functor(asLLSD(), response); + } + else if (mCombinedNotifications.empty()) + { + // no registered responder + return; + } + + if (mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = ""; + mTemporaryResponder = false; + } + + if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + mForm->setIgnored(mIgnored); + if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response); + } + } + + for (std::vector<LLNotificationPtr>::const_iterator it = mCombinedNotifications.begin(); it != mCombinedNotifications.end(); ++it) + { + if ((*it)) + { + (*it)->respond(response); + } + } + + update(); } void LLNotification::respondWithDefault() { - respond(getResponseTemplate(WITH_DEFAULT_BUTTON)); + respond(getResponseTemplate(WITH_DEFAULT_BUTTON)); } const std::string& LLNotification::getName() const { - return mTemplatep->mName; + return mTemplatep->mName; } const std::string& LLNotification::getIcon() const { - return mTemplatep->mIcon; + return mTemplatep->mIcon; } bool LLNotification::isPersistent() const { - return mTemplatep->mPersist; + return mTemplatep->mPersist; } std::string LLNotification::getType() const { - return (mTemplatep ? mTemplatep->mType : ""); + return (mTemplatep ? mTemplatep->mType : ""); } S32 LLNotification::getURLOption() const { - return (mTemplatep ? mTemplatep->mURLOption : -1); + return (mTemplatep ? mTemplatep->mURLOption : -1); } S32 LLNotification::getURLOpenExternally() const { - return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); + return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); } bool LLNotification::getForceUrlsExternal() const @@ -763,223 +764,223 @@ bool LLNotification::getForceUrlsExternal() const return (mTemplatep ? mTemplatep->mForceUrlsExternal : false); } -bool LLNotification::hasUniquenessConstraints() const -{ - return (mTemplatep ? mTemplatep->mUnique : false); +bool LLNotification::hasUniquenessConstraints() const +{ + return (mTemplatep ? mTemplatep->mUnique : false); } bool LLNotification::matchesTag(const std::string& tag) { - bool result = false; - - if(mTemplatep) - { - std::list<std::string>::iterator it; - for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++) - { - if((*it) == tag) - { - result = true; - break; - } - } - } - - return result; + bool result = false; + + if(mTemplatep) + { + std::list<std::string>::iterator it; + for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++) + { + if((*it) == tag) + { + result = true; + break; + } + } + } + + return result; } void LLNotification::setIgnored(bool ignore) { - mIgnored = ignore; + mIgnored = ignore; } void LLNotification::setResponseFunctor(std::string const &responseFunctorName) { - if (mTemporaryResponder) - // get rid of the old one - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - mResponseFunctorName = responseFunctorName; - mTemporaryResponder = false; + if (mTemporaryResponder) + // get rid of the old one + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = responseFunctorName; + mTemporaryResponder = false; } void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb) { - if(mTemporaryResponder) - { - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - } + if(mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + } - LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); + LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); } void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder) { - mResponder = responder; + mResponder = responder; } bool LLNotification::isEquivalentTo(LLNotificationPtr that) const { - if (this->mTemplatep->mName != that->mTemplatep->mName) - { - return false; // must have the same template name or forget it - } - if (this->mTemplatep->mUnique) - { - const LLSD& these_substitutions = this->getSubstitutions(); - const LLSD& those_substitutions = that->getSubstitutions(); - const LLSD& this_payload = this->getPayload(); - const LLSD& that_payload = that->getPayload(); - - // highlander bit sez there can only be one of these - for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end(); - it != end_it; - ++it) - { - // if templates differ in either substitution strings or payload with the given field name - // then they are considered inequivalent - // use of get() avoids converting the LLSD value to a map as the [] operator would - if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() - || this_payload.get(*it).asString() != that_payload.get(*it).asString()) - { - return false; - } - } - return true; - } - - return false; + if (this->mTemplatep->mName != that->mTemplatep->mName) + { + return false; // must have the same template name or forget it + } + if (this->mTemplatep->mUnique) + { + const LLSD& these_substitutions = this->getSubstitutions(); + const LLSD& those_substitutions = that->getSubstitutions(); + const LLSD& this_payload = this->getPayload(); + const LLSD& that_payload = that->getPayload(); + + // highlander bit sez there can only be one of these + for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end(); + it != end_it; + ++it) + { + // if templates differ in either substitution strings or payload with the given field name + // then they are considered inequivalent + // use of get() avoids converting the LLSD value to a map as the [] operator would + if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() + || this_payload.get(*it).asString() != that_payload.get(*it).asString()) + { + return false; + } + } + return true; + } + + return false; } void LLNotification::init(const std::string& template_name, const LLSD& form_elements) { - mTemplatep = LLNotifications::instance().getTemplate(template_name); - if (!mTemplatep) return; - - // add default substitutions - const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs(); - for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin(); - iter != default_args.end(); ++iter) - { - mSubstitutions[iter->first] = iter->second; - } - mSubstitutions["_URL"] = getURL(); - mSubstitutions["_NAME"] = template_name; - // TODO: something like this so that a missing alert is sensible: - //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); - - mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); + mTemplatep = LLNotifications::instance().getTemplate(template_name); + if (!mTemplatep) return; + + // add default substitutions + const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs(); + for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin(); + iter != default_args.end(); ++iter) + { + mSubstitutions[iter->first] = iter->second; + } + mSubstitutions["_URL"] = getURL(); + mSubstitutions["_NAME"] = template_name; + // TODO: something like this so that a missing alert is sensible: + //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); + + mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); mForm->append(form_elements); - // apply substitution to form labels - mForm->formatElements(mSubstitutions); + // apply substitution to form labels + mForm->formatElements(mSubstitutions); - mIgnored = mForm->getIgnored(); + mIgnored = mForm->getIgnored(); - LLDate rightnow = LLDate::now(); - if (mTemplatep->mExpireSeconds) - { - mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds); - } + LLDate rightnow = LLDate::now(); + if (mTemplatep->mExpireSeconds) + { + mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds); + } - if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED) - { - mPriority = mTemplatep->mPriority; - } + if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED) + { + mPriority = mTemplatep->mPriority; + } } std::string LLNotification::summarize() const { - std::string s = "Notification("; - s += getName(); - s += ") : "; - s += mTemplatep ? mTemplatep->mMessage : ""; - // should also include timestamp and expiration time (but probably not payload) - return s; + std::string s = "Notification("; + s += getName(); + s += ") : "; + s += mTemplatep ? mTemplatep->mMessage : ""; + // should also include timestamp and expiration time (but probably not payload) + return s; } std::string LLNotification::getMessage() const { - // all our callers cache this result, so it gives us more flexibility - // to do the substitution at call time rather than attempting to - // cache it in the notification - if (!mTemplatep) - return std::string(); + // all our callers cache this result, so it gives us more flexibility + // to do the substitution at call time rather than attempting to + // cache it in the notification + if (!mTemplatep) + return std::string(); - std::string message = mTemplatep->mMessage; - LLStringUtil::format(message, mSubstitutions); - return message; + std::string message = mTemplatep->mMessage; + LLStringUtil::format(message, mSubstitutions); + return message; } std::string LLNotification::getFooter() const { - if (!mTemplatep) - return std::string(); + if (!mTemplatep) + return std::string(); - std::string footer = mTemplatep->mFooter; - LLStringUtil::format(footer, mSubstitutions); - return footer; + std::string footer = mTemplatep->mFooter; + LLStringUtil::format(footer, mSubstitutions); + return footer; } std::string LLNotification::getLabel() const { - std::string label = mTemplatep->mLabel; - LLStringUtil::format(label, mSubstitutions); - return (mTemplatep ? label : ""); + std::string label = mTemplatep->mLabel; + LLStringUtil::format(label, mSubstitutions); + return (mTemplatep ? label : ""); } std::string LLNotification::getURL() const { - if (!mTemplatep) - return std::string(); - std::string url = mTemplatep->mURL; - LLStringUtil::format(url, mSubstitutions); - return (mTemplatep ? url : ""); + if (!mTemplatep) + return std::string(); + std::string url = mTemplatep->mURL; + LLStringUtil::format(url, mSubstitutions); + return (mTemplatep ? url : ""); } bool LLNotification::canLogToChat() const { - return mTemplatep->mLogToChat; + return mTemplatep->mLogToChat; } bool LLNotification::canLogToIM() const { - return mTemplatep->mLogToIM; + return mTemplatep->mLogToIM; } bool LLNotification::canShowToast() const { - return mTemplatep->mShowToast; + return mTemplatep->mShowToast; } bool LLNotification::canFadeToast() const { - return mTemplatep->mFadeToast; + return mTemplatep->mFadeToast; } bool LLNotification::hasFormElements() const { - return mTemplatep->mForm->getNumElements() != 0; + return mTemplatep->mForm->getNumElements() != 0; } void LLNotification::playSound() -{ +{ make_ui_sound(mTemplatep->mSoundName.c_str()); } LLNotification::ECombineBehavior LLNotification::getCombineBehavior() const { - return mTemplatep->mCombineBehavior; + return mTemplatep->mCombineBehavior; } void LLNotification::updateForm( const LLNotificationFormPtr& form ) { - mForm = form; + mForm = form; } void LLNotification::repost() { - mRespondedTo = false; - LLNotifications::instance().update(shared_from_this()); + mRespondedTo = false; + LLNotifications::instance().update(shared_from_this()); } @@ -989,50 +990,50 @@ void LLNotification::repost() // --- LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot) { - // when someone wants to connect to a channel, we first throw them - // all of the notifications that are already in the channel - // we use a special signal called "load" in case the channel wants to care - // only about new notifications + // when someone wants to connect to a channel, we first throw them + // all of the notifications that are already in the channel + // we use a special signal called "load" in case the channel wants to care + // only about new notifications LLMutexLock lock(&mItemsMutex); - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); - } - // and then connect the signal so that all future notifications will also be - // forwarded. - return mChanged.connect(slot); + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); + } + // and then connect the signal so that all future notifications will also be + // forwarded. + return mChanged.connect(slot); } LLBoundListener LLNotificationChannelBase::connectAtFrontChangedImpl(const LLEventListener& slot) { - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); - } - return mChanged.connect(slot, boost::signals2::at_front); + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); + } + return mChanged.connect(slot, boost::signals2::at_front); } LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot) { - // these two filters only fire for notifications added after the current one, because - // they don't participate in the hierarchy. - return mPassedFilter.connect(slot); + // these two filters only fire for notifications added after the current one, because + // they don't participate in the hierarchy. + return mPassedFilter.connect(slot); } LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot) { - return mFailedFilter.connect(slot); + return mFailedFilter.connect(slot); } // external call, conforms to our standard signature bool LLNotificationChannelBase::updateItem(const LLSD& payload) -{ - // first check to see if it's in the master list - LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]); - if (!pNotification) - return false; // not found - - return updateItem(payload, pNotification); +{ + // first check to see if it's in the master list + LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]); + if (!pNotification) + return false; // not found + + return updateItem(payload, pNotification); } @@ -1041,134 +1042,134 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload) // internal call, for use in avoiding lookup bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) -{ - std::string cmd = payload["sigtype"]; - LLNotificationSet::iterator foundItem = mItems.find(pNotification); - bool wasFound = (foundItem != mItems.end()); - bool passesFilter = mFilter ? mFilter(pNotification) : true; - - // first, we offer the result of the filter test to the simple - // signals for pass/fail. One of these is guaranteed to be called. - // If either signal returns true, the change processing is NOT performed - // (so don't return true unless you know what you're doing!) - bool abortProcessing = false; - if (passesFilter) - { - onFilterPass(pNotification); - abortProcessing = mPassedFilter(payload); - } - else - { - onFilterFail(pNotification); - abortProcessing = mFailedFilter(payload); - } - - if (abortProcessing) - { - return true; - } - - if (cmd == "load") - { - // should be no reason we'd ever get a load if we already have it - // if passes filter send a load message, else do nothing - assert(!wasFound); - if (passesFilter) - { - // not in our list, add it and say so - mItems.insert(pNotification); - onLoad(pNotification); - abortProcessing = mChanged(payload); - } - } - else if (cmd == "change") - { - // if it passes filter now and was found, we just send a change message - // if it passes filter now and wasn't found, we have to add it - // if it doesn't pass filter and wasn't found, we do nothing - // if it doesn't pass filter and was found, we need to delete it - if (passesFilter) - { - if (wasFound) - { - // it already existed, so this is a change - // since it changed in place, all we have to do is resend the signal - onChange(pNotification); - abortProcessing = mChanged(payload); - } - else - { - // not in our list, add it and say so - mItems.insert(pNotification); - onChange(pNotification); - // our payload is const, so make a copy before changing it - LLSD newpayload = payload; - newpayload["sigtype"] = "add"; - abortProcessing = mChanged(newpayload); - } - } - else - { - if (wasFound) - { - // it already existed, so this is a delete - mItems.erase(pNotification); - onChange(pNotification); - // our payload is const, so make a copy before changing it - LLSD newpayload = payload; - newpayload["sigtype"] = "delete"; - abortProcessing = mChanged(newpayload); - } - // didn't pass, not on our list, do nothing - } - } - else if (cmd == "add") - { - // should be no reason we'd ever get an add if we already have it - // if passes filter send an add message, else do nothing - assert(!wasFound); - if (passesFilter) - { - // not in our list, add it and say so - mItems.insert(pNotification); - onAdd(pNotification); - abortProcessing = mChanged(payload); - } - } - else if (cmd == "delete") - { - // if we have it in our list, pass on the delete, then delete it, else do nothing - if (wasFound) - { - onDelete(pNotification); - abortProcessing = mChanged(payload); - mItems.erase(pNotification); - } - } - return abortProcessing; +{ + std::string cmd = payload["sigtype"]; + LLNotificationSet::iterator foundItem = mItems.find(pNotification); + bool wasFound = (foundItem != mItems.end()); + bool passesFilter = mFilter ? mFilter(pNotification) : true; + + // first, we offer the result of the filter test to the simple + // signals for pass/fail. One of these is guaranteed to be called. + // If either signal returns true, the change processing is NOT performed + // (so don't return true unless you know what you're doing!) + bool abortProcessing = false; + if (passesFilter) + { + onFilterPass(pNotification); + abortProcessing = mPassedFilter(payload); + } + else + { + onFilterFail(pNotification); + abortProcessing = mFailedFilter(payload); + } + + if (abortProcessing) + { + return true; + } + + if (cmd == "load") + { + // should be no reason we'd ever get a load if we already have it + // if passes filter send a load message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + onLoad(pNotification); + abortProcessing = mChanged(payload); + } + } + else if (cmd == "change") + { + // if it passes filter now and was found, we just send a change message + // if it passes filter now and wasn't found, we have to add it + // if it doesn't pass filter and wasn't found, we do nothing + // if it doesn't pass filter and was found, we need to delete it + if (passesFilter) + { + if (wasFound) + { + // it already existed, so this is a change + // since it changed in place, all we have to do is resend the signal + onChange(pNotification); + abortProcessing = mChanged(payload); + } + else + { + // not in our list, add it and say so + mItems.insert(pNotification); + onChange(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "add"; + abortProcessing = mChanged(newpayload); + } + } + else + { + if (wasFound) + { + // it already existed, so this is a delete + mItems.erase(pNotification); + onChange(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "delete"; + abortProcessing = mChanged(newpayload); + } + // didn't pass, not on our list, do nothing + } + } + else if (cmd == "add") + { + // should be no reason we'd ever get an add if we already have it + // if passes filter send an add message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + onAdd(pNotification); + abortProcessing = mChanged(payload); + } + } + else if (cmd == "delete") + { + // if we have it in our list, pass on the delete, then delete it, else do nothing + if (wasFound) + { + onDelete(pNotification); + abortProcessing = mChanged(payload); + mItems.erase(pNotification); + } + } + return abortProcessing; } LLNotificationChannel::LLNotificationChannel(const Params& p) -: LLNotificationChannelBase(p.filter()), - LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()), - mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()) +: LLNotificationChannelBase(p.filter()), + LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()), + mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()) { - for (const std::string& source : p.sources) + for (const std::string& source : p.sources) { - connectToChannel(source); - } + connectToChannel(source); + } } -LLNotificationChannel::LLNotificationChannel(const std::string& name, - const std::string& parent, - LLNotificationFilter filter) -: LLNotificationChannelBase(filter), - LLInstanceTracker<LLNotificationChannel, std::string>(name), - mName(name) +LLNotificationChannel::LLNotificationChannel(const std::string& name, + const std::string& parent, + LLNotificationFilter filter) +: LLNotificationChannelBase(filter), + LLInstanceTracker<LLNotificationChannel, std::string>(name), + mName(name) { - // bind to notification broadcast - connectToChannel(parent); + // bind to notification broadcast + connectToChannel(parent); } LLNotificationChannel::~LLNotificationChannel() @@ -1181,7 +1182,7 @@ LLNotificationChannel::~LLNotificationChannel() bool LLNotificationChannel::isEmpty() const { - return mItems.empty(); + return mItems.empty(); } S32 LLNotificationChannel::size() const @@ -1191,7 +1192,7 @@ S32 LLNotificationChannel::size() const size_t LLNotificationChannel::size() { - return mItems.size(); + return mItems.size(); } void LLNotificationChannel::forEachNotification(NotificationProcess process) @@ -1202,31 +1203,31 @@ void LLNotificationChannel::forEachNotification(NotificationProcess process) std::string LLNotificationChannel::summarize() { - std::string s("Channel '"); - s += mName; - s += "'\n "; + std::string s("Channel '"); + s += mName; + s += "'\n "; LLMutexLock lock(&mItemsMutex); - for (LLNotificationChannel::Iterator it = mItems.begin(); it != mItems.end(); ++it) - { - s += (*it)->summarize(); - s += "\n "; - } - return s; + for (LLNotificationChannel::Iterator it = mItems.begin(); it != mItems.end(); ++it) + { + s += (*it)->summarize(); + s += "\n "; + } + return s; } void LLNotificationChannel::connectToChannel( const std::string& channel_name ) { - if (channel_name.empty()) - { + if (channel_name.empty()) + { mListeners.push_back(LLNotifications::instance().connectChanged( - boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); - } - else - { - mParents.push_back(channel_name); - LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); + boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); + } + else + { + mParents.push_back(channel_name); + LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); mListeners.push_back(p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); - } + } } // --- @@ -1234,18 +1235,18 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name ) // ========================================================= -// ============================================== =========== +// ============================================== =========== // LLNotifications implementation // --- -LLNotifications::LLNotifications() -: LLNotificationChannelBase(LLNotificationFilters::includeEverything), - mIgnoreAllNotifications(false) +LLNotifications::LLNotifications() +: LLNotificationChannelBase(LLNotificationFilters::includeEverything), + mIgnoreAllNotifications(false) { mListener.reset(new LLNotificationsListener(*this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); - // touch the instance tracker for notification channels, so that it will still be around in our destructor - LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); + // touch the instance tracker for notification channels, so that it will still be around in our destructor + LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); } void LLNotifications::clear() @@ -1256,152 +1257,152 @@ void LLNotifications::clear() // The expiration channel gets all notifications that are cancelled bool LLNotifications::expirationFilter(LLNotificationPtr pNotification) { - return pNotification->isCancelled() || pNotification->isRespondedTo(); + return pNotification->isCancelled() || pNotification->isRespondedTo(); } bool LLNotifications::expirationHandler(const LLSD& payload) { - if (payload["sigtype"].asString() != "delete") - { - // anything added to this channel actually should be deleted from the master - cancel(find(payload["id"])); - return true; // don't process this item any further - } - return false; + if (payload["sigtype"].asString() != "delete") + { + // anything added to this channel actually should be deleted from the master + cancel(find(payload["id"])); + return true; // don't process this item any further + } + return false; } bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif) { - if (!pNotif->hasUniquenessConstraints()) - { - return true; - } - - // checks against existing unique notifications - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - if (pNotif->getCombineBehavior() == LLNotification::CANCEL_OLD) - { - cancel(existing_notification); - return true; - } - else - { - return false; - } - } - } - - return true; + if (!pNotif->hasUniquenessConstraints()) + { + return true; + } + + // checks against existing unique notifications + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + if (pNotif->getCombineBehavior() == LLNotification::CANCEL_OLD) + { + cancel(existing_notification); + return true; + } + else + { + return false; + } + } + } + + return true; } bool LLNotifications::uniqueHandler(const LLSD& payload) { - std::string cmd = payload["sigtype"]; + std::string cmd = payload["sigtype"]; - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (pNotif && pNotif->hasUniquenessConstraints()) - { - if (cmd == "add") - { - // not a duplicate according to uniqueness criteria, so we keep it - // and store it for future uniqueness checks - mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); - } - else if (cmd == "delete") - { - mUniqueNotifications.erase(pNotif->getName()); - } - } + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (pNotif && pNotif->hasUniquenessConstraints()) + { + if (cmd == "add") + { + // not a duplicate according to uniqueness criteria, so we keep it + // and store it for future uniqueness checks + mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); + } + else if (cmd == "delete") + { + mUniqueNotifications.erase(pNotif->getName()); + } + } - return false; + return false; } bool LLNotifications::failedUniquenessTest(const LLSD& payload) { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - - std::string cmd = payload["sigtype"]; - - if (!pNotif || cmd != "add") - { - return false; - } - - switch(pNotif->getCombineBehavior()) - { - case LLNotification::REPLACE_WITH_NEW: - // Update the existing unique notification with the data from this particular instance... - // This guarantees that duplicate notifications will be collapsed to the one - // most recently triggered - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - // copy notification instance data over to oldest instance - // of this unique notification and update it - existing_notification->updateFrom(pNotif); - // then delete the new one - cancel(pNotif); - } - } - break; - case LLNotification::COMBINE_WITH_NEW: - // Add to the existing unique notification with the data from this particular instance... - // This guarantees that duplicate notifications will be collapsed to the one - // most recently triggered - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - // copy the notifications from the newest instance into the oldest - existing_notification->mCombinedNotifications.push_back(pNotif); - existing_notification->mCombinedNotifications.insert(existing_notification->mCombinedNotifications.end(), - pNotif->mCombinedNotifications.begin(), pNotif->mCombinedNotifications.end()); - - // pop up again - existing_notification->update(); - } - } - break; - case LLNotification::KEEP_OLD: - break; - case LLNotification::CANCEL_OLD: - // already handled by filter logic - break; - default: - break; - } - - return false; + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + + std::string cmd = payload["sigtype"]; + + if (!pNotif || cmd != "add") + { + return false; + } + + switch(pNotif->getCombineBehavior()) + { + case LLNotification::REPLACE_WITH_NEW: + // Update the existing unique notification with the data from this particular instance... + // This guarantees that duplicate notifications will be collapsed to the one + // most recently triggered + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + // copy notification instance data over to oldest instance + // of this unique notification and update it + existing_notification->updateFrom(pNotif); + // then delete the new one + cancel(pNotif); + } + } + break; + case LLNotification::COMBINE_WITH_NEW: + // Add to the existing unique notification with the data from this particular instance... + // This guarantees that duplicate notifications will be collapsed to the one + // most recently triggered + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + // copy the notifications from the newest instance into the oldest + existing_notification->mCombinedNotifications.push_back(pNotif); + existing_notification->mCombinedNotifications.insert(existing_notification->mCombinedNotifications.end(), + pNotif->mCombinedNotifications.begin(), pNotif->mCombinedNotifications.end()); + + // pop up again + existing_notification->update(); + } + } + break; + case LLNotification::KEEP_OLD: + break; + case LLNotification::CANCEL_OLD: + // already handled by filter logic + break; + default: + break; + } + + return false; } LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName) { - return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get()); + return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get()); } // this function is called once at construction time, after the object is constructed. void LLNotifications::initSingleton() { - loadTemplates(); - loadVisibilityRules(); - createDefaultChannels(); + loadTemplates(); + loadVisibilityRules(); + createDefaultChannels(); } void LLNotifications::cleanupSingleton() @@ -1412,525 +1413,530 @@ void LLNotifications::cleanupSingleton() void LLNotifications::createDefaultChannels() { LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL; - // now construct the various channels AFTER loading the notifications, - // because the history channel is going to rewrite the stored notifications file - mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "", - !boost::bind(&LLNotifications::getIgnoreAllNotifications, this))); - mDefaultChannels.push_back(new LLNotificationChannel("Expiration", "Enabled", - boost::bind(&LLNotifications::expirationFilter, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Unexpired", "Enabled", - !boost::bind(&LLNotifications::expirationFilter, this, _1))); // use negated bind - mDefaultChannels.push_back(new LLNotificationChannel("Unique", "Unexpired", - boost::bind(&LLNotifications::uniqueFilter, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Ignore", "Unique", - filterIgnoredNotifications)); - mDefaultChannels.push_back(new LLNotificationChannel("VisibilityRules", "Ignore", - boost::bind(&LLNotifications::isVisibleByRules, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Visible", "VisibilityRules", - &LLNotificationFilters::includeEverything)); - mDefaultChannels.push_back(new LLPersistentNotificationChannel()); - - // connect action methods to these channels - getChannel("Enabled")->connectFailedFilter(&defaultResponse); - getChannel("Expiration")->connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); - // uniqueHandler slot should be added as first slot of the signal due to - // usage LLStopWhenHandled combiner in LLStandardSignal - getChannel("Unique")->connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1)); - getChannel("Unique")->connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1)); - getChannel("Ignore")->connectFailedFilter(&handleIgnoredNotification); - getChannel("VisibilityRules")->connectFailedFilter(&visibilityRuleMached); + // now construct the various channels AFTER loading the notifications, + // because the history channel is going to rewrite the stored notifications file + mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "", + !boost::bind(&LLNotifications::getIgnoreAllNotifications, this))); + mDefaultChannels.push_back(new LLNotificationChannel("Expiration", "Enabled", + boost::bind(&LLNotifications::expirationFilter, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Unexpired", "Enabled", + !boost::bind(&LLNotifications::expirationFilter, this, _1))); // use negated bind + mDefaultChannels.push_back(new LLNotificationChannel("Unique", "Unexpired", + boost::bind(&LLNotifications::uniqueFilter, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Ignore", "Unique", + filterIgnoredNotifications)); + mDefaultChannels.push_back(new LLNotificationChannel("VisibilityRules", "Ignore", + boost::bind(&LLNotifications::isVisibleByRules, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Visible", "VisibilityRules", + &LLNotificationFilters::includeEverything)); + mDefaultChannels.push_back(new LLPersistentNotificationChannel()); + + // connect action methods to these channels + getChannel("Enabled")->connectFailedFilter(&defaultResponse); + getChannel("Expiration")->connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); + // uniqueHandler slot should be added as first slot of the signal due to + // usage LLStopWhenHandled combiner in LLStandardSignal + getChannel("Unique")->connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1)); + getChannel("Unique")->connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1)); + getChannel("Ignore")->connectFailedFilter(&handleIgnoredNotification); + getChannel("VisibilityRules")->connectFailedFilter(&visibilityRuleMached); } LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name) { - if (mTemplates.count(name)) - { - return mTemplates[name]; - } - else - { - return mTemplates["MissingAlert"]; - } + if (mTemplates.count(name)) + { + return mTemplates[name]; + } + else + { + return mTemplates["MissingAlert"]; + } } bool LLNotifications::templateExists(const std::string& name) { - return (mTemplates.count(name) != 0); + return (mTemplates.count(name) != 0); } void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) { - LLNotificationPtr temp_notify(new LLNotification(params)); - LLSD response = temp_notify->getResponseTemplate(); - LLSD selected_item = temp_notify->getForm()->getElement(option); - - if (selected_item.isUndefined()) - { - LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; - return; - } - response[selected_item["name"].asString()] = true; + LLNotificationPtr temp_notify(new LLNotification(params)); + LLSD response = temp_notify->getResponseTemplate(); + LLSD selected_item = temp_notify->getForm()->getElement(option); + + if (selected_item.isUndefined()) + { + LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; + return; + } + response[selected_item["name"].asString()] = true; - temp_notify->respond(response); + temp_notify->respond(response); } LLNotifications::TemplateNames LLNotifications::getTemplateNames() const { - TemplateNames names; - for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it) - { - names.push_back(it->first); - } - return names; + TemplateNames names; + for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it) + { + names.push_back(it->first); + } + return names; } typedef std::map<std::string, std::string> StringMap; void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { - // walk the list of attributes looking for replacements - for (LLXMLAttribList::iterator it=node->mAttributes.begin(); - it != node->mAttributes.end(); ++it) - { - std::string value = it->second->getValue(); - if (value[0] == '$') - { - value.erase(0, 1); // trim off the $ - std::string replacement; - StringMap::const_iterator found = replacements.find(value); - if (found != replacements.end()) - { - replacement = found->second; - LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; - it->second->setValue(replacement); - } - else - { - LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; - } - } - } - - // now walk the list of children and call this recursively. - for (LLXMLNodePtr child = node->getFirstChild(); - child.notNull(); child = child->getNextSibling()) - { - replaceSubstitutionStrings(child, replacements); - } + // walk the list of attributes looking for replacements + for (LLXMLAttribList::iterator it=node->mAttributes.begin(); + it != node->mAttributes.end(); ++it) + { + std::string value = it->second->getValue(); + if (value[0] == '$') + { + value.erase(0, 1); // trim off the $ + std::string replacement; + StringMap::const_iterator found = replacements.find(value); + if (found != replacements.end()) + { + replacement = found->second; + LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; + it->second->setValue(replacement); + } + else + { + LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; + } + } + } + + // now walk the list of children and call this recursively. + for (LLXMLNodePtr child = node->getFirstChild(); + child.notNull(); child = child->getNextSibling()) + { + replaceSubstitutionStrings(child, replacements); + } } void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace) { - if (form.ignore.isProvided() && form.ignore.text() == pattern) - { - form.ignore.text = replace; - } + if (form.ignore.isProvided() && form.ignore.text() == pattern) + { + form.ignore.text = replace; + } - for (LLNotificationForm::FormElement& element : form.form_elements.elements) - { - if (element.button.isChosen() && element.button.text() == pattern) - { - element.button.text = replace; - } - } + for (LLNotificationForm::FormElement& element : form.form_elements.elements) + { + if (element.button.isChosen() && element.button.text() == pattern) + { + element.button.text = replace; + } + } } void addPathIfExists(const std::string& new_path, std::vector<std::string>& paths) { - if (gDirUtilp->fileExists(new_path)) - { - paths.push_back(new_path); - } + if (gDirUtilp->fileExists(new_path)) + { + paths.push_back(new_path); + } } bool LLNotifications::loadTemplates() { - LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; - // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it - // output all relevant pathnames instead of just the ones from the most - // specific skin. - std::vector<std::string> search_paths = - gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; + // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it + // output all relevant pathnames instead of just the ones from the most + // specific skin. + std::vector<std::string> search_paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + if (search_paths.empty()) + { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL; + } - std::string base_filename = search_paths.front(); - LLXMLNodePtr root; - BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); + std::string base_filename = search_paths.front(); + LLXMLNodePtr root; + BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); - if (!success || root.isNull() || !root->hasName( "notifications" )) - { + if (!success || root.isNull() || !root->hasName( "notifications" )) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; - return false; - } + LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; + return false; + } - LLNotificationTemplate::Notifications params; - LLXUIParser parser; - parser.readXUI(root, params, base_filename); + LLNotificationTemplate::Notifications params; + LLXUIParser parser; + parser.readXUI(root, params, base_filename); - if(!params.validateBlock()) - { + if(!params.validateBlock()) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; - return false; - } - - mTemplates.clear(); - - for (const LLNotificationTemplate::GlobalString& string : params.strings) - { - mGlobalStrings[string.name] = string.value; - } - - std::map<std::string, LLNotificationForm::Params> form_templates; - - for (const LLNotificationTemplate::Template& notification_template : params.templates) - { - form_templates[notification_template.name] = notification_template.form; - } - - for (LLNotificationTemplate::Params& notification : params.notifications) - { - if (notification.form_ref.form_template.isChosen()) - { - // replace form contents from template - notification.form_ref.form = form_templates[notification.form_ref.form_template.name]; - if(notification.form_ref.form_template.yes_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text); - } - if(notification.form_ref.form_template.no_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text); - } - if(notification.form_ref.form_template.cancel_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text); - } - if(notification.form_ref.form_template.help_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$helptext", notification.form_ref.form_template.help_text); - } - if(notification.form_ref.form_template.ignore_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text); - } - } - mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); - } - - LL_INFOS("Notifications") << "...done" << LL_ENDL; - - return true; + LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; + return false; + } + + mTemplates.clear(); + + for (const LLNotificationTemplate::GlobalString& string : params.strings) + { + mGlobalStrings[string.name] = string.value; + } + + std::map<std::string, LLNotificationForm::Params> form_templates; + + for (const LLNotificationTemplate::Template& notification_template : params.templates) + { + form_templates[notification_template.name] = notification_template.form; + } + + for (LLNotificationTemplate::Params& notification : params.notifications) + { + if (notification.form_ref.form_template.isChosen()) + { + // replace form contents from template + notification.form_ref.form = form_templates[notification.form_ref.form_template.name]; + if(notification.form_ref.form_template.yes_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text); + } + if(notification.form_ref.form_template.no_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text); + } + if(notification.form_ref.form_template.cancel_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text); + } + if(notification.form_ref.form_template.help_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$helptext", notification.form_ref.form_template.help_text); + } + if(notification.form_ref.form_template.ignore_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text); + } + } + mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); + } + + LL_INFOS("Notifications") << "...done" << LL_ENDL; + + return true; } bool LLNotifications::loadVisibilityRules() { - const std::string xml_filename = "notification_visibility.xml"; - // Note that here we're looking for the "en" version, the default - // language, rather than the most localized version of this file. - std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, xml_filename); + const std::string xml_filename = "notification_visibility.xml"; + // Note that here we're looking for the "en" version, the default + // language, rather than the most localized version of this file. + std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, xml_filename); - LLNotificationVisibilityRule::Rules params; - LLSimpleXUIParser parser; - parser.readXUI(full_filename, params); + LLNotificationVisibilityRule::Rules params; + LLSimpleXUIParser parser; + parser.readXUI(full_filename, params); - if(!params.validateBlock()) - { + if(!params.validateBlock()) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; - return false; - } + LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; + return false; + } - mVisibilityRules.clear(); + mVisibilityRules.clear(); - for (const LLNotificationVisibilityRule::Rule& rule : params.rules) - { - mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); - } + for (const LLNotificationVisibilityRule::Rule& rule : params.rules) + { + mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); + } - return true; + return true; } // Add a simple notification (from XUI) void LLNotifications::addFromCallback(const LLSD& name) { - add(name.asString(), LLSD(), LLSD()); + add(name.asString(), LLSD(), LLSD()); } LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload) { - LLNotification::Params::Functor functor_p; - functor_p.name = name; - return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = name; + return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); } LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, const std::string& functor_name) { - LLNotification::Params::Functor functor_p; - functor_p.name = functor_name; - return add(LLNotification::Params().name(name) - .substitutions(substitutions) - .payload(payload) - .functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = functor_name; + return add(LLNotification::Params().name(name) + .substitutions(substitutions) + .payload(payload) + .functor(functor_p)); } - + //virtual LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, LLNotificationFunctorRegistry::ResponseFunctor functor) { - LLNotification::Params::Functor functor_p; - functor_p.function = functor; - return add(LLNotification::Params().name(name) - .substitutions(substitutions) - .payload(payload) - .functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.function = functor; + return add(LLNotification::Params().name(name) + .substitutions(substitutions) + .payload(payload) + .functor(functor_p)); } // generalized add function that takes a parameter block object for more complex instantiations LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) { - LLNotificationPtr pNotif(new LLNotification(p)); - add(pNotif); - return pNotif; + LLNotificationPtr pNotif(new LLNotification(p)); + add(pNotif); + return pNotif; } void LLNotifications::add(const LLNotificationPtr pNotif) { - if (pNotif == NULL) return; + if (pNotif == NULL) return; - // first see if we already have it -- if so, that's a problem - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - LL_ERRS() << "Notification added a second time to the master notification channel." << LL_ENDL; - } + // first see if we already have it -- if so, that's a problem + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + LL_ERRS() << "Notification added a second time to the master notification channel." << LL_ENDL; + } - updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); } void LLNotifications::load(const LLNotificationPtr pNotif) { - if (pNotif == NULL) return; + if (pNotif == NULL) return; - // first see if we already have it -- if so, that's a problem - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL; - } + // first see if we already have it -- if so, that's a problem + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL; + } - updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif); } void LLNotifications::cancel(LLNotificationPtr pNotif) { - if (pNotif == NULL || pNotif->isCancelled()) return; + if (pNotif == NULL || pNotif->isCancelled()) return; - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::cancelByName(const std::string& name) { LLMutexLock lock(&mItemsMutex); - std::vector<LLNotificationPtr> notifs_to_cancel; - for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - if (pNotif->getName() == name) - { - notifs_to_cancel.push_back(pNotif); - } - } - - for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + std::vector<LLNotificationPtr> notifs_to_cancel; + for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + if (pNotif->getName() == name) + { + notifs_to_cancel.push_back(pNotif); + } + } + + for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::cancelByOwner(const LLUUID ownerId) { LLMutexLock lock(&mItemsMutex); - std::vector<LLNotificationPtr> notifs_to_cancel; - for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - if (pNotif && pNotif->getPayload().get("owner_id").asUUID() == ownerId) - { - notifs_to_cancel.push_back(pNotif); - } - } - - for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + std::vector<LLNotificationPtr> notifs_to_cancel; + for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + if (pNotif && pNotif->getPayload().get("owner_id").asUUID() == ownerId) + { + notifs_to_cancel.push_back(pNotif); + } + } + + for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::update(const LLNotificationPtr pNotif) { - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); - } + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); + } } LLNotificationPtr LLNotifications::find(LLUUID uuid) { - LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid))); - LLNotificationSet::iterator it=mItems.find(target); - if (it == mItems.end()) - { - LL_DEBUGS("Notifications") << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << LL_ENDL; - return LLNotificationPtr((LLNotification*)NULL); - } - else - { - return *it; - } + LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid))); + LLNotificationSet::iterator it=mItems.find(target); + if (it == mItems.end()) + { + LL_DEBUGS("Notifications") << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << LL_ENDL; + return LLNotificationPtr((LLNotification*)NULL); + } + else + { + return *it; + } } std::string LLNotifications::getGlobalString(const std::string& key) const { - GlobalStringMap::const_iterator it = mGlobalStrings.find(key); - if (it != mGlobalStrings.end()) - { - return it->second; - } - else - { - // if we don't have the key as a global, return the key itself so that the error - // is self-diagnosing. - return key; - } + GlobalStringMap::const_iterator it = mGlobalStrings.find(key); + if (it != mGlobalStrings.end()) + { + return it->second; + } + else + { + // if we don't have the key as a global, return the key itself so that the error + // is self-diagnosing. + return key; + } } void LLNotifications::setIgnoreAllNotifications(bool setting) { - mIgnoreAllNotifications = setting; + mIgnoreAllNotifications = setting; } bool LLNotifications::getIgnoreAllNotifications() { - return mIgnoreAllNotifications; + return mIgnoreAllNotifications; } void LLNotifications::setIgnored(const std::string& name, bool ignored) { - LLNotificationTemplatePtr templatep = getTemplate(name); - templatep->mForm->setIgnored(ignored); + LLNotificationTemplatePtr templatep = getTemplate(name); + templatep->mForm->setIgnored(ignored); } bool LLNotifications::getIgnored(const std::string& name) { - LLNotificationTemplatePtr templatep = getTemplate(name); - return (mIgnoreAllNotifications) || ( (templatep->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) && (templatep->mForm->getIgnored()) ); + LLNotificationTemplatePtr templatep = getTemplate(name); + return (mIgnoreAllNotifications) || ( (templatep->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) && (templatep->mForm->getIgnored()) ); } - + bool LLNotifications::isVisibleByRules(LLNotificationPtr n) { - if(n->isRespondedTo()) - { - // This avoids infinite recursion in the case where the filter calls respond() - return true; - } - - VisibilityRuleList::iterator it; - - for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) - { - // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. - LL_DEBUGS("Notifications") - << "notification \"" << n->getName() << "\" " - << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " - << "name = \"" << (*it)->mName << "\" " - << "tag = \"" << (*it)->mTag << "\" " - << "type = \"" << (*it)->mType << "\" " - << LL_ENDL; - - if(!(*it)->mType.empty()) - { - if((*it)->mType != n->getType()) - { - // Type doesn't match, so skip this rule. - continue; - } - } - - if(!(*it)->mTag.empty()) - { - // check this notification's tag(s) against it->mTag and continue if no match is found. - if(!n->matchesTag((*it)->mTag)) - { - // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule. - continue; - } - } - - if(!(*it)->mName.empty()) - { - // check this notification's name against the notification's name and continue if no match is found. - if((*it)->mName != n->getName()) - { - // This rule's non-empty name didn't match the notification. Skip this rule. - continue; - } - } - - // If we got here, the rule matches. Don't evaluate subsequent rules. - if(!(*it)->mVisible) - { - // This notification is being hidden. - - if((*it)->mResponse.empty()) - { - // Response property is empty. Cancel this notification. - LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL; - - cancel(n); - } - else - { - // Response property is not empty. Return the specified response. - LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON); - // TODO: verify that the response template has an item with the correct name - response[(*it)->mResponse] = true; - - LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; - - n->respond(response); - } - - return false; - } - - // If we got here, exit the loop and return true. - break; - } - - LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL; - - return true; -} - + if(n->isRespondedTo()) + { + // This avoids infinite recursion in the case where the filter calls respond() + return true; + } + + VisibilityRuleList::iterator it; + + for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) + { + // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. + LL_DEBUGS("Notifications") + << "notification \"" << n->getName() << "\" " + << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " + << "name = \"" << (*it)->mName << "\" " + << "tag = \"" << (*it)->mTag << "\" " + << "type = \"" << (*it)->mType << "\" " + << LL_ENDL; + + if(!(*it)->mType.empty()) + { + if((*it)->mType != n->getType()) + { + // Type doesn't match, so skip this rule. + continue; + } + } + + if(!(*it)->mTag.empty()) + { + // check this notification's tag(s) against it->mTag and continue if no match is found. + if(!n->matchesTag((*it)->mTag)) + { + // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule. + continue; + } + } + + if(!(*it)->mName.empty()) + { + // check this notification's name against the notification's name and continue if no match is found. + if((*it)->mName != n->getName()) + { + // This rule's non-empty name didn't match the notification. Skip this rule. + continue; + } + } + + // If we got here, the rule matches. Don't evaluate subsequent rules. + if(!(*it)->mVisible) + { + // This notification is being hidden. + + if((*it)->mResponse.empty()) + { + // Response property is empty. Cancel this notification. + LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL; + + cancel(n); + } + else + { + // Response property is not empty. Return the specified response. + LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON); + // TODO: verify that the response template has an item with the correct name + response[(*it)->mResponse] = true; + + LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; + + n->respond(response); + } + + return false; + } + + // If we got here, exit the loop and return true. + break; + } + + LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL; + + return true; +} + // --- // END OF LLNotifications implementation @@ -1938,66 +1944,66 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) std::ostream& operator<<(std::ostream& s, const LLNotification& notification) { - s << notification.summarize(); - return s; + s << notification.summarize(); + return s; } void LLPostponedNotification::lookupName(const LLUUID& id, - bool is_group) + bool is_group) { - if (is_group) - { - gCacheName->getGroup(id, - boost::bind(&LLPostponedNotification::onGroupNameCache, - this, _1, _2, _3)); - } - else - { - fetchAvatarName(id); - } + if (is_group) + { + gCacheName->getGroup(id, + boost::bind(&LLPostponedNotification::onGroupNameCache, + this, _1, _2, _3)); + } + else + { + fetchAvatarName(id); + } } void LLPostponedNotification::onGroupNameCache(const LLUUID& id, - const std::string& full_name, - bool is_group) + const std::string& full_name, + bool is_group) { - finalizeName(full_name); + finalizeName(full_name); } void LLPostponedNotification::fetchAvatarName(const LLUUID& id) { - if (id.notNull()) - { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } + if (id.notNull()) + { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } - mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLPostponedNotification::onAvatarNameCache, this, _1, _2)); - } + mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLPostponedNotification::onAvatarNameCache, this, _1, _2)); + } } void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name) + const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); + mAvatarNameCacheConnection.disconnect(); + + std::string name = av_name.getCompleteName(); - std::string name = av_name.getCompleteName(); + // from PE merge - we should figure out if this is the right thing to do + if (name.empty()) + { + LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL; + name = SYSTEM_FROM; + } - // from PE merge - we should figure out if this is the right thing to do - if (name.empty()) - { - LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL; - name = SYSTEM_FROM; - } - - finalizeName(name); + finalizeName(name); } void LLPostponedNotification::finalizeName(const std::string& name) { - mName = name; - modifyNotificationParams(); - LLNotifications::instance().add(mParams); - cleanup(); + mName = name; + modifyNotificationParams(); + LLNotifications::instance().add(mParams); + cleanup(); } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 8e61ff5259..ab4f009a80 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,46 +31,46 @@ /** * This system is intended to provide a singleton mechanism for adding * notifications to one of an arbitrary set of event channels. - * + * * Controlling JIRA: DEV-9061 * * Every notification has (see code for full list): * - a textual name, which is used to look up its template in the XML files * - a payload, which is a block of LLSD * - a channel, which is normally extracted from the XML files but - * can be overridden. + * can be overridden. * - a timestamp, used to order the notifications * - expiration time -- if nonzero, specifies a time after which the * notification will no longer be valid. * - a callback name and a couple of status bits related to callbacks (see below) - * + * * There is a management class called LLNotifications, which is an LLSingleton. * The class maintains a collection of all of the notifications received * or processed during this session, and also manages the persistence * of those notifications that must be persisted. - * + * * We also have Channels. A channel is a view on a collection of notifications; * The collection is defined by a filter function that controls which - * notifications are in the channel, and its ordering is controlled by - * a comparator. + * notifications are in the channel, and its ordering is controlled by + * a comparator. * * There is a hierarchy of channels; notifications flow down from * the management class (LLNotifications, which itself inherits from * The channel base class) to the individual channels. - * Any change to notifications (add, delete, modify) is + * Any change to notifications (add, delete, modify) is * automatically propagated through the channel hierarchy. - * + * * We provide methods for adding a new notification, for removing * one, and for managing channels. Channels are relatively cheap to construct * and maintain, so in general, human interfaces should use channels to * select and manage their lists of notifications. - * - * We also maintain a collection of templates that are loaded from the + * + * We also maintain a collection of templates that are loaded from the * XML file of template translations. The system supports substitution * of named variables from the payload into the XML file. - * + * * By default, only the "unknown message" template is built into the system. - * It is not an error to add a notification that's not found in the + * It is not an error to add a notification that's not found in the * template system, but it is logged. * */ @@ -103,29 +103,29 @@ class LLAvatarName; typedef enum e_notification_priority { - NOTIFICATION_PRIORITY_UNSPECIFIED, - NOTIFICATION_PRIORITY_LOW, - NOTIFICATION_PRIORITY_NORMAL, - NOTIFICATION_PRIORITY_HIGH, - NOTIFICATION_PRIORITY_CRITICAL + NOTIFICATION_PRIORITY_UNSPECIFIED, + NOTIFICATION_PRIORITY_LOW, + NOTIFICATION_PRIORITY_NORMAL, + NOTIFICATION_PRIORITY_HIGH, + NOTIFICATION_PRIORITY_CRITICAL } ENotificationPriority; struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues> { - static void declareValues(); + static void declareValues(); }; class LLNotificationResponderInterface { public: - LLNotificationResponderInterface(){}; - virtual ~LLNotificationResponderInterface(){}; + LLNotificationResponderInterface(){}; + virtual ~LLNotificationResponderInterface(){}; - virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0; + virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0; - virtual LLSD asLLSD() = 0; + virtual LLSD asLLSD() = 0; - virtual void fromLLSD(const LLSD& params) = 0; + virtual void fromLLSD(const LLSD& params) = 0; }; typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder; @@ -141,16 +141,16 @@ class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LL { public: - LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID()) - { - } + LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID()) + { + } - virtual ~LLNotificationContext() {} + virtual ~LLNotificationContext() {} - LLSD asLLSD() const - { - return getKey(); - } + LLSD asLLSD() const + { + return getKey(); + } private: @@ -160,119 +160,120 @@ private: // manipulator functions class LLNotificationForm { - LOG_CLASS(LLNotificationForm); + LOG_CLASS(LLNotificationForm); public: - struct FormElementBase : public LLInitParam::Block<FormElementBase> - { - Optional<std::string> name; - Optional<bool> enabled; - - FormElementBase(); - }; - - struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase> - { - Optional<std::string> text; - Optional<bool> save_option; - Optional<std::string> control; - Optional<bool> invert_control; - Optional<bool> session_only; - Optional<bool> checkbox_only; - - FormIgnore(); - }; - - struct FormButton : public LLInitParam::Block<FormButton, FormElementBase> - { - Mandatory<S32> index; - Mandatory<std::string> text; - Optional<std::string> ignore; - Optional<bool> is_default; - Optional<S32> width; - - Mandatory<std::string> type; - - FormButton(); - }; - - struct FormInput : public LLInitParam::Block<FormInput, FormElementBase> - { - Mandatory<std::string> type; - Optional<S32> width; - Optional<S32> max_length_chars; - Optional<std::string> text; - - Optional<std::string> value; - FormInput(); - }; - - struct FormElement : public LLInitParam::ChoiceBlock<FormElement> - { - Alternative<FormButton> button; - Alternative<FormInput> input; - - FormElement(); - }; - - struct FormElements : public LLInitParam::Block<FormElements> - { - Multiple<FormElement> elements; - FormElements(); - }; - - struct Params : public LLInitParam::Block<Params> - { - Optional<std::string> name; - Optional<FormIgnore> ignore; - Optional<FormElements> form_elements; - - Params(); - }; - - typedef enum e_ignore_type - { - IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only - IGNORE_NO = 0, - IGNORE_WITH_DEFAULT_RESPONSE, - IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY, - IGNORE_WITH_LAST_RESPONSE, - IGNORE_SHOW_AGAIN - } EIgnoreType; - - LLNotificationForm(); - LLNotificationForm(const LLNotificationForm&); - LLNotificationForm(const LLSD& sd); - LLNotificationForm(const std::string& name, const Params& p); - - void fromLLSD(const LLSD& sd); - LLSD asLLSD() const; - - S32 getNumElements() { return mFormData.size(); } - LLSD getElement(S32 index) { return mFormData.get(index); } - LLSD getElement(const std::string& element_name); + struct FormElementBase : public LLInitParam::Block<FormElementBase> + { + Optional<std::string> name; + Optional<bool> enabled; + + FormElementBase(); + }; + + struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase> + { + Optional<std::string> text; + Optional<bool> save_option; + Optional<std::string> control; + Optional<bool> invert_control; + Optional<bool> session_only; + Optional<bool> checkbox_only; + + FormIgnore(); + }; + + struct FormButton : public LLInitParam::Block<FormButton, FormElementBase> + { + Mandatory<S32> index; + Mandatory<std::string> text; + Optional<std::string> ignore; + Optional<bool> is_default; + Optional<S32> width; + + Mandatory<std::string> type; + + FormButton(); + }; + + struct FormInput : public LLInitParam::Block<FormInput, FormElementBase> + { + Mandatory<std::string> type; + Optional<S32> width; + Optional<S32> max_length_chars; + Optional<bool> allow_emoji; + Optional<std::string> text; + + Optional<std::string> value; + FormInput(); + }; + + struct FormElement : public LLInitParam::ChoiceBlock<FormElement> + { + Alternative<FormButton> button; + Alternative<FormInput> input; + + FormElement(); + }; + + struct FormElements : public LLInitParam::Block<FormElements> + { + Multiple<FormElement> elements; + FormElements(); + }; + + struct Params : public LLInitParam::Block<Params> + { + Optional<std::string> name; + Optional<FormIgnore> ignore; + Optional<FormElements> form_elements; + + Params(); + }; + + typedef enum e_ignore_type + { + IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only + IGNORE_NO = 0, + IGNORE_WITH_DEFAULT_RESPONSE, + IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY, + IGNORE_WITH_LAST_RESPONSE, + IGNORE_SHOW_AGAIN + } EIgnoreType; + + LLNotificationForm(); + LLNotificationForm(const LLNotificationForm&); + LLNotificationForm(const LLSD& sd); + LLNotificationForm(const std::string& name, const Params& p); + + void fromLLSD(const LLSD& sd); + LLSD asLLSD() const; + + S32 getNumElements() { return mFormData.size(); } + LLSD getElement(S32 index) { return mFormData.get(index); } + LLSD getElement(const std::string& element_name); void getElements(LLSD& elements, S32 offset = 0); - bool hasElement(const std::string& element_name) const; - bool getElementEnabled(const std::string& element_name) const; - void setElementEnabled(const std::string& element_name, bool enabled); - void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD(), bool enabled = true); - void formatElements(const LLSD& substitutions); - // appends form elements from another form serialized as LLSD - void append(const LLSD& sub_form); - std::string getDefaultOption(); - LLPointer<class LLControlVariable> getIgnoreSetting(); - bool getIgnored(); - void setIgnored(bool ignored); - - EIgnoreType getIgnoreType() { return mIgnore; } - std::string getIgnoreMessage() { return mIgnoreMsg; } + bool hasElement(const std::string& element_name) const; + bool getElementEnabled(const std::string& element_name) const; + void setElementEnabled(const std::string& element_name, bool enabled); + void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD(), bool enabled = true); + void formatElements(const LLSD& substitutions); + // appends form elements from another form serialized as LLSD + void append(const LLSD& sub_form); + std::string getDefaultOption(); + LLPointer<class LLControlVariable> getIgnoreSetting(); + bool getIgnored(); + void setIgnored(bool ignored); + + EIgnoreType getIgnoreType() { return mIgnore; } + std::string getIgnoreMessage() { return mIgnoreMsg; } private: - LLSD mFormData; - EIgnoreType mIgnore; - std::string mIgnoreMsg; - LLPointer<class LLControlVariable> mIgnoreSetting; - bool mInvertSetting; + LLSD mFormData; + EIgnoreType mIgnore; + std::string mIgnoreMsg; + LLPointer<class LLControlVariable> mIgnoreSetting; + bool mInvertSetting; }; typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr; @@ -292,253 +293,253 @@ typedef std::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRu /** * @class LLNotification * @brief The object that expresses the details of a notification - * + * * We make this noncopyable because * we want to manage these through LLNotificationPtr, and only * ever create one instance of any given notification. - * + * * The enable_shared_from_this flag ensures that if we construct * a smart pointer from a notification, we'll always get the same * shared pointer. */ -class LLNotification : - boost::noncopyable, - public std::enable_shared_from_this<LLNotification> +class LLNotification : + boost::noncopyable, + public std::enable_shared_from_this<LLNotification> { LOG_CLASS(LLNotification); friend class LLNotifications; public: - // parameter object used to instantiate a new notification - struct Params : public LLInitParam::Block<Params> - { - friend class LLNotification; - - Mandatory<std::string> name; - Optional<LLUUID> id; - Optional<LLSD> substitutions, - form_elements, - payload; - Optional<ENotificationPriority, NotificationPriorityValues> priority; - Optional<LLDate> time_stamp, - expiry; - Optional<LLNotificationContext*> context; - Optional<void*> responder; - Optional<bool> offer_from_agent; - Optional<bool> is_dnd; - - struct Functor : public LLInitParam::ChoiceBlock<Functor> - { - Alternative<std::string> name; - Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function; - Alternative<LLNotificationResponderPtr> responder; - Alternative<LLSD> responder_sd; - - Functor() - : name("responseFunctor"), - function("functor"), - responder("responder"), + // parameter object used to instantiate a new notification + struct Params : public LLInitParam::Block<Params> + { + friend class LLNotification; + + Mandatory<std::string> name; + Optional<LLUUID> id; + Optional<LLSD> substitutions, + form_elements, + payload; + Optional<ENotificationPriority, NotificationPriorityValues> priority; + Optional<LLDate> time_stamp, + expiry; + Optional<LLNotificationContext*> context; + Optional<void*> responder; + Optional<bool> offer_from_agent; + Optional<bool> is_dnd; + + struct Functor : public LLInitParam::ChoiceBlock<Functor> + { + Alternative<std::string> name; + Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function; + Alternative<LLNotificationResponderPtr> responder; + Alternative<LLSD> responder_sd; + + Functor() + : name("responseFunctor"), + function("functor"), + responder("responder"), responder_sd("responder_sd") - {} - }; - Optional<Functor> functor; - - Params() - : name("name"), - id("id"), - priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), - time_stamp("time"), - payload("payload"), - form_elements("form"), - substitutions("substitutions"), - expiry("expiry"), - offer_from_agent("offer_from_agent", false), + {} + }; + Optional<Functor> functor; + + Params() + : name("name"), + id("id"), + priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), + time_stamp("time"), + payload("payload"), + form_elements("form"), + substitutions("substitutions"), + expiry("expiry"), + offer_from_agent("offer_from_agent", false), is_dnd("is_dnd", false) - { - time_stamp = LLDate::now(); - responder = NULL; - } - - Params(const std::string& _name) - : name("name"), - priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), - time_stamp("time"), - payload("payload"), - form_elements("form"), - substitutions("substitutions"), - expiry("expiry"), - offer_from_agent("offer_from_agent", false), + { + time_stamp = LLDate::now(); + responder = NULL; + } + + Params(const std::string& _name) + : name("name"), + priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), + time_stamp("time"), + payload("payload"), + form_elements("form"), + substitutions("substitutions"), + expiry("expiry"), + offer_from_agent("offer_from_agent", false), is_dnd("is_dnd", false) - { - functor.name = _name; - name = _name; - time_stamp = LLDate::now(); - responder = NULL; - } - }; + { + functor.name = _name; + name = _name; + time_stamp = LLDate::now(); + responder = NULL; + } + }; - LLNotificationResponderPtr getResponderPtr() { return mResponder; } + LLNotificationResponderPtr getResponderPtr() { return mResponder; } private: - - const LLUUID mId; - LLSD mPayload; - LLSD mSubstitutions; - LLDate mTimestamp; - LLDate mExpiresAt; - bool mCancelled; - bool mRespondedTo; // once the notification has been responded to, this becomes true - LLSD mResponse; - bool mIgnored; - ENotificationPriority mPriority; - LLNotificationFormPtr mForm; - void* mResponderObj; // TODO - refactor/remove this field - LLNotificationResponderPtr mResponder; - bool mOfferFromAgent; + + const LLUUID mId; + LLSD mPayload; + LLSD mSubstitutions; + LLDate mTimestamp; + LLDate mExpiresAt; + bool mCancelled; + bool mRespondedTo; // once the notification has been responded to, this becomes true + LLSD mResponse; + bool mIgnored; + ENotificationPriority mPriority; + LLNotificationFormPtr mForm; + void* mResponderObj; // TODO - refactor/remove this field + LLNotificationResponderPtr mResponder; + bool mOfferFromAgent; bool mIsDND; - // a reference to the template - LLNotificationTemplatePtr mTemplatep; - - /* - We want to be able to store and reload notifications so that they can survive - a shutdown/restart of the client. So we can't simply pass in callbacks; - we have to specify a callback mechanism that can be used by name rather than - by some arbitrary pointer -- and then people have to initialize callbacks - in some useful location. So we use LLNotificationFunctorRegistry to manage them. - */ - std::string mResponseFunctorName; - - /* - In cases where we want to specify an explict, non-persisted callback, - we store that in the callback registry under a dynamically generated - key, and store the key in the notification, so we can still look it up - using the same mechanism. - */ - bool mTemporaryResponder; - - // keep track of other notifications combined with COMBINE_WITH_NEW - std::vector<LLNotificationPtr> mCombinedNotifications; - - void init(const std::string& template_name, const LLSD& form_elements); - - void cancel(); + // a reference to the template + LLNotificationTemplatePtr mTemplatep; -public: - LLNotification(const LLSDParamAdapter<Params>& p); + /* + We want to be able to store and reload notifications so that they can survive + a shutdown/restart of the client. So we can't simply pass in callbacks; + we have to specify a callback mechanism that can be used by name rather than + by some arbitrary pointer -- and then people have to initialize callbacks + in some useful location. So we use LLNotificationFunctorRegistry to manage them. + */ + std::string mResponseFunctorName; + + /* + In cases where we want to specify an explict, non-persisted callback, + we store that in the callback registry under a dynamically generated + key, and store the key in the notification, so we can still look it up + using the same mechanism. + */ + bool mTemporaryResponder; + + // keep track of other notifications combined with COMBINE_WITH_NEW + std::vector<LLNotificationPtr> mCombinedNotifications; - void setResponseFunctor(std::string const &responseFunctorName); + void init(const std::string& template_name, const LLSD& form_elements); - void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); + void cancel(); - void setResponseFunctor(const LLNotificationResponderPtr& responder); +public: + LLNotification(const LLSDParamAdapter<Params>& p); - typedef enum e_response_template_type - { - WITHOUT_DEFAULT_BUTTON, - WITH_DEFAULT_BUTTON - } EResponseTemplateType; + void setResponseFunctor(std::string const &responseFunctorName); - // return response LLSD filled in with default form contents and (optionally) the default button selected - LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON); + void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); - // returns index of first button with value==TRUE - // usually this the button the user clicked on - // returns -1 if no button clicked (e.g. form has not been displayed) - static S32 getSelectedOption(const LLSD& notification, const LLSD& response); - // returns name of first button with value==TRUE - static std::string getSelectedOptionName(const LLSD& notification); + void setResponseFunctor(const LLNotificationResponderPtr& responder); - // after someone responds to a notification (usually by clicking a button, - // but sometimes by filling out a little form and THEN clicking a button), + typedef enum e_response_template_type + { + WITHOUT_DEFAULT_BUTTON, + WITH_DEFAULT_BUTTON + } EResponseTemplateType; + + // return response LLSD filled in with default form contents and (optionally) the default button selected + LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON); + + // returns index of first button with value==TRUE + // usually this the button the user clicked on + // returns -1 if no button clicked (e.g. form has not been displayed) + static S32 getSelectedOption(const LLSD& notification, const LLSD& response); + // returns name of first button with value==TRUE + static std::string getSelectedOptionName(const LLSD& notification); + + // after someone responds to a notification (usually by clicking a button, + // but sometimes by filling out a little form and THEN clicking a button), // the result of the response (the name and value of the button clicked, - // plus any other data) should be packaged up as LLSD, then passed as a - // parameter to the notification's respond() method here. This will look up - // and call the appropriate responder. - // - // response is notification serialized as LLSD: - // ["name"] = notification name - // ["form"] = LLSD tree that includes form description and any prefilled form data - // ["response"] = form data filled in by user - // (including, but not limited to which button they clicked on) - // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification), - // ["item_id"] (attached inventory item), etc. - // ["substitutions"] = string substitutions used to generate notification message + // plus any other data) should be packaged up as LLSD, then passed as a + // parameter to the notification's respond() method here. This will look up + // and call the appropriate responder. + // + // response is notification serialized as LLSD: + // ["name"] = notification name + // ["form"] = LLSD tree that includes form description and any prefilled form data + // ["response"] = form data filled in by user + // (including, but not limited to which button they clicked on) + // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification), + // ["item_id"] (attached inventory item), etc. + // ["substitutions"] = string substitutions used to generate notification message // from the template - // ["time"] = time at which notification was generated; - // ["expiry"] = time at which notification expires; - // ["responseFunctor"] = name of registered functor that handles responses to notification; - LLSD asLLSD(bool excludeTemplateElements = false); + // ["time"] = time at which notification was generated; + // ["expiry"] = time at which notification expires; + // ["responseFunctor"] = name of registered functor that handles responses to notification; + LLSD asLLSD(bool excludeTemplateElements = false); - const LLNotificationFormPtr getForm(); - void updateForm(const LLNotificationFormPtr& form); + const LLNotificationFormPtr getForm(); + void updateForm(const LLNotificationFormPtr& form); - void repost(); + void repost(); - void respond(const LLSD& sd); - void respondWithDefault(); + void respond(const LLSD& sd); + void respondWithDefault(); - void* getResponder() { return mResponderObj; } + void* getResponder() { return mResponderObj; } - void setResponder(void* responder) { mResponderObj = responder; } + void setResponder(void* responder) { mResponderObj = responder; } - void setIgnored(bool ignore); + void setIgnored(bool ignore); - bool isCancelled() const - { - return mCancelled; - } + bool isCancelled() const + { + return mCancelled; + } - bool isRespondedTo() const - { - return mRespondedTo; - } + bool isRespondedTo() const + { + return mRespondedTo; + } - bool isActive() const - { - return !isRespondedTo() - && !isCancelled() - && !isExpired(); - } + bool isActive() const + { + return !isRespondedTo() + && !isCancelled() + && !isExpired(); + } - const LLSD& getResponse() { return mResponse; } + const LLSD& getResponse() { return mResponse; } + + bool isIgnored() const + { + return mIgnored; + } - bool isIgnored() const - { - return mIgnored; - } + const std::string& getName() const; - const std::string& getName() const; + const std::string& getIcon() const; - const std::string& getIcon() const; + bool isPersistent() const; - bool isPersistent() const; + const LLUUID& id() const + { + return mId; + } - const LLUUID& id() const - { - return mId; - } - - const LLSD& getPayload() const - { - return mPayload; - } + const LLSD& getPayload() const + { + return mPayload; + } - const LLSD& getSubstitutions() const - { - return mSubstitutions; - } + const LLSD& getSubstitutions() const + { + return mSubstitutions; + } - const LLDate& getDate() const - { - return mTimestamp; - } + const LLDate& getDate() const + { + return mTimestamp; + } - bool getOfferFromAgent() const - { - return mOfferFromAgent; - } + bool getOfferFromAgent() const + { + return mOfferFromAgent; + } bool isDND() const { @@ -550,165 +551,165 @@ public: mIsDND = flag; } - std::string getType() const; - std::string getMessage() const; - std::string getFooter() const; - std::string getLabel() const; - std::string getURL() const; - S32 getURLOption() const; - S32 getURLOpenExternally() const; //for url responce option - bool getForceUrlsExternal() const; - bool canLogToChat() const; - bool canLogToIM() const; - bool canShowToast() const; - bool canFadeToast() const; - bool hasFormElements() const; + std::string getType() const; + std::string getMessage() const; + std::string getFooter() const; + std::string getLabel() const; + std::string getURL() const; + S32 getURLOption() const; + S32 getURLOpenExternally() const; //for url responce option + bool getForceUrlsExternal() const; + bool canLogToChat() const; + bool canLogToIM() const; + bool canShowToast() const; + bool canFadeToast() const; + bool hasFormElements() const; void playSound(); - typedef enum e_combine_behavior - { - REPLACE_WITH_NEW, - COMBINE_WITH_NEW, - KEEP_OLD, - CANCEL_OLD - - } ECombineBehavior; - - ECombineBehavior getCombineBehavior() const; - - const LLDate getExpiration() const - { - return mExpiresAt; - } - - ENotificationPriority getPriority() const - { - return mPriority; - } - - const LLUUID getID() const - { - return mId; - } - - // comparing two notifications normally means comparing them by UUID (so we can look them - // up quickly this way) - bool operator<(const LLNotification& rhs) const - { - return mId < rhs.mId; - } - - bool operator==(const LLNotification& rhs) const - { - return mId == rhs.mId; - } - - bool operator!=(const LLNotification& rhs) const - { - return !operator==(rhs); - } - - bool isSameObjectAs(const LLNotification* rhs) const - { - return this == rhs; - } - - // this object has been updated, so tell all our clients - void update(); - - void updateFrom(LLNotificationPtr other); - - // A fuzzy equals comparator. - // true only if both notifications have the same template and - // 1) flagged as unique (there can be only one of these) OR - // 2) all required payload fields of each also exist in the other. - bool isEquivalentTo(LLNotificationPtr that) const; - - // if the current time is greater than the expiration, the notification is expired - bool isExpired() const - { - if (mExpiresAt.secondsSinceEpoch() == 0) - { - return false; - } - - LLDate rightnow = LLDate::now(); - return rightnow > mExpiresAt; - } - - std::string summarize() const; - - bool hasUniquenessConstraints() const; - - bool matchesTag(const std::string& tag); - - virtual ~LLNotification() {} + typedef enum e_combine_behavior + { + REPLACE_WITH_NEW, + COMBINE_WITH_NEW, + KEEP_OLD, + CANCEL_OLD + + } ECombineBehavior; + + ECombineBehavior getCombineBehavior() const; + + const LLDate getExpiration() const + { + return mExpiresAt; + } + + ENotificationPriority getPriority() const + { + return mPriority; + } + + const LLUUID getID() const + { + return mId; + } + + // comparing two notifications normally means comparing them by UUID (so we can look them + // up quickly this way) + bool operator<(const LLNotification& rhs) const + { + return mId < rhs.mId; + } + + bool operator==(const LLNotification& rhs) const + { + return mId == rhs.mId; + } + + bool operator!=(const LLNotification& rhs) const + { + return !operator==(rhs); + } + + bool isSameObjectAs(const LLNotification* rhs) const + { + return this == rhs; + } + + // this object has been updated, so tell all our clients + void update(); + + void updateFrom(LLNotificationPtr other); + + // A fuzzy equals comparator. + // true only if both notifications have the same template and + // 1) flagged as unique (there can be only one of these) OR + // 2) all required payload fields of each also exist in the other. + bool isEquivalentTo(LLNotificationPtr that) const; + + // if the current time is greater than the expiration, the notification is expired + bool isExpired() const + { + if (mExpiresAt.secondsSinceEpoch() == 0) + { + return false; + } + + LLDate rightnow = LLDate::now(); + return rightnow > mExpiresAt; + } + + std::string summarize() const; + + bool hasUniquenessConstraints() const; + + bool matchesTag(const std::string& tag); + + virtual ~LLNotification() {} }; std::ostream& operator<<(std::ostream& s, const LLNotification& notification); namespace LLNotificationFilters { - // a sample filter - bool includeEverything(LLNotificationPtr p); - - typedef enum e_comparison - { - EQUAL, - LESS, - GREATER, - LESS_EQUAL, - GREATER_EQUAL - } EComparison; - - // generic filter functor that takes method or member variable reference - template<typename T> - struct filterBy - { - typedef boost::function<T (LLNotificationPtr)> field_t; - typedef typename boost::remove_reference<T>::type value_t; - - filterBy(field_t field, value_t value, EComparison comparison = EQUAL) - : mField(field), - mFilterValue(value), - mComparison(comparison) - { - } - - bool operator()(LLNotificationPtr p) - { - switch(mComparison) - { - case EQUAL: - return mField(p) == mFilterValue; - case LESS: - return mField(p) < mFilterValue; - case GREATER: - return mField(p) > mFilterValue; - case LESS_EQUAL: - return mField(p) <= mFilterValue; - case GREATER_EQUAL: - return mField(p) >= mFilterValue; - default: - return false; - } - } - - field_t mField; - value_t mFilterValue; - EComparison mComparison; - }; + // a sample filter + bool includeEverything(LLNotificationPtr p); + + typedef enum e_comparison + { + EQUAL, + LESS, + GREATER, + LESS_EQUAL, + GREATER_EQUAL + } EComparison; + + // generic filter functor that takes method or member variable reference + template<typename T> + struct filterBy + { + typedef boost::function<T (LLNotificationPtr)> field_t; + typedef typename boost::remove_reference<T>::type value_t; + + filterBy(field_t field, value_t value, EComparison comparison = EQUAL) + : mField(field), + mFilterValue(value), + mComparison(comparison) + { + } + + bool operator()(LLNotificationPtr p) + { + switch(mComparison) + { + case EQUAL: + return mField(p) == mFilterValue; + case LESS: + return mField(p) < mFilterValue; + case GREATER: + return mField(p) > mFilterValue; + case LESS_EQUAL: + return mField(p) <= mFilterValue; + case GREATER_EQUAL: + return mField(p) >= mFilterValue; + default: + return false; + } + } + + field_t mField; + value_t mFilterValue; + EComparison mComparison; + }; }; namespace LLNotificationComparators { - struct orderByUUID - { - bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs) const - { - return lhs->id() < rhs->id(); - } - }; + struct orderByUUID + { + bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs) const + { + return lhs->id() < rhs->id(); + } + }; }; typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter; @@ -729,18 +730,18 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap; // +-- Alerts // +-- Notifications // -// In general, new channels that want to only see notifications that pass through +// In general, new channels that want to only see notifications that pass through // all of the built-in tests should attach to the "Visible" channel // class LLNotificationChannelBase : - public LLEventTrackable, - public LLRefCount + public LLEventTrackable, + public LLRefCount { - LOG_CLASS(LLNotificationChannelBase); + LOG_CLASS(LLNotificationChannelBase); public: - LLNotificationChannelBase(LLNotificationFilter filter) + LLNotificationChannelBase(LLNotificationFilter filter) : mFilter(filter) - , mItems() + , mItems() , mItemsMutex() {} @@ -753,8 +754,8 @@ public: LLMutexLock lock(&mItemsMutex); mItems.clear(); } - // you can also connect to a Channel, so you can be notified of - // changes to this channel + // you can also connect to a Channel, so you can be notified of + // changes to this channel LLBoundListener connectChanged(const LLEventListener& slot) { // Call this->connectChangedImpl() to actually connect it. @@ -775,9 +776,9 @@ public: return connectFailedFilterImpl(slot); } - // use this when items change or to add a new one - bool updateItem(const LLSD& payload); - const LLNotificationFilter& getFilter() { return mFilter; } + // use this when items change or to add a new one + bool updateItem(const LLSD& payload); + const LLNotificationFilter& getFilter() { return mFilter; } protected: LLBoundListener connectChangedImpl(const LLEventListener& slot); @@ -785,29 +786,29 @@ protected: LLBoundListener connectPassedFilterImpl(const LLEventListener& slot); LLBoundListener connectFailedFilterImpl(const LLEventListener& slot); - LLNotificationSet mItems; - LLStandardSignal mChanged; - LLStandardSignal mPassedFilter; - LLStandardSignal mFailedFilter; + LLNotificationSet mItems; + LLStandardSignal mChanged; + LLStandardSignal mPassedFilter; + LLStandardSignal mFailedFilter; LLMutex mItemsMutex; - - // these are action methods that subclasses can override to take action - // on specific types of changes; the management of the mItems list is - // still handled by the generic handler. - virtual void onLoad(LLNotificationPtr p) {} - virtual void onAdd(LLNotificationPtr p) {} - virtual void onDelete(LLNotificationPtr p) {} - virtual void onChange(LLNotificationPtr p) {} - - virtual void onFilterPass(LLNotificationPtr p) {} - virtual void onFilterFail(LLNotificationPtr p) {} - - bool updateItem(const LLSD& payload, LLNotificationPtr pNotification); - LLNotificationFilter mFilter; + + // these are action methods that subclasses can override to take action + // on specific types of changes; the management of the mItems list is + // still handled by the generic handler. + virtual void onLoad(LLNotificationPtr p) {} + virtual void onAdd(LLNotificationPtr p) {} + virtual void onDelete(LLNotificationPtr p) {} + virtual void onChange(LLNotificationPtr p) {} + + virtual void onFilterPass(LLNotificationPtr p) {} + virtual void onFilterFail(LLNotificationPtr p) {} + + bool updateItem(const LLSD& payload, LLNotificationPtr pNotification); + LLNotificationFilter mFilter; }; // The type of the pointers that we're going to manage in the NotificationQueue system -// Because LLNotifications is a singleton, we don't actually expect to ever +// Because LLNotifications is a singleton, we don't actually expect to ever // destroy it, but if it becomes necessary to do so, the shared_ptr model // will ensure that we don't leak resources. class LLNotificationChannel; @@ -815,39 +816,39 @@ typedef boost::intrusive_ptr<LLNotificationChannel> LLNotificationChannelPtr; // manages a list of notifications // Note that if this is ever copied around, we might find ourselves with multiple copies -// of a queue with notifications being added to different nonequivalent copies. So we +// of a queue with notifications being added to different nonequivalent copies. So we // make it inherit from boost::noncopyable, and then create a map of LLPointer to manage it. // -class LLNotificationChannel : - boost::noncopyable, - public LLNotificationChannelBase, - public LLInstanceTracker<LLNotificationChannel, std::string> +class LLNotificationChannel : + boost::noncopyable, + public LLNotificationChannelBase, + public LLInstanceTracker<LLNotificationChannel, std::string> { - LOG_CLASS(LLNotificationChannel); - -public: - // Notification Channels have a filter, which determines which notifications - // will be added to this channel. - // Channel filters cannot change. - struct Params : public LLInitParam::Block<Params> - { - Mandatory<std::string> name; - Optional<LLNotificationFilter> filter; - Multiple<std::string> sources; - }; - - LLNotificationChannel(const Params& p = Params()); - LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter); - - virtual ~LLNotificationChannel(); - typedef LLNotificationSet::iterator Iterator; - - std::string getName() const { return mName; } - typedef std::vector<std::string>::const_iterator parents_iter; - boost::iterator_range<parents_iter> getParents() const - { - return boost::iterator_range<parents_iter>(mParents); - } + LOG_CLASS(LLNotificationChannel); + +public: + // Notification Channels have a filter, which determines which notifications + // will be added to this channel. + // Channel filters cannot change. + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; + Optional<LLNotificationFilter> filter; + Multiple<std::string> sources; + }; + + LLNotificationChannel(const Params& p = Params()); + LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter); + + virtual ~LLNotificationChannel(); + typedef LLNotificationSet::iterator Iterator; + + std::string getName() const { return mName; } + typedef std::vector<std::string>::const_iterator parents_iter; + boost::iterator_range<parents_iter> getParents() const + { + return boost::iterator_range<parents_iter>(mParents); + } bool isEmpty() const; S32 size() const; @@ -856,14 +857,14 @@ public: typedef boost::function<void(LLNotificationPtr)> NotificationProcess; void forEachNotification(NotificationProcess process); - std::string summarize(); + std::string summarize(); protected: void connectToChannel(const std::string& channel_name); private: - std::string mName; - std::vector<std::string> mParents; + std::string mName; + std::vector<std::string> mParents; std::vector<LLBoundListener> mListeners; }; @@ -872,20 +873,20 @@ private: class LLNotificationsInterface { public: - virtual LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - LLNotificationFunctorRegistry::ResponseFunctor functor) = 0; + virtual LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor) = 0; }; -class LLNotifications : - public LLNotificationsInterface, - public LLSingleton<LLNotifications>, - public LLNotificationChannelBase +class LLNotifications : + public LLNotificationsInterface, + public LLSingleton<LLNotifications>, + public LLNotificationChannelBase { - LLSINGLETON(LLNotifications); - LOG_CLASS(LLNotifications); - virtual ~LLNotifications() {} + LLSINGLETON(LLNotifications); + LOG_CLASS(LLNotifications); + virtual ~LLNotifications() {} public: @@ -895,106 +896,106 @@ public: // void clear(); - // load all notification descriptions from file - // calling more than once will overwrite existing templates - // but never delete a template - bool loadTemplates(); - - // load visibility rules from file; - // OK to call more than once because it will reload - bool loadVisibilityRules(); - - // Add a simple notification (from XUI) - void addFromCallback(const LLSD& name); - - // *NOTE: To add simple notifications, #include "llnotificationsutil.h" - // and use LLNotificationsUtil::add("MyNote") or add("MyNote", args) - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload); - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - const std::string& functor_name); - /* virtual */ LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - LLNotificationFunctorRegistry::ResponseFunctor functor) override; - LLNotificationPtr add(const LLNotification::Params& p); - - void add(const LLNotificationPtr pNotif); - void load(const LLNotificationPtr pNotif); - void cancel(LLNotificationPtr pNotif); - void cancelByName(const std::string& name); - void cancelByOwner(const LLUUID ownerId); - void update(const LLNotificationPtr pNotif); - - LLNotificationPtr find(LLUUID uuid); - - // This is all stuff for managing the templates - // take your template out - LLNotificationTemplatePtr getTemplate(const std::string& name); - - // get the whole collection - typedef std::vector<std::string> TemplateNames; - TemplateNames getTemplateNames() const; // returns a list of notification names - - typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap; - - TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); } - TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); } - - // test for existence - bool templateExists(const std::string& name); - - typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList; - - void forceResponse(const LLNotification::Params& params, S32 option); - - void createDefaultChannels(); - - LLNotificationChannelPtr getChannel(const std::string& channelName); - - std::string getGlobalString(const std::string& key) const; - - void setIgnoreAllNotifications(bool ignore); - bool getIgnoreAllNotifications(); - - void setIgnored(const std::string& name, bool ignored); - bool getIgnored(const std::string& name); - - bool isVisibleByRules(LLNotificationPtr pNotification); - + // load all notification descriptions from file + // calling more than once will overwrite existing templates + // but never delete a template + bool loadTemplates(); + + // load visibility rules from file; + // OK to call more than once because it will reload + bool loadVisibilityRules(); + + // Add a simple notification (from XUI) + void addFromCallback(const LLSD& name); + + // *NOTE: To add simple notifications, #include "llnotificationsutil.h" + // and use LLNotificationsUtil::add("MyNote") or add("MyNote", args) + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload); + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + const std::string& functor_name); + /* virtual */ LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor) override; + LLNotificationPtr add(const LLNotification::Params& p); + + void add(const LLNotificationPtr pNotif); + void load(const LLNotificationPtr pNotif); + void cancel(LLNotificationPtr pNotif); + void cancelByName(const std::string& name); + void cancelByOwner(const LLUUID ownerId); + void update(const LLNotificationPtr pNotif); + + LLNotificationPtr find(LLUUID uuid); + + // This is all stuff for managing the templates + // take your template out + LLNotificationTemplatePtr getTemplate(const std::string& name); + + // get the whole collection + typedef std::vector<std::string> TemplateNames; + TemplateNames getTemplateNames() const; // returns a list of notification names + + typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap; + + TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); } + TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); } + + // test for existence + bool templateExists(const std::string& name); + + typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList; + + void forceResponse(const LLNotification::Params& params, S32 option); + + void createDefaultChannels(); + + LLNotificationChannelPtr getChannel(const std::string& channelName); + + std::string getGlobalString(const std::string& key) const; + + void setIgnoreAllNotifications(bool ignore); + bool getIgnoreAllNotifications(); + + void setIgnored(const std::string& name, bool ignored); + bool getIgnored(const std::string& name); + + bool isVisibleByRules(LLNotificationPtr pNotification); + private: - /*virtual*/ void initSingleton() override; - /*virtual*/ void cleanupSingleton() override; - - void loadPersistentNotifications(); - - bool expirationFilter(LLNotificationPtr pNotification); - bool expirationHandler(const LLSD& payload); - bool uniqueFilter(LLNotificationPtr pNotification); - bool uniqueHandler(const LLSD& payload); - bool failedUniquenessTest(const LLSD& payload); - LLNotificationChannelPtr pHistoryChannel; - LLNotificationChannelPtr pExpirationChannel; - - TemplateMap mTemplates; - - VisibilityRuleList mVisibilityRules; - - std::string mFileName; - - LLNotificationMap mUniqueNotifications; - - typedef std::map<std::string, std::string> GlobalStringMap; - GlobalStringMap mGlobalStrings; - - bool mIgnoreAllNotifications; - - std::unique_ptr<LLNotificationsListener> mListener; - - std::vector<LLNotificationChannelPtr> mDefaultChannels; + /*virtual*/ void initSingleton() override; + /*virtual*/ void cleanupSingleton() override; + + void loadPersistentNotifications(); + + bool expirationFilter(LLNotificationPtr pNotification); + bool expirationHandler(const LLSD& payload); + bool uniqueFilter(LLNotificationPtr pNotification); + bool uniqueHandler(const LLSD& payload); + bool failedUniquenessTest(const LLSD& payload); + LLNotificationChannelPtr pHistoryChannel; + LLNotificationChannelPtr pExpirationChannel; + + TemplateMap mTemplates; + + VisibilityRuleList mVisibilityRules; + + std::string mFileName; + + LLNotificationMap mUniqueNotifications; + + typedef std::map<std::string, std::string> GlobalStringMap; + GlobalStringMap mGlobalStrings; + + bool mIgnoreAllNotifications; + + std::unique_ptr<LLNotificationsListener> mListener; + + std::vector<LLNotificationChannelPtr> mDefaultChannels; }; /** @@ -1010,64 +1011,64 @@ private: class LLPostponedNotification : public LLMortician { public: - /** - * Performs hooking cache name callback which will add notification to notifications system. - * Type of added notification should be specified by template parameter T - * and non-private derived from LLPostponedNotification class, - * otherwise compilation error will occur. - */ - template<class T> - static void add(const LLNotification::Params& params, - const LLUUID& id, bool is_group) - { - // upcast T to the base type to restrict T derivation from LLPostponedNotification - LLPostponedNotification* thiz = new T(); - thiz->mParams = params; - - // Avoid header file dependency on llcachename.h - thiz->lookupName(id, is_group); - } + /** + * Performs hooking cache name callback which will add notification to notifications system. + * Type of added notification should be specified by template parameter T + * and non-private derived from LLPostponedNotification class, + * otherwise compilation error will occur. + */ + template<class T> + static void add(const LLNotification::Params& params, + const LLUUID& id, bool is_group) + { + // upcast T to the base type to restrict T derivation from LLPostponedNotification + LLPostponedNotification* thiz = new T(); + thiz->mParams = params; + + // Avoid header file dependency on llcachename.h + thiz->lookupName(id, is_group); + } private: - void lookupName(const LLUUID& id, bool is_group); - // only used for groups - void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group); - // only used for avatars - void fetchAvatarName(const LLUUID& id); - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - // used for both group and avatar names - void finalizeName(const std::string& name); - - void cleanup() - { - die(); - } + void lookupName(const LLUUID& id, bool is_group); + // only used for groups + void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group); + // only used for avatars + void fetchAvatarName(const LLUUID& id); + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + // used for both group and avatar names + void finalizeName(const std::string& name); + + void cleanup() + { + die(); + } protected: - LLPostponedNotification() - : mParams(), - mName(), - mAvatarNameCacheConnection() - {} - - virtual ~LLPostponedNotification() - { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } - } - - /** - * Abstract method provides possibility to modify notification parameters and - * will be called after cache name retrieve information about avatar or group - * and before notification will be added to the notification system. - */ - virtual void modifyNotificationParams() = 0; - - LLNotification::Params mParams; - std::string mName; - boost::signals2::connection mAvatarNameCacheConnection; + LLPostponedNotification() + : mParams(), + mName(), + mAvatarNameCacheConnection() + {} + + virtual ~LLPostponedNotification() + { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + } + + /** + * Abstract method provides possibility to modify notification parameters and + * will be called after cache name retrieve information about avatar or group + * and before notification will be added to the notification system. + */ + virtual void modifyNotificationParams() = 0; + + LLNotification::Params mParams; + std::string mName; + boost::signals2::connection mAvatarNameCacheConnection; }; // Stores only persistent notifications. @@ -1075,57 +1076,57 @@ protected: // (see LLPersistentNotificationStorage for example). class LLPersistentNotificationChannel : public LLNotificationChannel { - LOG_CLASS(LLPersistentNotificationChannel); + LOG_CLASS(LLPersistentNotificationChannel); public: - LLPersistentNotificationChannel() - : LLNotificationChannel("Persistent", "Visible", ¬ificationFilter) - {} + LLPersistentNotificationChannel() + : LLNotificationChannel("Persistent", "Visible", ¬ificationFilter) + {} virtual ~LLPersistentNotificationChannel() { mHistory.clear(); } - typedef std::vector<LLNotificationPtr> history_list_t; - history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); } - history_list_t::iterator endHistory() { return mHistory.end(); } + typedef std::vector<LLNotificationPtr> history_list_t; + history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); } + history_list_t::iterator endHistory() { return mHistory.end(); } private: - struct sortByTime - { - S32 operator ()(const LLNotificationPtr& a, const LLNotificationPtr& b) - { - return a->getDate() < b->getDate(); - } - }; - - void sortHistory() - { - std::sort(mHistory.begin(), mHistory.end(), sortByTime()); - } - - // The channel gets all persistent notifications except those that have been canceled - static bool notificationFilter(LLNotificationPtr pNotification) - { - bool handle_notification = false; - - handle_notification = pNotification->isPersistent() - && !pNotification->isCancelled(); - - return handle_notification; - } - - void onAdd(LLNotificationPtr p) - { - mHistory.push_back(p); - } - - void onLoad(LLNotificationPtr p) - { - mHistory.push_back(p); - } - - std::vector<LLNotificationPtr> mHistory; + struct sortByTime + { + S32 operator ()(const LLNotificationPtr& a, const LLNotificationPtr& b) + { + return a->getDate() < b->getDate(); + } + }; + + void sortHistory() + { + std::sort(mHistory.begin(), mHistory.end(), sortByTime()); + } + + // The channel gets all persistent notifications except those that have been canceled + static bool notificationFilter(LLNotificationPtr pNotification) + { + bool handle_notification = false; + + handle_notification = pNotification->isPersistent() + && !pNotification->isCancelled(); + + return handle_notification; + } + + void onAdd(LLNotificationPtr p) + { + mHistory.push_back(p); + } + + void onLoad(LLNotificationPtr p) + { + mHistory.push_back(p); + } + + std::vector<LLNotificationPtr> mHistory; }; #endif//LL_LLNOTIFICATIONS_H diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index 859222f907..ace9e37e25 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2009-07-08 * @brief Implementation for llnotificationslistener. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -87,39 +87,39 @@ LLNotificationsListener::~LLNotificationsListener() void LLNotificationsListener::requestAdd(const LLSD& event_data) const { - if(event_data.has("reply")) - { - LLSD payload(event_data["payload"]); - // copy reqid, if provided, to link response with request - payload["reqid"] = event_data["reqid"]; - mNotifications.add(event_data["name"], - event_data["substitutions"], - payload, - boost::bind(&LLNotificationsListener::NotificationResponder, - this, - event_data["reply"].asString(), - _1, _2 - ) - ); - } - else - { - mNotifications.add(event_data["name"], - event_data["substitutions"], - event_data["payload"]); - } + if(event_data.has("reply")) + { + LLSD payload(event_data["payload"]); + // copy reqid, if provided, to link response with request + payload["reqid"] = event_data["reqid"]; + mNotifications.add(event_data["name"], + event_data["substitutions"], + payload, + boost::bind(&LLNotificationsListener::NotificationResponder, + this, + event_data["reply"].asString(), + _1, _2 + ) + ); + } + else + { + mNotifications.add(event_data["name"], + event_data["substitutions"], + event_data["payload"]); + } } -void LLNotificationsListener::NotificationResponder(const std::string& reply_pump, - const LLSD& notification, - const LLSD& response) const +void LLNotificationsListener::NotificationResponder(const std::string& reply_pump, + const LLSD& notification, + const LLSD& response) const { - LLSD response_event; - response_event["notification"] = notification; - response_event["response"] = response; - // surface reqid at top level of response for request/response protocol - response_event["reqid"] = notification["payload"]["reqid"]; - LLEventPumps::getInstance()->obtain(reply_pump).post(response_event); + LLSD response_event; + response_event["notification"] = notification; + response_event["response"] = response; + // surface reqid at top level of response for request/response protocol + response_event["reqid"] = notification["payload"]["reqid"]; + LLEventPumps::getInstance()->obtain(reply_pump).post(response_event); } void LLNotificationsListener::listChannels(const LLSD& params) const @@ -191,11 +191,11 @@ void LLNotificationsListener::ignore(const LLSD& params) const if (params["name"].isDefined()) { // ["name"] was passed: ignore just that notification - LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]); - if (templatep) - { - templatep->mForm->setIgnored(ignore); - } + LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]); + if (templatep) + { + templatep->mForm->setIgnored(ignore); + } } else { diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h index 4bab377626..65993c9ff8 100644 --- a/indra/llui/llnotificationslistener.h +++ b/indra/llui/llnotificationslistener.h @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2009-07-08 * @brief Wrap subset of LLNotifications API in event API for test scripts. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,9 +46,9 @@ public: private: void requestAdd(LLSD const & event_data) const; - void NotificationResponder(const std::string& replypump, - const LLSD& notification, - const LLSD& response) const; + void NotificationResponder(const std::string& replypump, + const LLSD& notification, + const LLSD& response) const; void listChannels(const LLSD& params) const; void listChannelNotifications(const LLSD& params) const; @@ -62,7 +62,7 @@ private: class Forwarder; typedef std::map<std::string, std::shared_ptr<Forwarder> > ForwarderMap; ForwarderMap mForwarders; - LLNotifications & mNotifications; + LLNotifications & mNotifications; }; #endif // LL_LLNOTIFICATIONSLISTENER_H diff --git a/indra/llui/llnotificationsutil.cpp b/indra/llui/llnotificationsutil.cpp index cc791c26d1..c1cad431c5 100644 --- a/indra/llui/llnotificationsutil.cpp +++ b/indra/llui/llnotificationsutil.cpp @@ -4,21 +4,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,68 +28,68 @@ #include "llnotifications.h" #include "llsd.h" -#include "llxmlnode.h" // apparently needed to call LLNotifications::instance() +#include "llxmlnode.h" // apparently needed to call LLNotifications::instance() LLNotificationPtr LLNotificationsUtil::add(const std::string& name) { - LLNotification::Params::Functor functor_p; - functor_p.name = name; - return LLNotifications::instance().add( - LLNotification::Params().name(name).substitutions(LLSD()).payload(LLSD()).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = name; + return LLNotifications::instance().add( + LLNotification::Params().name(name).substitutions(LLSD()).payload(LLSD()).functor(functor_p)); } -LLNotificationPtr LLNotificationsUtil::add(const std::string& name, - const LLSD& substitutions) +LLNotificationPtr LLNotificationsUtil::add(const std::string& name, + const LLSD& substitutions) { - LLNotification::Params::Functor functor_p; - functor_p.name = name; - return LLNotifications::instance().add( - LLNotification::Params().name(name).substitutions(substitutions).payload(LLSD()).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = name; + return LLNotifications::instance().add( + LLNotification::Params().name(name).substitutions(substitutions).payload(LLSD()).functor(functor_p)); } -LLNotificationPtr LLNotificationsUtil::add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload) +LLNotificationPtr LLNotificationsUtil::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload) { - LLNotification::Params::Functor functor_p; - functor_p.name = name; - return LLNotifications::instance().add( - LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = name; + return LLNotifications::instance().add( + LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); } -LLNotificationPtr LLNotificationsUtil::add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - const std::string& functor_name) +LLNotificationPtr LLNotificationsUtil::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + const std::string& functor_name) { - LLNotification::Params::Functor functor_p; - functor_p.name = functor_name; - return LLNotifications::instance().add( - LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = functor_name; + return LLNotifications::instance().add( + LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); } -LLNotificationPtr LLNotificationsUtil::add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - boost::function<void (const LLSD&, const LLSD&)> functor) +LLNotificationPtr LLNotificationsUtil::add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + boost::function<void (const LLSD&, const LLSD&)> functor) { - LLNotification::Params::Functor functor_p; - functor_p.function = functor; - return LLNotifications::instance().add( - LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.function = functor; + return LLNotifications::instance().add( + LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); } S32 LLNotificationsUtil::getSelectedOption(const LLSD& notification, const LLSD& response) { - return LLNotification::getSelectedOption(notification, response); + return LLNotification::getSelectedOption(notification, response); } void LLNotificationsUtil::cancel(LLNotificationPtr pNotif) { - LLNotifications::instance().cancel(pNotif); + LLNotifications::instance().cancel(pNotif); } LLNotificationPtr LLNotificationsUtil::find(LLUUID uuid) { - return LLNotifications::instance().find(uuid); + return LLNotifications::instance().find(uuid); } diff --git a/indra/llui/llnotificationsutil.h b/indra/llui/llnotificationsutil.h index 9f29087b4a..f21d93a50e 100644 --- a/indra/llui/llnotificationsutil.h +++ b/indra/llui/llnotificationsutil.h @@ -4,28 +4,28 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLNOTIFICATIONSUTIL_H #define LLNOTIFICATIONSUTIL_H -// The vast majority of clients of the notifications system just want to add +// The vast majority of clients of the notifications system just want to add // a notification to the screen, so define this lightweight public interface // to avoid including the heavyweight llnotifications.h @@ -38,30 +38,30 @@ class LLSD; namespace LLNotificationsUtil { - LLNotificationPtr add(const std::string& name); - - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions); - - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload); - - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - const std::string& functor_name); + LLNotificationPtr add(const std::string& name); + + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions); + + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload); + + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + const std::string& functor_name); + + LLNotificationPtr add(const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + boost::function<void (const LLSD&, const LLSD&)> functor); - LLNotificationPtr add(const std::string& name, - const LLSD& substitutions, - const LLSD& payload, - boost::function<void (const LLSD&, const LLSD&)> functor); - - S32 getSelectedOption(const LLSD& notification, const LLSD& response); + S32 getSelectedOption(const LLSD& notification, const LLSD& response); - void cancel(LLNotificationPtr pNotif); + void cancel(LLNotificationPtr pNotif); - LLNotificationPtr find(LLUUID uuid); + LLNotificationPtr find(LLUUID uuid); } #endif diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index a8902486e4..0f77251ffe 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,212 +33,212 @@ typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr; -// This is the class of object read from the XML file (notifications.xml, +// This is the class of object read from the XML file (notifications.xml, // from the appropriate local language directory). struct LLNotificationTemplate { - struct CombineBehaviorNames - : public LLInitParam::TypeValuesHelper<LLNotification::ECombineBehavior, CombineBehaviorNames> - { - static void declareValues() - { - declare("replace_with_new", LLNotification::REPLACE_WITH_NEW); - declare("combine_with_new", LLNotification::COMBINE_WITH_NEW); - declare("keep_old", LLNotification::KEEP_OLD); - declare("cancel_old", LLNotification::CANCEL_OLD); - } - }; - - - struct GlobalString : public LLInitParam::Block<GlobalString> - { - Mandatory<std::string> name, - value; - - GlobalString() - : name("name"), - value("value") - {} - }; - - struct UniquenessContext : public LLInitParam::Block<UniquenessContext> - { - Mandatory<std::string> value; - - UniquenessContext() - : value("value") - { - addSynonym(value, "key"); - } - - }; - - struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint> - { - private: - // this idiom allows - // <notification> <unique/> </notification> - // as well as - // <notification> <unique> <context></context> </unique>... - Optional<LLInitParam::Flag> dummy_val; - public: - Multiple<UniquenessContext> contexts; - Optional<LLNotification::ECombineBehavior, CombineBehaviorNames> combine; - - UniquenessConstraint() - : contexts("context"), - combine("combine", LLNotification::REPLACE_WITH_NEW), - dummy_val("") - {} - }; - - // Templates are used to define common form types, such as OK/Cancel dialogs, etc. - - struct Template : public LLInitParam::Block<Template> - { - Mandatory<std::string> name; - Mandatory<LLNotificationForm::Params> form; - - Template() - : name("name"), - form("form") - {} - }; - - // Reference a template to use its form elements - struct TemplateRef : public LLInitParam::Block<TemplateRef> - { - Mandatory<std::string> name; - Optional<std::string> yes_text, - no_text, - cancel_text, - help_text, - ignore_text; - - TemplateRef() - : name("name"), - yes_text("yestext"), - no_text("notext"), - cancel_text("canceltext"), - help_text("helptext"), - ignore_text("ignoretext") - {} - }; - - struct URL : public LLInitParam::Block<URL> - { - Mandatory<S32> option; - Mandatory<std::string> value; - Optional<std::string> target; - Ignored name; - - URL() - : option("option", -1), - value("value"), - target("target", "_blank"), - name("name") - {} - }; - - struct FormRef : public LLInitParam::ChoiceBlock<FormRef> - { - Alternative<LLNotificationForm::Params> form; - Alternative<TemplateRef> form_template; - - FormRef() - : form("form"), - form_template("usetemplate") - {} - }; - - struct Tag : public LLInitParam::Block<Tag> - { - Mandatory<std::string> value; - - Tag() - : value("value") - {} - }; - - struct Footer : public LLInitParam::Block<Footer> - { - Mandatory<std::string> value; - - Footer() - : value("value") - { - addSynonym(value, ""); - } - }; - - struct Params : public LLInitParam::Block<Params> - { - Mandatory<std::string> name; - Optional<bool> persist, - log_to_im, - show_toast, - fade_toast, - log_to_chat, - force_urls_external; - Optional<std::string> functor, - icon, - label, - sound, - type, - value; - Optional<U32> duration; - Optional<S32> expire_option; - Optional<URL> url; - Optional<UniquenessConstraint> unique; - Optional<FormRef> form_ref; - Optional<ENotificationPriority, - NotificationPriorityValues> priority; - Multiple<Tag> tags; - Optional<Footer> footer; - - - Params() - : name("name"), - persist("persist", false), - fade_toast("fade_toast", true), - log_to_im("log_to_im", false), - show_toast("show_toast", true), - log_to_chat("log_to_chat", true), - force_urls_external("force_urls_external", false), - functor("functor"), - icon("icon"), - label("label"), - priority("priority"), - sound("sound"), - type("type"), - value("value"), - duration("duration"), - expire_option("expireOption", -1), - url("url"), - unique("unique"), - form_ref(""), - tags("tag"), - footer("footer") - {} - - }; - - struct Notifications : public LLInitParam::Block<Notifications> - { - Multiple<GlobalString> strings; - Multiple<Template> templates; - Multiple<Params> notifications; - - Notifications() - : strings("global"), - notifications("notification"), - templates("template") - {} - }; - - LLNotificationTemplate(const Params& p); + struct CombineBehaviorNames + : public LLInitParam::TypeValuesHelper<LLNotification::ECombineBehavior, CombineBehaviorNames> + { + static void declareValues() + { + declare("replace_with_new", LLNotification::REPLACE_WITH_NEW); + declare("combine_with_new", LLNotification::COMBINE_WITH_NEW); + declare("keep_old", LLNotification::KEEP_OLD); + declare("cancel_old", LLNotification::CANCEL_OLD); + } + }; + + + struct GlobalString : public LLInitParam::Block<GlobalString> + { + Mandatory<std::string> name, + value; + + GlobalString() + : name("name"), + value("value") + {} + }; + + struct UniquenessContext : public LLInitParam::Block<UniquenessContext> + { + Mandatory<std::string> value; + + UniquenessContext() + : value("value") + { + addSynonym(value, "key"); + } + + }; + + struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint> + { + private: + // this idiom allows + // <notification> <unique/> </notification> + // as well as + // <notification> <unique> <context></context> </unique>... + Optional<LLInitParam::Flag> dummy_val; + public: + Multiple<UniquenessContext> contexts; + Optional<LLNotification::ECombineBehavior, CombineBehaviorNames> combine; + + UniquenessConstraint() + : contexts("context"), + combine("combine", LLNotification::REPLACE_WITH_NEW), + dummy_val("") + {} + }; + + // Templates are used to define common form types, such as OK/Cancel dialogs, etc. + + struct Template : public LLInitParam::Block<Template> + { + Mandatory<std::string> name; + Mandatory<LLNotificationForm::Params> form; + + Template() + : name("name"), + form("form") + {} + }; + + // Reference a template to use its form elements + struct TemplateRef : public LLInitParam::Block<TemplateRef> + { + Mandatory<std::string> name; + Optional<std::string> yes_text, + no_text, + cancel_text, + help_text, + ignore_text; + + TemplateRef() + : name("name"), + yes_text("yestext"), + no_text("notext"), + cancel_text("canceltext"), + help_text("helptext"), + ignore_text("ignoretext") + {} + }; + + struct URL : public LLInitParam::Block<URL> + { + Mandatory<S32> option; + Mandatory<std::string> value; + Optional<std::string> target; + Ignored name; + + URL() + : option("option", -1), + value("value"), + target("target", "_blank"), + name("name") + {} + }; + + struct FormRef : public LLInitParam::ChoiceBlock<FormRef> + { + Alternative<LLNotificationForm::Params> form; + Alternative<TemplateRef> form_template; + + FormRef() + : form("form"), + form_template("usetemplate") + {} + }; + + struct Tag : public LLInitParam::Block<Tag> + { + Mandatory<std::string> value; + + Tag() + : value("value") + {} + }; + + struct Footer : public LLInitParam::Block<Footer> + { + Mandatory<std::string> value; + + Footer() + : value("value") + { + addSynonym(value, ""); + } + }; + + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; + Optional<bool> persist, + log_to_im, + show_toast, + fade_toast, + log_to_chat, + force_urls_external; + Optional<std::string> functor, + icon, + label, + sound, + type, + value; + Optional<U32> duration; + Optional<S32> expire_option; + Optional<URL> url; + Optional<UniquenessConstraint> unique; + Optional<FormRef> form_ref; + Optional<ENotificationPriority, + NotificationPriorityValues> priority; + Multiple<Tag> tags; + Optional<Footer> footer; + + + Params() + : name("name"), + persist("persist", false), + fade_toast("fade_toast", true), + log_to_im("log_to_im", false), + show_toast("show_toast", true), + log_to_chat("log_to_chat", true), + force_urls_external("force_urls_external", false), + functor("functor"), + icon("icon"), + label("label"), + priority("priority"), + sound("sound"), + type("type"), + value("value"), + duration("duration"), + expire_option("expireOption", -1), + url("url"), + unique("unique"), + form_ref(""), + tags("tag"), + footer("footer") + {} + + }; + + struct Notifications : public LLInitParam::Block<Notifications> + { + Multiple<GlobalString> strings; + Multiple<Template> templates; + Multiple<Params> notifications; + + Notifications() + : strings("global"), + notifications("notification"), + templates("template") + {} + }; + + LLNotificationTemplate(const Params& p); // the name of the notification -- the key used to identify it - // Ideally, the key should follow variable naming rules + // Ideally, the key should follow variable naming rules // (no spaces or punctuation). std::string mName; // The type of the notification @@ -249,13 +249,13 @@ struct LLNotificationTemplate std::string mMessage; // The text used to display the notification, but under the form. std::string mFooter; - // The label for the notification; used for - // certain classes of notification (those with a window and a window title). - // Also used when a notification pops up underneath the current one. - // Replaceable parameters can be used in the label. - std::string mLabel; - // The name of the icon image. This should include an extension. - std::string mIcon; + // The label for the notification; used for + // certain classes of notification (those with a window and a window title). + // Also used when a notification pops up underneath the current one. + // Replaceable parameters can be used in the label. + std::string mLabel; + // The name of the icon image. This should include an extension. + std::string mIcon; // This is the Highlander bit -- "There Can Be Only One" // An outstanding notification with this bit set // is updated by an incoming notification with the same name, @@ -263,25 +263,25 @@ struct LLNotificationTemplate // (used for things like progress indications, or repeating warnings // like "the grid is going down in N minutes") bool mUnique; - LLNotification::ECombineBehavior mCombineBehavior; + LLNotification::ECombineBehavior mCombineBehavior; // if we want to be unique only if a certain part of the payload or substitutions args - // are constant specify the field names for the payload. The notification will only be + // are constant specify the field names for the payload. The notification will only be // combined if all of the fields named in the context are identical in the // new and the old notification; otherwise, the notification will be // duplicated. This is to support suppressing duplicate offers from the same // sender but still differentiating different offers. Example: Invitation to // conference chat. std::vector<std::string> mUniqueContext; - // If this notification expires automatically, this value will be + // If this notification expires automatically, this value will be // nonzero, and indicates the number of seconds for which the notification - // will be valid (a teleport offer, for example, might be valid for - // 300 seconds). + // will be valid (a teleport offer, for example, might be valid for + // 300 seconds). U32 mExpireSeconds; // if the offer expires, one of the options is chosen automatically - // based on its "value" parameter. This controls which one. + // based on its "value" parameter. This controls which one. // If expireSeconds is specified, expireOption should also be specified. U32 mExpireOption; - // if the notification contains a url, it's stored here (and replaced + // if the notification contains a url, it's stored here (and replaced // into the message where [_URL] is found) std::string mURL; // if there's a URL in the message, this controls which option visits @@ -289,36 +289,36 @@ struct LLNotificationTemplate // messages when we allow clickable URLs in the UI U32 mURLOption; - //This is a flag that tells if option url needs to open externally dispite - //what the user setting is. - std::string mURLTarget; - - // All links clicked inside notification will be opened in external browser - // Note: Some notifications block and exit viewer, yet they provide a link - // to click, we should be able to open such links in external browser. - bool mForceUrlsExternal; - - // does this notification persist across sessions? if so, it will be - // serialized to disk on first receipt and read on startup - bool mPersist; - // This is the name of the default functor, if present, to be - // used for the notification's callback. It is optional, and used only if - // the notification is constructed without an identified functor. - std::string mDefaultFunctor; - // The form data associated with a given notification (buttons, text boxes, etc) + //This is a flag that tells if option url needs to open externally dispite + //what the user setting is. + std::string mURLTarget; + + // All links clicked inside notification will be opened in external browser + // Note: Some notifications block and exit viewer, yet they provide a link + // to click, we should be able to open such links in external browser. + bool mForceUrlsExternal; + + // does this notification persist across sessions? if so, it will be + // serialized to disk on first receipt and read on startup + bool mPersist; + // This is the name of the default functor, if present, to be + // used for the notification's callback. It is optional, and used only if + // the notification is constructed without an identified functor. + std::string mDefaultFunctor; + // The form data associated with a given notification (buttons, text boxes, etc) LLNotificationFormPtr mForm; - // default priority for notifications of this type - ENotificationPriority mPriority; - // Stores the sound name which can then be used to play the sound using make_ui_sound - std::string mSoundName; - // List of tags that rules can match against. - std::list<std::string> mTags; - - // inject these notifications into chat/IM streams - bool mLogToChat; - bool mLogToIM; - bool mShowToast; - bool mFadeToast; + // default priority for notifications of this type + ENotificationPriority mPriority; + // Stores the sound name which can then be used to play the sound using make_ui_sound + std::string mSoundName; + // List of tags that rules can match against. + std::list<std::string> mTags; + + // inject these notifications into chat/IM streams + bool mLogToChat; + bool mLogToIM; + bool mShowToast; + bool mFadeToast; }; #endif //LL_LLNOTIFICATION_TEMPLATE_H diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h index 78788a275c..064b3b148e 100644 --- a/indra/llui/llnotificationvisibilityrule.h +++ b/indra/llui/llnotificationvisibilityrule.h @@ -1,26 +1,26 @@ /** * @file llnotificationvisibility.h -* @brief Rules for +* @brief Rules for * @author Monroe * * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,71 +33,71 @@ -// This is the class of object read from the XML file (notification_visibility.xml, +// This is the class of object read from the XML file (notification_visibility.xml, // from the appropriate local language directory). struct LLNotificationVisibilityRule { - struct Filter : public LLInitParam::Block<Filter> - { - Optional<std::string> type, - tag, - name; - - Filter() - : type("type"), - tag("tag"), - name("name") - {} - }; - - struct Respond : public LLInitParam::Block<Respond, Filter> - { - Mandatory<std::string> response; - - Respond() - : response("response") - {} - }; - - struct Rule : public LLInitParam::ChoiceBlock<Rule> - { - Alternative<Filter> show; - Alternative<Filter> hide; - Alternative<Respond> respond; - - Rule() - : show("show"), - hide("hide"), - respond("respond") - {} - }; - - struct Rules : public LLInitParam::Block<Rules> - { - Multiple<Rule> rules; - - Rules() - : rules("") - {} - }; - - LLNotificationVisibilityRule(const Rule& p); - + struct Filter : public LLInitParam::Block<Filter> + { + Optional<std::string> type, + tag, + name; + + Filter() + : type("type"), + tag("tag"), + name("name") + {} + }; + + struct Respond : public LLInitParam::Block<Respond, Filter> + { + Mandatory<std::string> response; + + Respond() + : response("response") + {} + }; + + struct Rule : public LLInitParam::ChoiceBlock<Rule> + { + Alternative<Filter> show; + Alternative<Filter> hide; + Alternative<Respond> respond; + + Rule() + : show("show"), + hide("hide"), + respond("respond") + {} + }; + + struct Rules : public LLInitParam::Block<Rules> + { + Multiple<Rule> rules; + + Rules() + : rules("") + {} + }; + + LLNotificationVisibilityRule(const Rule& p); + // If true, this rule makes matching notifications visible. Otherwise, it makes them invisible. bool mVisible; // Which response to give when making a notification invisible. An empty string means the notification should be cancelled instead of responded to. - std::string mResponse; + std::string mResponse; // String to match against the notification's "type". An empty string matches all notifications. std::string mType; - + // String to match against the notification's tag(s). An empty string matches all notifications. - std::string mTag; + std::string mTag; // String to match against the notification's name. An empty string matches all notifications. - std::string mName; - + std::string mName; + }; #endif //LL_LLNOTIFICATION_VISIBILITY_RULE_H diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index f770920c4a..d580566b13 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanel.cpp * @brief LLPanel base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,454 +50,454 @@ #include "llviewborder.h" static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML); -LLPanel::factory_stack_t LLPanel::sFactoryStack; +LLPanel::factory_stack_t LLPanel::sFactoryStack; // Compiler optimization, generate extern template template class LLPanel* LLView::getChild<class LLPanel>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; LLPanel::LocalizedString::LocalizedString() -: name("name"), - value("value") +: name("name"), + value("value") {} -const LLPanel::Params& LLPanel::getDefaultParams() -{ - return LLUICtrlFactory::getDefaultParams<LLPanel>(); +const LLPanel::Params& LLPanel::getDefaultParams() +{ + return LLUICtrlFactory::getDefaultParams<LLPanel>(); } LLPanel::Params::Params() -: has_border("border", false), - border(""), - background_visible("background_visible", false), - background_opaque("background_opaque", false), - bg_opaque_color("bg_opaque_color"), - bg_alpha_color("bg_alpha_color"), - bg_opaque_image_overlay("bg_opaque_image_overlay"), - bg_alpha_image_overlay("bg_alpha_image_overlay"), - bg_opaque_image("bg_opaque_image"), - bg_alpha_image("bg_alpha_image"), - min_width("min_width", 100), - min_height("min_height", 100), - strings("string"), - filename("filename"), - class_name("class"), - help_topic("help_topic"), - visible_callback("visible_callback"), - accepts_badge("accepts_badge") -{ - addSynonym(background_visible, "bg_visible"); - addSynonym(has_border, "border_visible"); - addSynonym(label, "title"); +: has_border("border", false), + border(""), + background_visible("background_visible", false), + background_opaque("background_opaque", false), + bg_opaque_color("bg_opaque_color"), + bg_alpha_color("bg_alpha_color"), + bg_opaque_image_overlay("bg_opaque_image_overlay"), + bg_alpha_image_overlay("bg_alpha_image_overlay"), + bg_opaque_image("bg_opaque_image"), + bg_alpha_image("bg_alpha_image"), + min_width("min_width", 100), + min_height("min_height", 100), + strings("string"), + filename("filename"), + class_name("class"), + help_topic("help_topic"), + visible_callback("visible_callback"), + accepts_badge("accepts_badge") +{ + addSynonym(background_visible, "bg_visible"); + addSynonym(has_border, "border_visible"); + addSynonym(label, "title"); } LLPanel::LLPanel(const LLPanel::Params& p) -: LLUICtrl(p), - LLBadgeHolder(p.accepts_badge), - mBgVisible(p.background_visible), - mBgOpaque(p.background_opaque), - mBgOpaqueColor(p.bg_opaque_color()), - mBgAlphaColor(p.bg_alpha_color()), - mBgOpaqueImageOverlay(p.bg_opaque_image_overlay), - mBgAlphaImageOverlay(p.bg_alpha_image_overlay), - mBgOpaqueImage(p.bg_opaque_image()), - mBgAlphaImage(p.bg_alpha_image()), - mDefaultBtn(NULL), - mBorder(NULL), - mLabel(p.label), - mHelpTopic(p.help_topic), - mCommitCallbackRegistrar(false), - mEnableCallbackRegistrar(false), - mXMLFilename(p.filename), - mVisibleSignal(NULL) - // *NOTE: Be sure to also change LLPanel::initFromParams(). We have too - // many classes derived from LLPanel to retrofit them all to pass in params. -{ - if (p.has_border) - { - addBorder(p.border); - } +: LLUICtrl(p), + LLBadgeHolder(p.accepts_badge), + mBgVisible(p.background_visible), + mBgOpaque(p.background_opaque), + mBgOpaqueColor(p.bg_opaque_color()), + mBgAlphaColor(p.bg_alpha_color()), + mBgOpaqueImageOverlay(p.bg_opaque_image_overlay), + mBgAlphaImageOverlay(p.bg_alpha_image_overlay), + mBgOpaqueImage(p.bg_opaque_image()), + mBgAlphaImage(p.bg_alpha_image()), + mDefaultBtn(NULL), + mBorder(NULL), + mLabel(p.label), + mHelpTopic(p.help_topic), + mCommitCallbackRegistrar(false), + mEnableCallbackRegistrar(false), + mXMLFilename(p.filename), + mVisibleSignal(NULL) + // *NOTE: Be sure to also change LLPanel::initFromParams(). We have too + // many classes derived from LLPanel to retrofit them all to pass in params. +{ + if (p.has_border) + { + addBorder(p.border); + } } LLPanel::~LLPanel() { - delete mVisibleSignal; + delete mVisibleSignal; } // virtual BOOL LLPanel::isPanel() const { - return TRUE; + return TRUE; } void LLPanel::addBorder(LLViewBorder::Params p) { - removeBorder(); - p.rect = getLocalRect(); + removeBorder(); + p.rect = getLocalRect(); - mBorder = LLUICtrlFactory::create<LLViewBorder>(p); - addChild( mBorder ); + mBorder = LLUICtrlFactory::create<LLViewBorder>(p); + addChild( mBorder ); } -void LLPanel::addBorder() -{ - LLViewBorder::Params p; - p.border_thickness(LLPANEL_BORDER_WIDTH); - addBorder(p); +void LLPanel::addBorder() +{ + LLViewBorder::Params p; + p.border_thickness(LLPANEL_BORDER_WIDTH); + addBorder(p); } void LLPanel::removeBorder() { - if (mBorder) - { - removeChild(mBorder); - delete mBorder; - mBorder = NULL; - } + if (mBorder) + { + removeChild(mBorder); + delete mBorder; + mBorder = NULL; + } } // virtual void LLPanel::clearCtrls() { - LLPanel::ctrl_list_t ctrls = getCtrlList(); - for (LLPanel::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it) - { - LLUICtrl* ctrl = *ctrl_it; - ctrl->setFocus( FALSE ); - ctrl->setEnabled( FALSE ); - ctrl->clear(); - } + LLPanel::ctrl_list_t ctrls = getCtrlList(); + for (LLPanel::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it) + { + LLUICtrl* ctrl = *ctrl_it; + ctrl->setFocus( FALSE ); + ctrl->setEnabled( FALSE ); + ctrl->clear(); + } } void LLPanel::setCtrlsEnabled( BOOL b ) { - LLPanel::ctrl_list_t ctrls = getCtrlList(); - for (LLPanel::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it) - { - LLUICtrl* ctrl = *ctrl_it; - ctrl->setEnabled( b ); - } + LLPanel::ctrl_list_t ctrls = getCtrlList(); + for (LLPanel::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it) + { + LLUICtrl* ctrl = *ctrl_it; + ctrl->setEnabled( b ); + } } LLPanel::ctrl_list_t LLPanel::getCtrlList() const { - ctrl_list_t controls; - for(child_list_t::const_iterator it = getChildList()->begin(), end_it = getChildList()->end(); it != end_it; ++it) - { - LLView* viewp = *it; - if(viewp->isCtrl()) - { - controls.push_back(static_cast<LLUICtrl*>(viewp)); - } - } - return controls; + ctrl_list_t controls; + for(child_list_t::const_iterator it = getChildList()->begin(), end_it = getChildList()->end(); it != end_it; ++it) + { + LLView* viewp = *it; + if(viewp->isCtrl()) + { + controls.push_back(static_cast<LLUICtrl*>(viewp)); + } + } + return controls; } void LLPanel::draw() { - F32 alpha = getDrawContext().mAlpha; - - // draw background - if( mBgVisible ) - { - alpha = getCurrentTransparency(); - - LLRect local_rect = getLocalRect(); - if (mBgOpaque ) - { - // opaque, in-front look - if (mBgOpaqueImage.notNull()) - { - mBgOpaqueImage->draw( local_rect, mBgOpaqueImageOverlay % alpha ); - } - else - { - // fallback to flat colors when there are no images - gl_rect_2d( local_rect, mBgOpaqueColor.get() % alpha); - } - } - else - { - // transparent, in-back look - if (mBgAlphaImage.notNull()) - { - mBgAlphaImage->draw( local_rect, mBgAlphaImageOverlay % alpha ); - } - else - { - gl_rect_2d( local_rect, mBgAlphaColor.get() % alpha ); - } - } - } - - updateDefaultBtn(); - - LLView::draw(); + F32 alpha = getDrawContext().mAlpha; + + // draw background + if( mBgVisible ) + { + alpha = getCurrentTransparency(); + + LLRect local_rect = getLocalRect(); + if (mBgOpaque ) + { + // opaque, in-front look + if (mBgOpaqueImage.notNull()) + { + mBgOpaqueImage->draw( local_rect, mBgOpaqueImageOverlay % alpha ); + } + else + { + // fallback to flat colors when there are no images + gl_rect_2d( local_rect, mBgOpaqueColor.get() % alpha); + } + } + else + { + // transparent, in-back look + if (mBgAlphaImage.notNull()) + { + mBgAlphaImage->draw( local_rect, mBgAlphaImageOverlay % alpha ); + } + else + { + gl_rect_2d( local_rect, mBgAlphaColor.get() % alpha ); + } + } + } + + updateDefaultBtn(); + + LLView::draw(); } void LLPanel::updateDefaultBtn() { - if( mDefaultBtn) - { - if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) - { - LLButton* buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus()); - BOOL focus_is_child_button = buttonp && buttonp->getCommitOnReturn(); - // only enable default button when current focus is not a return-capturing button - mDefaultBtn->setBorderEnabled(!focus_is_child_button); - } - else - { - mDefaultBtn->setBorderEnabled(FALSE); - } - } + if( mDefaultBtn) + { + if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) + { + LLButton* buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus()); + BOOL focus_is_child_button = buttonp && buttonp->getCommitOnReturn(); + // only enable default button when current focus is not a return-capturing button + mDefaultBtn->setBorderEnabled(!focus_is_child_button); + } + else + { + mDefaultBtn->setBorderEnabled(FALSE); + } + } } void LLPanel::refresh() { - // do nothing by default - // but is automatically called in setFocus(TRUE) + // do nothing by default + // but is automatically called in setFocus(TRUE) } void LLPanel::setDefaultBtn(LLButton* btn) { - if (mDefaultBtn && mDefaultBtn->getEnabled()) - { - mDefaultBtn->setBorderEnabled(FALSE); - } - mDefaultBtn = btn; - if (mDefaultBtn) - { - mDefaultBtn->setBorderEnabled(TRUE); - } + if (mDefaultBtn && mDefaultBtn->getEnabled()) + { + mDefaultBtn->setBorderEnabled(FALSE); + } + mDefaultBtn = btn; + if (mDefaultBtn) + { + mDefaultBtn->setBorderEnabled(TRUE); + } } void LLPanel::setDefaultBtn(const std::string& id) { - LLButton *button = getChild<LLButton>(id); - if (button) - { - setDefaultBtn(button); - } - else - { - setDefaultBtn(NULL); - } + LLButton *button = getChild<LLButton>(id); + if (button) + { + setDefaultBtn(button); + } + else + { + setDefaultBtn(NULL); + } } BOOL LLPanel::handleKeyHere( KEY key, MASK mask ) { - BOOL handled = FALSE; - - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - - // handle user hitting ESC to defocus - if (key == KEY_ESCAPE) - { - setFocus(FALSE); - return TRUE; - } - else if( (mask == MASK_SHIFT) && (KEY_TAB == key)) - { - //SHIFT-TAB - if (cur_focus) - { - LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); - if (focus_root) - { - handled = focus_root->focusPrevItem(FALSE); - } - } - } - else if( (mask == MASK_NONE ) && (KEY_TAB == key)) - { - //TAB - if (cur_focus) - { - LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); - if (focus_root) - { - handled = focus_root->focusNextItem(FALSE); - } - } - } - - // If RETURN was pressed and something has focus, call onCommit() - if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE) - { - LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus); - if (focused_button && focused_button->getCommitOnReturn()) - { - // current focus is a return-capturing button, - // let *that* button handle the return key - handled = FALSE; - } - else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled()) - { - // If we have a default button, click it when return is pressed - mDefaultBtn->onCommit(); - handled = TRUE; - } - else if (cur_focus->acceptsTextInput()) - { - // call onCommit for text input handling control - cur_focus->onCommit(); - handled = TRUE; - } - } - - return handled; + BOOL handled = FALSE; + + LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); + + // handle user hitting ESC to defocus + if (key == KEY_ESCAPE) + { + setFocus(FALSE); + return TRUE; + } + else if( (mask == MASK_SHIFT) && (KEY_TAB == key)) + { + //SHIFT-TAB + if (cur_focus) + { + LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); + if (focus_root) + { + handled = focus_root->focusPrevItem(FALSE); + } + } + } + else if( (mask == MASK_NONE ) && (KEY_TAB == key)) + { + //TAB + if (cur_focus) + { + LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); + if (focus_root) + { + handled = focus_root->focusNextItem(FALSE); + } + } + } + + // If RETURN was pressed and something has focus, call onCommit() + if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE) + { + LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus); + if (focused_button && focused_button->getCommitOnReturn()) + { + // current focus is a return-capturing button, + // let *that* button handle the return key + handled = FALSE; + } + else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled()) + { + // If we have a default button, click it when return is pressed + mDefaultBtn->onCommit(); + handled = TRUE; + } + else if (cur_focus->acceptsTextInput()) + { + // call onCommit for text input handling control + cur_focus->onCommit(); + handled = TRUE; + } + } + + return handled; } void LLPanel::onVisibilityChange ( BOOL new_visibility ) { - LLUICtrl::onVisibilityChange ( new_visibility ); - if (mVisibleSignal) - (*mVisibleSignal)(this, LLSD(new_visibility) ); // Pass BOOL as LLSD + LLUICtrl::onVisibilityChange ( new_visibility ); + if (mVisibleSignal) + (*mVisibleSignal)(this, LLSD(new_visibility) ); // Pass BOOL as LLSD } void LLPanel::setFocus(BOOL b) { - if( b && !hasFocus()) - { - // give ourselves focus preemptively, to avoid infinite loop - LLUICtrl::setFocus(TRUE); - // then try to pass to first valid child - focusFirstItem(); - } - else - { - LLUICtrl::setFocus(b); - } + if( b && !hasFocus()) + { + // give ourselves focus preemptively, to avoid infinite loop + LLUICtrl::setFocus(TRUE); + // then try to pass to first valid child + focusFirstItem(); + } + else + { + LLUICtrl::setFocus(b); + } } void LLPanel::setBorderVisible(BOOL b) { - if (mBorder) - { - mBorder->setVisible( b ); - } + if (mBorder) + { + mBorder->setVisible( b ); + } } LLTrace::BlockTimerStatHandle FTM_PANEL_CONSTRUCTION("Panel Construction"); LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node) { - std::string name("panel"); - node->getAttributeString("name", name); - - std::string class_attr; - node->getAttributeString("class", class_attr); - - LLPanel* panelp = NULL; - - { LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); - - if(!class_attr.empty()) - { - panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr); - if (!panelp) - { - LL_WARNS() << "Panel class \"" << class_attr << "\" not registered." << LL_ENDL; - } - } - - if (!panelp) - { - panelp = createFactoryPanel(name); - llassert(panelp); - - if (!panelp) - { - return NULL; // :( - } - } - - } - // factory panels may have registered their own factory maps - if (!panelp->getFactoryMap().empty()) - { - sFactoryStack.push_back(&panelp->getFactoryMap()); - } - // for local registry callbacks; define in constructor, referenced in XUI or postBuild - panelp->mCommitCallbackRegistrar.pushScope(); - panelp->mEnableCallbackRegistrar.pushScope(); - - panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>()); - - panelp->mCommitCallbackRegistrar.popScope(); - panelp->mEnableCallbackRegistrar.popScope(); - - if (!panelp->getFactoryMap().empty()) - { - sFactoryStack.pop_back(); - } - - return panelp; + std::string name("panel"); + node->getAttributeString("name", name); + + std::string class_attr; + node->getAttributeString("class", class_attr); + + LLPanel* panelp = NULL; + + { LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); + + if(!class_attr.empty()) + { + panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr); + if (!panelp) + { + LL_WARNS() << "Panel class \"" << class_attr << "\" not registered." << LL_ENDL; + } + } + + if (!panelp) + { + panelp = createFactoryPanel(name); + llassert(panelp); + + if (!panelp) + { + return NULL; // :( + } + } + + } + // factory panels may have registered their own factory maps + if (!panelp->getFactoryMap().empty()) + { + sFactoryStack.push_back(&panelp->getFactoryMap()); + } + // for local registry callbacks; define in constructor, referenced in XUI or postBuild + panelp->mCommitCallbackRegistrar.pushScope(); + panelp->mEnableCallbackRegistrar.pushScope(); + + panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>()); + + panelp->mCommitCallbackRegistrar.popScope(); + panelp->mEnableCallbackRegistrar.popScope(); + + if (!panelp->getFactoryMap().empty()) + { + sFactoryStack.pop_back(); + } + + return panelp; } void LLPanel::initFromParams(const LLPanel::Params& p) { //setting these here since panel constructor not called with params - //and LLView::initFromParams will use them to set visible and enabled - setVisible(p.visible); - setEnabled(p.enabled); - setFocusRoot(p.focus_root); - setSoundFlags(p.sound_flags); - - // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible - LLUICtrl::initFromParams(p); - - // visible callback - if (p.visible_callback.isProvided()) - { - setVisibleCallback(initCommitCallback(p.visible_callback)); - } - - for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin(); - it != p.strings.end(); - ++it) - { - mUIStrings[it->name] = it->value; - } - - setLabel(p.label()); - setHelpTopic(p.help_topic); - setShape(p.rect); - parseFollowsFlags(p); - - setToolTip(p.tool_tip()); - setFromXUI(p.from_xui); - - mHoverCursor = getCursorFromString(p.hover_cursor); - - if (p.has_border) - { - addBorder(p.border); - } - // let constructors set this value if not provided - if (p.use_bounding_rect.isProvided()) - { - setUseBoundingRect(p.use_bounding_rect); - } - setDefaultTabGroup(p.default_tab_group); - setMouseOpaque(p.mouse_opaque); - - setBackgroundVisible(p.background_visible); - setBackgroundOpaque(p.background_opaque); - setBackgroundColor(p.bg_opaque_color().get()); - setTransparentColor(p.bg_alpha_color().get()); - mBgOpaqueImage = p.bg_opaque_image(); - mBgAlphaImage = p.bg_alpha_image(); - mBgOpaqueImageOverlay = p.bg_opaque_image_overlay; - mBgAlphaImageOverlay = p.bg_alpha_image_overlay; - - setAcceptsBadge(p.accepts_badge); + //and LLView::initFromParams will use them to set visible and enabled + setVisible(p.visible); + setEnabled(p.enabled); + setFocusRoot(p.focus_root); + setSoundFlags(p.sound_flags); + + // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible + LLUICtrl::initFromParams(p); + + // visible callback + if (p.visible_callback.isProvided()) + { + setVisibleCallback(initCommitCallback(p.visible_callback)); + } + + for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin(); + it != p.strings.end(); + ++it) + { + mUIStrings[it->name] = it->value; + } + + setLabel(p.label()); + setHelpTopic(p.help_topic); + setShape(p.rect); + parseFollowsFlags(p); + + setToolTip(p.tool_tip()); + setFromXUI(p.from_xui); + + mHoverCursor = getCursorFromString(p.hover_cursor); + + if (p.has_border) + { + addBorder(p.border); + } + // let constructors set this value if not provided + if (p.use_bounding_rect.isProvided()) + { + setUseBoundingRect(p.use_bounding_rect); + } + setDefaultTabGroup(p.default_tab_group); + setMouseOpaque(p.mouse_opaque); + + setBackgroundVisible(p.background_visible); + setBackgroundOpaque(p.background_opaque); + setBackgroundColor(p.bg_opaque_color().get()); + setTransparentColor(p.bg_alpha_color().get()); + mBgOpaqueImage = p.bg_opaque_image(); + mBgAlphaImage = p.bg_alpha_image(); + mBgOpaqueImageOverlay = p.bg_opaque_image_overlay; + mBgAlphaImageOverlay = p.bg_alpha_image_overlay; + + setAcceptsBadge(p.accepts_badge); } static LLTrace::BlockTimerStatHandle FTM_PANEL_SETUP("Panel Setup"); @@ -506,178 +506,178 @@ static LLTrace::BlockTimerStatHandle FTM_PANEL_POSTBUILD("Panel PostBuild"); BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params) { - Params params(default_params); - { - LL_RECORD_BLOCK_TIME(FTM_PANEL_SETUP); - - LLXMLNodePtr referenced_xml; - std::string xml_filename = mXMLFilename; - - // if the panel didn't provide a filename, check the node - if (xml_filename.empty()) - { - node->getAttributeString("filename", xml_filename); - setXMLFilename(xml_filename); - } - - LLXUIParser parser; - - if (!xml_filename.empty()) - { - if (output_node) - { - //if we are exporting, we want to export the current xml - //not the referenced xml - parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); - Params output_params(params); - setupParamsForExport(output_params, parent); - output_node->setName(node->getName()->mString); - parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); - return TRUE; - } - - LLUICtrlFactory::instance().pushFileName(xml_filename); - - LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_PANEL_LOAD); - if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) - { - LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; - - return FALSE; - } - - parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); - - // add children using dimensions from referenced xml for consistent layout - setShape(params.rect); - LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); - - LLUICtrlFactory::instance().popFileName(); - } - - // ask LLUICtrlFactory for filename, since xml_filename might be empty - parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); - - if (output_node) - { - Params output_params(params); - setupParamsForExport(output_params, parent); - output_node->setName(node->getName()->mString); - parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); - } - - params.from_xui = true; - applyXUILayout(params, parent); - { - LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); - initFromParams(params); - } - - // add children - LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); - - // Connect to parent after children are built, because tab containers - // do a reshape() on their child panels, which requires that the children - // be built/added. JC - if (parent) - { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); - parent->addChild(this, tab_group); - } - - { - LL_RECORD_BLOCK_TIME(FTM_PANEL_POSTBUILD); - postBuild(); - } - } - return TRUE; + Params params(default_params); + { + LL_RECORD_BLOCK_TIME(FTM_PANEL_SETUP); + + LLXMLNodePtr referenced_xml; + std::string xml_filename = mXMLFilename; + + // if the panel didn't provide a filename, check the node + if (xml_filename.empty()) + { + node->getAttributeString("filename", xml_filename); + setXMLFilename(xml_filename); + } + + LLXUIParser parser; + + if (!xml_filename.empty()) + { + if (output_node) + { + //if we are exporting, we want to export the current xml + //not the referenced xml + parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); + Params output_params(params); + setupParamsForExport(output_params, parent); + output_node->setName(node->getName()->mString); + parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); + return TRUE; + } + + LLUICtrlFactory::instance().pushFileName(xml_filename); + + LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_PANEL_LOAD); + if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) + { + LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; + + return FALSE; + } + + parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); + + // add children using dimensions from referenced xml for consistent layout + setShape(params.rect); + LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); + + LLUICtrlFactory::instance().popFileName(); + } + + // ask LLUICtrlFactory for filename, since xml_filename might be empty + parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); + + if (output_node) + { + Params output_params(params); + setupParamsForExport(output_params, parent); + output_node->setName(node->getName()->mString); + parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params); + } + + params.from_xui = true; + applyXUILayout(params, parent); + { + LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); + initFromParams(params); + } + + // add children + LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); + + // Connect to parent after children are built, because tab containers + // do a reshape() on their child panels, which requires that the children + // be built/added. JC + if (parent) + { + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); + parent->addChild(this, tab_group); + } + + { + LL_RECORD_BLOCK_TIME(FTM_PANEL_POSTBUILD); + postBuild(); + } + } + return TRUE; } bool LLPanel::hasString(const std::string& name) { - return mUIStrings.find(name) != mUIStrings.end(); + return mUIStrings.find(name) != mUIStrings.end(); } std::string LLPanel::getString(const std::string& name, const LLStringUtil::format_map_t& args) const { - ui_string_map_t::const_iterator found_it = mUIStrings.find(name); - if (found_it != mUIStrings.end()) - { - // make a copy as format works in place - LLUIString formatted_string = LLUIString(found_it->second); - formatted_string.setArgList(args); - return formatted_string.getString(); - } - std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate - if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) - { - LL_ERRS() << err_str << LL_ENDL; - } - else - { - LL_WARNS() << err_str << LL_ENDL; - } - return LLStringUtil::null; + ui_string_map_t::const_iterator found_it = mUIStrings.find(name); + if (found_it != mUIStrings.end()) + { + // make a copy as format works in place + LLUIString formatted_string = LLUIString(found_it->second); + formatted_string.setArgList(args); + return formatted_string.getString(); + } + std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate + if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) + { + LL_ERRS() << err_str << LL_ENDL; + } + else + { + LL_WARNS() << err_str << LL_ENDL; + } + return LLStringUtil::null; } std::string LLPanel::getString(const std::string& name) const { - ui_string_map_t::const_iterator found_it = mUIStrings.find(name); - if (found_it != mUIStrings.end()) - { - return found_it->second; - } - std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate - if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) - { - LL_ERRS() << err_str << LL_ENDL; - } - else - { - LL_WARNS() << err_str << LL_ENDL; - } - return LLStringUtil::null; + ui_string_map_t::const_iterator found_it = mUIStrings.find(name); + if (found_it != mUIStrings.end()) + { + return found_it->second; + } + std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate + if(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("QAMode")) + { + LL_ERRS() << err_str << LL_ENDL; + } + else + { + LL_WARNS() << err_str << LL_ENDL; + } + return LLStringUtil::null; } void LLPanel::childSetVisible(const std::string& id, bool visible) { - LLView* child = findChild<LLView>(id); - if (child) - { - child->setVisible(visible); - } + LLView* child = findChild<LLView>(id); + if (child) + { + child->setVisible(visible); + } } void LLPanel::childSetEnabled(const std::string& id, bool enabled) { - LLView* child = findChild<LLView>(id); - if (child) - { - child->setEnabled(enabled); - } + LLView* child = findChild<LLView>(id); + if (child) + { + child->setEnabled(enabled); + } } void LLPanel::childSetFocus(const std::string& id, BOOL focus) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - child->setFocus(focus); - } + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + child->setFocus(focus); + } } BOOL LLPanel::childHasFocus(const std::string& id) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->hasFocus(); - } - else - { - return FALSE; - } + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->hasFocus(); + } + else + { + return FALSE; + } } // *TODO: Deprecate; for backwards compatability only: @@ -686,118 +686,118 @@ BOOL LLPanel::childHasFocus(const std::string& id) // a named callback and reference it in XML. void LLPanel::childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - child->setCommitCallback(boost::bind(cb, child, data)); - } + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + child->setCommitCallback(boost::bind(cb, child, data)); + } } void LLPanel::childSetColor(const std::string& id, const LLColor4& color) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - child->setColor(color); - } + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + child->setColor(color); + } } LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const std::string& id) const { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->getSelectionInterface(); - } - return NULL; + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->getSelectionInterface(); + } + return NULL; } LLCtrlListInterface* LLPanel::childGetListInterface(const std::string& id) const { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->getListInterface(); - } - return NULL; + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->getListInterface(); + } + return NULL; } LLCtrlScrollInterface* LLPanel::childGetScrollInterface(const std::string& id) const { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->getScrollInterface(); - } - return NULL; + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->getScrollInterface(); + } + return NULL; } void LLPanel::childSetValue(const std::string& id, LLSD value) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - child->setValue(value); - } + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + child->setValue(value); + } } LLSD LLPanel::childGetValue(const std::string& id) const { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->getValue(); - } - // Not found => return undefined - return LLSD(); + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->getValue(); + } + // Not found => return undefined + return LLSD(); } BOOL LLPanel::childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text) { - LLUICtrl* child = findChild<LLUICtrl>(id); - if (child) - { - return child->setTextArg(key, text); - } - return FALSE; + LLUICtrl* child = findChild<LLUICtrl>(id); + if (child) + { + return child->setTextArg(key, text); + } + return FALSE; } BOOL LLPanel::childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text) { - LLView* child = findChild<LLView>(id); - if (child) - { - return child->setLabelArg(key, text); - } - return FALSE; + LLView* child = findChild<LLView>(id); + if (child) + { + return child->setLabelArg(key, text); + } + return FALSE; } void LLPanel::childSetAction(const std::string& id, const commit_signal_t::slot_type& function) { - LLButton* button = findChild<LLButton>(id); - if (button) - { - button->setClickedCallback(function); - } + LLButton* button = findChild<LLButton>(id); + if (button) + { + button->setClickedCallback(function); + } } void LLPanel::childSetAction(const std::string& id, boost::function<void(void*)> function, void* value) { - LLButton* button = findChild<LLButton>(id); - if (button) - { - button->setClickedCallback(boost::bind(function, value)); - } + LLButton* button = findChild<LLButton>(id); + if (button) + { + button->setClickedCallback(boost::bind(function, value)); + } } boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::slot_type& cb ) { - if (!mVisibleSignal) - { - mVisibleSignal = new commit_signal_t(); - } + if (!mVisibleSignal) + { + mVisibleSignal = new commit_signal_t(); + } - return mVisibleSignal->connect(cb); + return mVisibleSignal->connect(cb); } //----------------------------------------------------------------------------- @@ -806,49 +806,49 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t:: BOOL LLPanel::buildFromFile(const std::string& filename, const LLPanel::Params& default_params) { LL_PROFILE_ZONE_SCOPED; - BOOL didPost = FALSE; - LLXMLNodePtr root; - - if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) - { - LL_WARNS() << "Couldn't parse panel from: " << filename << LL_ENDL; - return didPost; - } - - // root must be called panel - if( !root->hasName("panel" ) ) - { - LL_WARNS() << "Root node should be named panel in : " << filename << LL_ENDL; - return didPost; - } - - LL_DEBUGS() << "Building panel " << filename << LL_ENDL; - - LLUICtrlFactory::instance().pushFileName(filename); - { - if (!getFactoryMap().empty()) - { - sFactoryStack.push_back(&getFactoryMap()); - } - - // for local registry callbacks; define in constructor, referenced in XUI or postBuild - getCommitCallbackRegistrar().pushScope(); - getEnableCallbackRegistrar().pushScope(); - - didPost = initPanelXML(root, NULL, NULL, default_params); - - getCommitCallbackRegistrar().popScope(); - getEnableCallbackRegistrar().popScope(); - - setXMLFilename(filename); - - if (!getFactoryMap().empty()) - { - sFactoryStack.pop_back(); - } - } - LLUICtrlFactory::instance().popFileName(); - return didPost; + BOOL didPost = FALSE; + LLXMLNodePtr root; + + if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) + { + LL_WARNS() << "Couldn't parse panel from: " << filename << LL_ENDL; + return didPost; + } + + // root must be called panel + if( !root->hasName("panel" ) ) + { + LL_WARNS() << "Root node should be named panel in : " << filename << LL_ENDL; + return didPost; + } + + LL_DEBUGS() << "Building panel " << filename << LL_ENDL; + + LLUICtrlFactory::instance().pushFileName(filename); + { + if (!getFactoryMap().empty()) + { + sFactoryStack.push_back(&getFactoryMap()); + } + + // for local registry callbacks; define in constructor, referenced in XUI or postBuild + getCommitCallbackRegistrar().pushScope(); + getEnableCallbackRegistrar().pushScope(); + + didPost = initPanelXML(root, NULL, NULL, default_params); + + getCommitCallbackRegistrar().popScope(); + getEnableCallbackRegistrar().popScope(); + + setXMLFilename(filename); + + if (!getFactoryMap().empty()) + { + sFactoryStack.pop_back(); + } + } + LLUICtrlFactory::instance().popFileName(); + return didPost; } //----------------------------------------------------------------------------- @@ -856,20 +856,20 @@ BOOL LLPanel::buildFromFile(const std::string& filename, const LLPanel::Params& //----------------------------------------------------------------------------- LLPanel* LLPanel::createFactoryPanel(const std::string& name) { - std::deque<const LLCallbackMap::map_t*>::iterator itor; - for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor) - { - const LLCallbackMap::map_t* factory_map = *itor; - - // Look up this panel's name in the map. - LLCallbackMap::map_const_iter_t iter = factory_map->find( name ); - if (iter != factory_map->end()) - { - // Use the factory to create the panel, instead of using a default LLPanel. - LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData ); - return ret; - } - } - LLPanel::Params panel_p; - return LLUICtrlFactory::create<LLPanel>(panel_p); + std::deque<const LLCallbackMap::map_t*>::iterator itor; + for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor) + { + const LLCallbackMap::map_t* factory_map = *itor; + + // Look up this panel's name in the map. + LLCallbackMap::map_const_iter_t iter = factory_map->find( name ); + if (iter != factory_map->end()) + { + // Use the factory to create the panel, instead of using a default LLPanel. + LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData ); + return ret; + } + } + LLPanel::Params panel_p; + return LLUICtrlFactory::create<LLPanel>(panel_p); } diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 8018365d3e..365cac9fe6 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -1,4 +1,4 @@ -/** +/** * @file llpanel.h * @author James Cook, Tom Yedwab * @brief LLPanel base class @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -55,203 +55,203 @@ class LLUIImage; class LLPanel : public LLUICtrl, public LLBadgeHolder { public: - struct LocalizedString : public LLInitParam::Block<LocalizedString> - { - Mandatory<std::string> name; - Mandatory<std::string> value; - - LocalizedString(); - }; - - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> has_border; - Optional<LLViewBorder::Params> border; - - Optional<bool> background_visible, - background_opaque; - - Optional<LLUIColor> bg_opaque_color, - bg_alpha_color, - bg_opaque_image_overlay, - bg_alpha_image_overlay; - // opaque image is for "panel in foreground" look - Optional<LLUIImage*> bg_opaque_image, - bg_alpha_image; - - Optional<S32> min_width, - min_height; - - Optional<std::string> filename; - Optional<std::string> class_name; - Optional<std::string> help_topic; - - Multiple<LocalizedString> strings; - - Optional<CommitCallbackParam> visible_callback; - - Optional<bool> accepts_badge; - - Params(); - }; + struct LocalizedString : public LLInitParam::Block<LocalizedString> + { + Mandatory<std::string> name; + Mandatory<std::string> value; + + LocalizedString(); + }; + + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> has_border; + Optional<LLViewBorder::Params> border; + + Optional<bool> background_visible, + background_opaque; + + Optional<LLUIColor> bg_opaque_color, + bg_alpha_color, + bg_opaque_image_overlay, + bg_alpha_image_overlay; + // opaque image is for "panel in foreground" look + Optional<LLUIImage*> bg_opaque_image, + bg_alpha_image; + + Optional<S32> min_width, + min_height; + + Optional<std::string> filename; + Optional<std::string> class_name; + Optional<std::string> help_topic; + + Multiple<LocalizedString> strings; + + Optional<CommitCallbackParam> visible_callback; + + Optional<bool> accepts_badge; + + Params(); + }; protected: - friend class LLUICtrlFactory; - // RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8 - static const LLPanel::Params& getDefaultParams(); + friend class LLUICtrlFactory; + // RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8 + static const LLPanel::Params& getDefaultParams(); + + // Panels can get constructed directly + LLPanel(const LLPanel::Params& params = getDefaultParams()); - // Panels can get constructed directly - LLPanel(const LLPanel::Params& params = getDefaultParams()); - public: - typedef std::vector<class LLUICtrl *> ctrl_list_t; - - BOOL buildFromFile(const std::string &filename, const LLPanel::Params& default_params = getDefaultParams()); - - static LLPanel* createFactoryPanel(const std::string& name); - - /*virtual*/ ~LLPanel(); - - // LLView interface - /*virtual*/ BOOL isPanel() const; - /*virtual*/ void draw(); - /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); - /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); - - // From LLFocusableElement - /*virtual*/ void setFocus( BOOL b ); - - // New virtuals - virtual void refresh(); // called in setFocus() - virtual void clearCtrls(); // overridden in LLPanelObject and LLPanelVolume - - // Border controls - const LLViewBorder* getBorder() const { return mBorder; } - void addBorder( LLViewBorder::Params p); - void addBorder(); - void removeBorder(); - BOOL hasBorder() const { return mBorder != NULL; } - void setBorderVisible( BOOL b ); - - void setBackgroundColor( const LLColor4& color ) { mBgOpaqueColor = color; } - const LLColor4& getBackgroundColor() const { return mBgOpaqueColor; } - void setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; } - const LLColor4& getTransparentColor() const { return mBgAlphaColor; } - void setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; } - void setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; } - LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; } - LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; } - LLColor4 getBackgroundImageOverlay() { return mBgOpaqueImageOverlay; } - LLColor4 getTransparentImageOverlay() { return mBgAlphaImageOverlay; } - void setBackgroundVisible( BOOL b ) { mBgVisible = b; } - BOOL isBackgroundVisible() const { return mBgVisible; } - void setBackgroundOpaque(BOOL b) { mBgOpaque = b; } - BOOL isBackgroundOpaque() const { return mBgOpaque; } - void setDefaultBtn(LLButton* btn = NULL); - void setDefaultBtn(const std::string& id); - void updateDefaultBtn(); - void setLabel(const LLStringExplicit& label) { mLabel = label; } - std::string getLabel() const { return mLabel; } - void setHelpTopic(const std::string& help_topic) { mHelpTopic = help_topic; } - std::string getHelpTopic() const { return mHelpTopic; } - - void setCtrlsEnabled(BOOL b); - ctrl_list_t getCtrlList() const; - - LLHandle<LLPanel> getHandle() const { return getDerivedHandle<LLPanel>(); } - - const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } - - CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; } - EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; } - - void initFromParams(const Params& p); - BOOL initPanelXML( LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params); - - bool hasString(const std::string& name); - std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const; - std::string getString(const std::string& name) const; - - // ** Wrappers for setting child properties by name ** -TomY - // WARNING: These are deprecated, please use getChild<T>("name")->doStuff() idiom instead - - // LLView - void childSetVisible(const std::string& name, bool visible); - - void childSetEnabled(const std::string& name, bool enabled); - void childEnable(const std::string& name) { childSetEnabled(name, true); } - void childDisable(const std::string& name) { childSetEnabled(name, false); }; - - // LLUICtrl - void childSetFocus(const std::string& id, BOOL focus = TRUE); - BOOL childHasFocus(const std::string& id); - - // *TODO: Deprecate; for backwards compatability only: - // Prefer getChild<LLUICtrl>("foo")->setCommitCallback(boost:bind(...)), - // which takes a generic slot. Or use mCommitCallbackRegistrar.add() with - // a named callback and reference it in XML. - void childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data); - void childSetColor(const std::string& id, const LLColor4& color); - - LLCtrlSelectionInterface* childGetSelectionInterface(const std::string& id) const; - LLCtrlListInterface* childGetListInterface(const std::string& id) const; - LLCtrlScrollInterface* childGetScrollInterface(const std::string& id) const; - - // This is the magic bullet for data-driven UI - void childSetValue(const std::string& id, LLSD value); - LLSD childGetValue(const std::string& id) const; - - // For setting text / label replacement params, e.g. "Hello [NAME]" - // Not implemented for all types, defaults to noop, returns FALSE if not applicaple - BOOL childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text); - BOOL childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text); - - // LLButton - void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value); - void childSetAction(const std::string& id, const commit_signal_t::slot_type& function); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); - - //call onOpen to let panel know when it's about to be shown or activated - virtual void onOpen(const LLSD& key) {} - - void setXMLFilename(std::string filename) { mXMLFilename = filename; }; - std::string getXMLFilename() { return mXMLFilename; }; - - boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb ); + typedef std::vector<class LLUICtrl *> ctrl_list_t; + + BOOL buildFromFile(const std::string &filename, const LLPanel::Params& default_params = getDefaultParams()); + + static LLPanel* createFactoryPanel(const std::string& name); + + /*virtual*/ ~LLPanel(); + + // LLView interface + /*virtual*/ BOOL isPanel() const; + /*virtual*/ void draw(); + /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); + /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); + + // From LLFocusableElement + /*virtual*/ void setFocus( BOOL b ); + + // New virtuals + virtual void refresh(); // called in setFocus() + virtual void clearCtrls(); // overridden in LLPanelObject and LLPanelVolume + + // Border controls + const LLViewBorder* getBorder() const { return mBorder; } + void addBorder( LLViewBorder::Params p); + void addBorder(); + void removeBorder(); + BOOL hasBorder() const { return mBorder != NULL; } + void setBorderVisible( BOOL b ); + + void setBackgroundColor( const LLColor4& color ) { mBgOpaqueColor = color; } + const LLColor4& getBackgroundColor() const { return mBgOpaqueColor; } + void setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; } + const LLColor4& getTransparentColor() const { return mBgAlphaColor; } + void setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; } + void setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; } + LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; } + LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; } + LLColor4 getBackgroundImageOverlay() { return mBgOpaqueImageOverlay; } + LLColor4 getTransparentImageOverlay() { return mBgAlphaImageOverlay; } + void setBackgroundVisible( BOOL b ) { mBgVisible = b; } + BOOL isBackgroundVisible() const { return mBgVisible; } + void setBackgroundOpaque(BOOL b) { mBgOpaque = b; } + BOOL isBackgroundOpaque() const { return mBgOpaque; } + void setDefaultBtn(LLButton* btn = NULL); + void setDefaultBtn(const std::string& id); + void updateDefaultBtn(); + void setLabel(const LLStringExplicit& label) { mLabel = label; } + std::string getLabel() const { return mLabel; } + void setHelpTopic(const std::string& help_topic) { mHelpTopic = help_topic; } + std::string getHelpTopic() const { return mHelpTopic; } + + void setCtrlsEnabled(BOOL b); + ctrl_list_t getCtrlList() const; + + LLHandle<LLPanel> getHandle() const { return getDerivedHandle<LLPanel>(); } + + const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } + + CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; } + EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; } + + void initFromParams(const Params& p); + BOOL initPanelXML( LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params); + + bool hasString(const std::string& name); + std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const; + std::string getString(const std::string& name) const; + + // ** Wrappers for setting child properties by name ** -TomY + // WARNING: These are deprecated, please use getChild<T>("name")->doStuff() idiom instead + + // LLView + void childSetVisible(const std::string& name, bool visible); + + void childSetEnabled(const std::string& name, bool enabled); + void childEnable(const std::string& name) { childSetEnabled(name, true); } + void childDisable(const std::string& name) { childSetEnabled(name, false); }; + + // LLUICtrl + void childSetFocus(const std::string& id, BOOL focus = TRUE); + BOOL childHasFocus(const std::string& id); + + // *TODO: Deprecate; for backwards compatability only: + // Prefer getChild<LLUICtrl>("foo")->setCommitCallback(boost:bind(...)), + // which takes a generic slot. Or use mCommitCallbackRegistrar.add() with + // a named callback and reference it in XML. + void childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data); + void childSetColor(const std::string& id, const LLColor4& color); + + LLCtrlSelectionInterface* childGetSelectionInterface(const std::string& id) const; + LLCtrlListInterface* childGetListInterface(const std::string& id) const; + LLCtrlScrollInterface* childGetScrollInterface(const std::string& id) const; + + // This is the magic bullet for data-driven UI + void childSetValue(const std::string& id, LLSD value); + LLSD childGetValue(const std::string& id) const; + + // For setting text / label replacement params, e.g. "Hello [NAME]" + // Not implemented for all types, defaults to noop, returns FALSE if not applicaple + BOOL childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text); + BOOL childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text); + + // LLButton + void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value); + void childSetAction(const std::string& id, const commit_signal_t::slot_type& function); + + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); + + //call onOpen to let panel know when it's about to be shown or activated + virtual void onOpen(const LLSD& key) {} + + void setXMLFilename(std::string filename) { mXMLFilename = filename; }; + std::string getXMLFilename() { return mXMLFilename; }; + + boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb ); protected: - // Override to set not found list - LLButton* getDefaultButton() { return mDefaultBtn; } - LLCallbackMap::map_t mFactoryMap; - CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar; - EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar; + // Override to set not found list + LLButton* getDefaultButton() { return mDefaultBtn; } + LLCallbackMap::map_t mFactoryMap; + CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar; + EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar; - commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD() + commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD() - std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer - typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t; - static factory_stack_t sFactoryStack; + std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer + typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t; + static factory_stack_t sFactoryStack; + + // for setting the xml filename when building panel in context dependent cases + std::string mXMLFilename; - // for setting the xml filename when building panel in context dependent cases - std::string mXMLFilename; - private: - BOOL mBgVisible; // any background at all? - BOOL mBgOpaque; // use opaque color or image - LLUIColor mBgOpaqueColor; - LLUIColor mBgAlphaColor; - LLUIColor mBgOpaqueImageOverlay; - LLUIColor mBgAlphaImageOverlay; - LLPointer<LLUIImage> mBgOpaqueImage; // "panel in front" look - LLPointer<LLUIImage> mBgAlphaImage; // "panel in back" look - LLViewBorder* mBorder; - LLButton* mDefaultBtn; - LLUIString mLabel; - - typedef std::map<std::string, std::string> ui_string_map_t; - ui_string_map_t mUIStrings; + BOOL mBgVisible; // any background at all? + BOOL mBgOpaque; // use opaque color or image + LLUIColor mBgOpaqueColor; + LLUIColor mBgAlphaColor; + LLUIColor mBgOpaqueImageOverlay; + LLUIColor mBgAlphaImageOverlay; + LLPointer<LLUIImage> mBgOpaqueImage; // "panel in front" look + LLPointer<LLUIImage> mBgAlphaImage; // "panel in back" look + LLViewBorder* mBorder; + LLButton* mDefaultBtn; + LLUIString mLabel; + + typedef std::map<std::string, std::string> ui_string_map_t; + ui_string_map_t mUIStrings; }; // end class LLPanel @@ -259,7 +259,7 @@ private: // Build time optimization, generate once in .cpp file #ifndef LLPANEL_CPP extern template class LLPanel* LLView::getChild<class LLPanel>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc; @@ -267,51 +267,51 @@ typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc; // local static instance for registering a particular panel class class LLRegisterPanelClass -: public LLSingleton< LLRegisterPanelClass > +: public LLSingleton< LLRegisterPanelClass > { - LLSINGLETON_EMPTY_CTOR(LLRegisterPanelClass); + LLSINGLETON_EMPTY_CTOR(LLRegisterPanelClass); public: - // register with either the provided builder, or the generic templated builder - void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func) - { - mPanelClassesNames[tag] = func; - } - - LLPanel* createPanelClass(const std::string& tag) - { - param_name_map_t::iterator iT = mPanelClassesNames.find(tag); - if(iT == mPanelClassesNames.end()) - return 0; - return iT->second(); - } - template<typename T> - static T* defaultPanelClassBuilder() - { - T* pT = new T(); - return pT; - } + // register with either the provided builder, or the generic templated builder + void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func) + { + mPanelClassesNames[tag] = func; + } + + LLPanel* createPanelClass(const std::string& tag) + { + param_name_map_t::iterator iT = mPanelClassesNames.find(tag); + if(iT == mPanelClassesNames.end()) + return 0; + return iT->second(); + } + template<typename T> + static T* defaultPanelClassBuilder() + { + T* pT = new T(); + return pT; + } private: - typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t; - - param_name_map_t mPanelClassesNames; + typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t; + + param_name_map_t mPanelClassesNames; }; // local static instance for registering a particular panel class template<typename T> - class LLPanelInjector + class LLPanelInjector { public: - // register with either the provided builder, or the generic templated builder - LLPanelInjector(const std::string& tag); + // register with either the provided builder, or the generic templated builder + LLPanelInjector(const std::string& tag); }; template<typename T> - LLPanelInjector<T>::LLPanelInjector(const std::string& tag) + LLPanelInjector<T>::LLPanelInjector(const std::string& tag) { - LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>); + LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>); } diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp index cf57b1fe76..02cc1a5fcb 100644 --- a/indra/llui/llprogressbar.cpp +++ b/indra/llui/llprogressbar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprogressbar.cpp * @brief LLProgressBar class implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,32 +43,32 @@ static LLDefaultChildRegistry::Register<LLProgressBar> r("progress_bar"); LLProgressBar::Params::Params() -: image_bar("image_bar"), - image_fill("image_fill"), - color_bar("color_bar"), - color_bg("color_bg") +: image_bar("image_bar"), + image_fill("image_fill"), + color_bar("color_bar"), + color_bg("color_bg") {} -LLProgressBar::LLProgressBar(const LLProgressBar::Params& p) -: LLUICtrl(p), - mImageBar(p.image_bar), - mImageFill(p.image_fill), - mColorBackground(p.color_bg()), - mColorBar(p.color_bar()), - mPercentDone(0.f) +LLProgressBar::LLProgressBar(const LLProgressBar::Params& p) +: LLUICtrl(p), + mImageBar(p.image_bar), + mImageFill(p.image_fill), + mColorBackground(p.color_bg()), + mColorBar(p.color_bar()), + mPercentDone(0.f) {} LLProgressBar::~LLProgressBar() { - gFocusMgr.releaseFocusIfNeeded( this ); + gFocusMgr.releaseFocusIfNeeded( this ); } void LLProgressBar::draw() { - static LLTimer timer; - F32 alpha = getDrawContext().mAlpha; - + static LLTimer timer; + F32 alpha = getDrawContext().mAlpha; + if (mImageBar) // optional according to parameters { LLColor4 image_bar_color = mColorBackground.get(); @@ -89,5 +89,5 @@ void LLProgressBar::draw() void LLProgressBar::setValue(const LLSD& value) { - mPercentDone = llclamp((F32)value.asReal(), 0.f, 100.f); + mPercentDone = llclamp((F32)value.asReal(), 0.f, 100.f); } diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h index a8ec83ea00..0d5d32cf21 100644 --- a/indra/llui/llprogressbar.h +++ b/indra/llui/llprogressbar.h @@ -1,25 +1,25 @@ -/** +/** * @file llprogressbar.h * @brief LLProgressBar class definition * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,35 +32,35 @@ #include "lluiimage.h" class LLProgressBar - : public LLUICtrl + : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<LLUIImage*> image_bar, - image_fill; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLUIImage*> image_bar, + image_fill; - Optional<LLUIColor> color_bar, - color_bg; + Optional<LLUIColor> color_bar, + color_bg; - Params(); - }; - LLProgressBar(const Params&); - virtual ~LLProgressBar(); + Params(); + }; + LLProgressBar(const Params&); + virtual ~LLProgressBar(); - void setValue(const LLSD& value); + void setValue(const LLSD& value); - /*virtual*/ void draw(); + /*virtual*/ void draw(); private: - F32 mPercentDone; + F32 mPercentDone; + + LLPointer<LLUIImage> mImageBar; + LLUIColor mColorBar; - LLPointer<LLUIImage> mImageBar; - LLUIColor mColorBar; + LLUIColor mColorBackground; - LLUIColor mColorBackground; - - LLPointer<LLUIImage> mImageFill; + LLPointer<LLUIImage> mImageFill; }; #endif // LL_LLPROGRESSBAR_H diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index 2c7e7ab13d..ff53563a4c 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llradiogroup.cpp * @brief LLRadioGroup base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,75 +42,75 @@ static LLDefaultChildRegistry::Register<LLRadioGroup> r1("radio_group"); /* - * An invisible view containing multiple mutually exclusive toggling + * An invisible view containing multiple mutually exclusive toggling * buttons (usually radio buttons). Automatically handles the mutex * condition by highlighting only one button at a time. */ -class LLRadioCtrl : public LLCheckBoxCtrl +class LLRadioCtrl : public LLCheckBoxCtrl { public: - typedef LLRadioGroup::ItemParams Params; - /*virtual*/ ~LLRadioCtrl(); - /*virtual*/ void setValue(const LLSD& value); + typedef LLRadioGroup::ItemParams Params; + /*virtual*/ ~LLRadioCtrl(); + /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ BOOL postBuild(); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - LLSD getPayload() { return mPayload; } + LLSD getPayload() { return mPayload; } - // Ensure label is in an attribute, not the contents - static void setupParamsForExport(Params& p, LLView* parent); + // Ensure label is in an attribute, not the contents + static void setupParamsForExport(Params& p, LLView* parent); protected: - LLRadioCtrl(const LLRadioGroup::ItemParams& p); - friend class LLUICtrlFactory; + LLRadioCtrl(const LLRadioGroup::ItemParams& p); + friend class LLUICtrlFactory; - LLSD mPayload; // stores data that this item represents in the radio group + LLSD mPayload; // stores data that this item represents in the radio group }; static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item"); LLRadioGroup::Params::Params() -: allow_deselect("allow_deselect"), - items("item") +: allow_deselect("allow_deselect"), + items("item") { - addSynonym(items, "radio_item"); + addSynonym(items, "radio_item"); - // radio items are not tabbable until they are selected - tab_stop = false; + // radio items are not tabbable until they are selected + tab_stop = false; } LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p) -: LLUICtrl(p), - mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), - mSelectedIndex(-1), - mAllowDeselect(p.allow_deselect) +: LLUICtrl(p), + mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), + mSelectedIndex(-1), + mAllowDeselect(p.allow_deselect) {} void LLRadioGroup::initFromParams(const Params& p) { - for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); - it != p.items.end(); - ++it) - { - LLRadioGroup::ItemParams item_params(*it); - - if (!item_params.font.isProvided()) - { - item_params.font = mFont; // apply radio group font by default - } - item_params.commit_callback.function = boost::bind(&LLRadioGroup::onClickButton, this, _1); - item_params.from_xui = p.from_xui; - if (p.from_xui) - { - applyXUILayout(item_params, this); - } - - LLRadioCtrl* item = LLUICtrlFactory::create<LLRadioCtrl>(item_params, this); - mRadioButtons.push_back(item); - } - - // call this *after* setting up mRadioButtons so we can handle setValue() calls - LLUICtrl::initFromParams(p); + for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin(); + it != p.items.end(); + ++it) + { + LLRadioGroup::ItemParams item_params(*it); + + if (!item_params.font.isProvided()) + { + item_params.font = mFont; // apply radio group font by default + } + item_params.commit_callback.function = boost::bind(&LLRadioGroup::onClickButton, this, _1); + item_params.from_xui = p.from_xui; + if (p.from_xui) + { + applyXUILayout(item_params, this); + } + + LLRadioCtrl* item = LLUICtrlFactory::create<LLRadioCtrl>(item_params, this); + mRadioButtons.push_back(item); + } + + // call this *after* setting up mRadioButtons so we can handle setValue() calls + LLUICtrl::initFromParams(p); } @@ -121,64 +121,64 @@ LLRadioGroup::~LLRadioGroup() // virtual BOOL LLRadioGroup::postBuild() { - if (!mRadioButtons.empty()) - { - mRadioButtons[0]->setTabStop(true); - } - return TRUE; + if (!mRadioButtons.empty()) + { + mRadioButtons[0]->setTabStop(true); + } + return TRUE; } void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled) { - S32 count = 0; - for (button_list_t::iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - LLRadioCtrl* child = *iter; - if (count == index) - { - child->setEnabled(enabled); - if (index == mSelectedIndex && enabled == FALSE) - { - setSelectedIndex(-1); - } - break; - } - count++; - } - count = 0; - if (mSelectedIndex < 0) - { - // Set to highest enabled value < index, - // or lowest value above index if none lower are enabled - // or 0 if none are enabled - for (button_list_t::iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - LLRadioCtrl* child = *iter; - if (count >= index && mSelectedIndex >= 0) - { - break; - } - if (child->getEnabled()) - { - setSelectedIndex(count); - } - count++; - } - if (mSelectedIndex < 0) - { - setSelectedIndex(0); - } - } + S32 count = 0; + for (button_list_t::iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + LLRadioCtrl* child = *iter; + if (count == index) + { + child->setEnabled(enabled); + if (index == mSelectedIndex && enabled == FALSE) + { + setSelectedIndex(-1); + } + break; + } + count++; + } + count = 0; + if (mSelectedIndex < 0) + { + // Set to highest enabled value < index, + // or lowest value above index if none lower are enabled + // or 0 if none are enabled + for (button_list_t::iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + LLRadioCtrl* child = *iter; + if (count >= index && mSelectedIndex >= 0) + { + break; + } + if (child->getEnabled()) + { + setSelectedIndex(count); + } + count++; + } + if (mSelectedIndex < 0) + { + setSelectedIndex(0); + } + } } BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) { - if ((S32)mRadioButtons.size() <= index ) - { - return FALSE; - } + if ((S32)mRadioButtons.size() <= index ) + { + return FALSE; + } if (index < -1) { @@ -192,37 +192,37 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) return FALSE; } - if (mSelectedIndex >= 0) - { - LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex]; - old_radio_item->setTabStop(false); - old_radio_item->setValue( FALSE ); - } - else - { - mRadioButtons[0]->setTabStop(false); - } - - mSelectedIndex = index; - - if (mSelectedIndex >= 0) - { - LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex]; - radio_item->setTabStop(true); - radio_item->setValue( TRUE ); - - if (hasFocus()) - { - radio_item->focusFirstItem(FALSE, FALSE); - } - } - - if (!from_event) - { - setControlValue(getValue()); - } - - return TRUE; + if (mSelectedIndex >= 0) + { + LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex]; + old_radio_item->setTabStop(false); + old_radio_item->setValue( FALSE ); + } + else + { + mRadioButtons[0]->setTabStop(false); + } + + mSelectedIndex = index; + + if (mSelectedIndex >= 0) + { + LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex]; + radio_item->setTabStop(true); + radio_item->setValue( TRUE ); + + if (hasFocus()) + { + radio_item->focusFirstItem(FALSE, FALSE); + } + } + + if (!from_event) + { + setControlValue(getValue()); + } + + return TRUE; } void LLRadioGroup::focusSelectedRadioBtn() @@ -243,61 +243,61 @@ void LLRadioGroup::focusSelectedRadioBtn() BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask) { - BOOL handled = FALSE; - // do any of the tab buttons have keyboard focus? - if (mask == MASK_NONE) - { - switch(key) - { - case KEY_DOWN: - if (!setSelectedIndex((getSelectedIndex() + 1))) - { - make_ui_sound("UISndInvalidOp"); - } - else - { - onCommit(); - } - handled = TRUE; - break; - case KEY_UP: - if (!setSelectedIndex((getSelectedIndex() - 1))) - { - make_ui_sound("UISndInvalidOp"); - } - else - { - onCommit(); - } - handled = TRUE; - break; - case KEY_LEFT: - if (!setSelectedIndex((getSelectedIndex() - 1))) - { - make_ui_sound("UISndInvalidOp"); - } - else - { - onCommit(); - } - handled = TRUE; - break; - case KEY_RIGHT: - if (!setSelectedIndex((getSelectedIndex() + 1))) - { - make_ui_sound("UISndInvalidOp"); - } - else - { - onCommit(); - } - handled = TRUE; - break; - default: - break; - } - } - return handled; + BOOL handled = FALSE; + // do any of the tab buttons have keyboard focus? + if (mask == MASK_NONE) + { + switch(key) + { + case KEY_DOWN: + if (!setSelectedIndex((getSelectedIndex() + 1))) + { + make_ui_sound("UISndInvalidOp"); + } + else + { + onCommit(); + } + handled = TRUE; + break; + case KEY_UP: + if (!setSelectedIndex((getSelectedIndex() - 1))) + { + make_ui_sound("UISndInvalidOp"); + } + else + { + onCommit(); + } + handled = TRUE; + break; + case KEY_LEFT: + if (!setSelectedIndex((getSelectedIndex() - 1))) + { + make_ui_sound("UISndInvalidOp"); + } + else + { + onCommit(); + } + handled = TRUE; + break; + case KEY_RIGHT: + if (!setSelectedIndex((getSelectedIndex() + 1))) + { + make_ui_sound("UISndInvalidOp"); + } + else + { + onCommit(); + } + handled = TRUE; + break; + default: + break; + } + } + return handled; } // Handle one button being clicked. All child buttons must have this @@ -305,169 +305,169 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask) void LLRadioGroup::onClickButton(LLUICtrl* ctrl) { - // LL_INFOS() << "LLRadioGroup::onClickButton" << LL_ENDL; - LLRadioCtrl* clicked_radio = dynamic_cast<LLRadioCtrl*>(ctrl); - if (!clicked_radio) - return; - S32 index = 0; - for (button_list_t::iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - LLRadioCtrl* radio = *iter; - if (radio == clicked_radio) - { - if (index == mSelectedIndex && mAllowDeselect) - { - // don't select anything - setSelectedIndex(-1); - } - else - { - setSelectedIndex(index); - } - - // BUG: Calls click callback even if button didn't actually change - onCommit(); - - return; - } - - index++; - } - - LL_WARNS() << "LLRadioGroup::onClickButton - clicked button that isn't a child" << LL_ENDL; + // LL_INFOS() << "LLRadioGroup::onClickButton" << LL_ENDL; + LLRadioCtrl* clicked_radio = dynamic_cast<LLRadioCtrl*>(ctrl); + if (!clicked_radio) + return; + S32 index = 0; + for (button_list_t::iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + LLRadioCtrl* radio = *iter; + if (radio == clicked_radio) + { + if (index == mSelectedIndex && mAllowDeselect) + { + // don't select anything + setSelectedIndex(-1); + } + else + { + setSelectedIndex(index); + } + + // BUG: Calls click callback even if button didn't actually change + onCommit(); + + return; + } + + index++; + } + + LL_WARNS() << "LLRadioGroup::onClickButton - clicked button that isn't a child" << LL_ENDL; } void LLRadioGroup::setValue( const LLSD& value ) { - int idx = 0; - for (button_list_t::const_iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - LLRadioCtrl* radio = *iter; - if (radio->getPayload().asString() == value.asString()) - { - setSelectedIndex(idx); - idx = -1; - break; - } - ++idx; - } - if (idx != -1) - { - // string not found, try integer - if (value.isInteger()) - { - setSelectedIndex((S32) value.asInteger(), TRUE); - } - else - { - setSelectedIndex(-1, TRUE); - } - } + int idx = 0; + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + LLRadioCtrl* radio = *iter; + if (radio->getPayload().asString() == value.asString()) + { + setSelectedIndex(idx); + idx = -1; + break; + } + ++idx; + } + if (idx != -1) + { + // string not found, try integer + if (value.isInteger()) + { + setSelectedIndex((S32) value.asInteger(), TRUE); + } + else + { + setSelectedIndex(-1, TRUE); + } + } } LLSD LLRadioGroup::getValue() const { - int index = getSelectedIndex(); - int idx = 0; - for (button_list_t::const_iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - if (idx == index) return LLSD((*iter)->getPayload()); - ++idx; - } - return LLSD(); + int index = getSelectedIndex(); + int idx = 0; + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + if (idx == index) return LLSD((*iter)->getPayload()); + ++idx; + } + return LLSD(); } // LLCtrlSelectionInterface functions -BOOL LLRadioGroup::setCurrentByID( const LLUUID& id ) +BOOL LLRadioGroup::setCurrentByID( const LLUUID& id ) { - return FALSE; + return FALSE; } -LLUUID LLRadioGroup::getCurrentID() const +LLUUID LLRadioGroup::getCurrentID() const { - return LLUUID::null; + return LLUUID::null; } -BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected) +BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected) { - S32 idx = 0; - for (button_list_t::const_iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - if((*iter)->getPayload().asString() == value.asString()) - { - setSelectedIndex(idx); - return TRUE; - } - idx++; - } - - return FALSE; + S32 idx = 0; + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + if((*iter)->getPayload().asString() == value.asString()) + { + setSelectedIndex(idx); + return TRUE; + } + idx++; + } + + return FALSE; } -LLSD LLRadioGroup::getSelectedValue() +LLSD LLRadioGroup::getSelectedValue() { - return getValue(); + return getValue(); } -BOOL LLRadioGroup::isSelected(const LLSD& value) const +BOOL LLRadioGroup::isSelected(const LLSD& value) const { - S32 idx = 0; - for (button_list_t::const_iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) - { - if((*iter)->getPayload().asString() == value.asString()) - { - if (idx == mSelectedIndex) - { - return TRUE; - } - } - idx++; - } - return FALSE; + S32 idx = 0; + for (button_list_t::const_iterator iter = mRadioButtons.begin(); + iter != mRadioButtons.end(); ++iter) + { + if((*iter)->getPayload().asString() == value.asString()) + { + if (idx == mSelectedIndex) + { + return TRUE; + } + } + idx++; + } + return FALSE; } -BOOL LLRadioGroup::operateOnSelection(EOperation op) +BOOL LLRadioGroup::operateOnSelection(EOperation op) { - return FALSE; + return FALSE; } -BOOL LLRadioGroup::operateOnAll(EOperation op) +BOOL LLRadioGroup::operateOnAll(EOperation op) { - return FALSE; + return FALSE; } LLRadioGroup::ItemParams::ItemParams() -: value("value") +: value("value") { - addSynonym(value, "initial_value"); + addSynonym(value, "initial_value"); } LLRadioCtrl::LLRadioCtrl(const LLRadioGroup::ItemParams& p) -: LLCheckBoxCtrl(p), - mPayload(p.value) +: LLCheckBoxCtrl(p), + mPayload(p.value) { - // use name as default "Value" for backwards compatibility - if (!p.value.isProvided()) - { - mPayload = p.name(); - } + // use name as default "Value" for backwards compatibility + if (!p.value.isProvided()) + { + mPayload = p.name(); + } } BOOL LLRadioCtrl::postBuild() { - // Old-style radio_item used the text contents to indicate the label, - // but new-style radio_item uses label attribute. - std::string value = getValue().asString(); - if (!value.empty()) - { - setLabel(value); - } - return TRUE; + // Old-style radio_item used the text contents to indicate the label, + // but new-style radio_item uses label attribute. + std::string value = getValue().asString(); + if (!value.empty()) + { + setLabel(value); + } + return TRUE; } BOOL LLRadioCtrl::handleMouseDown(S32 x, S32 y, MASK mask) @@ -499,23 +499,23 @@ LLRadioCtrl::~LLRadioCtrl() void LLRadioCtrl::setValue(const LLSD& value) { - LLCheckBoxCtrl::setValue(value); - mButton->setTabStop(value.asBoolean()); + LLCheckBoxCtrl::setValue(value); + mButton->setTabStop(value.asBoolean()); } // *TODO: Remove this function after the initial XUI XML re-export pass. // static void LLRadioCtrl::setupParamsForExport(Params& p, LLView* parent) { - std::string label = p.label; - if (label.empty()) - { - // We don't have a label attribute, so move the text contents - // stored in "value" into the label - std::string initial_value = p.LLUICtrl::Params::initial_value(); - p.label = initial_value; - p.LLUICtrl::Params::initial_value = LLSD(); - } - - LLCheckBoxCtrl::setupParamsForExport(p, parent); + std::string label = p.label; + if (label.empty()) + { + // We don't have a label attribute, so move the text contents + // stored in "value" into the label + std::string initial_value = p.LLUICtrl::Params::initial_value(); + p.label = initial_value; + p.LLUICtrl::Params::initial_value = LLSD(); + } + + LLCheckBoxCtrl::setupParamsForExport(p, parent); } diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h index dcb2f43bfe..ca8883dce4 100644 --- a/indra/llui/llradiogroup.h +++ b/indra/llui/llradiogroup.h @@ -1,25 +1,25 @@ -/** +/** * @file llradiogroup.h * @brief LLRadioGroup base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,83 +32,83 @@ #include "llctrlselectioninterface.h" /* - * An invisible view containing multiple mutually exclusive toggling + * An invisible view containing multiple mutually exclusive toggling * buttons (usually radio buttons). Automatically handles the mutex * condition by highlighting only one button at a time. */ class LLRadioGroup -: public LLUICtrl, public LLCtrlSelectionInterface +: public LLUICtrl, public LLCtrlSelectionInterface { public: - struct ItemParams : public LLInitParam::Block<ItemParams, LLCheckBoxCtrl::Params> - { - Optional<LLSD> value; - ItemParams(); - }; + struct ItemParams : public LLInitParam::Block<ItemParams, LLCheckBoxCtrl::Params> + { + Optional<LLSD> value; + ItemParams(); + }; - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> allow_deselect; - Multiple<ItemParams, AtLeast<1> > items; - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> allow_deselect; + Multiple<ItemParams, AtLeast<1> > items; + Params(); + }; protected: - LLRadioGroup(const Params&); - friend class LLUICtrlFactory; + LLRadioGroup(const Params&); + friend class LLUICtrlFactory; public: - /*virtual*/ void initFromParams(const Params&); - - virtual ~LLRadioGroup(); - - virtual BOOL postBuild(); - - virtual BOOL handleKeyHere(KEY key, MASK mask); - - void setIndexEnabled(S32 index, BOOL enabled); - // return the index value of the selected item - S32 getSelectedIndex() const { return mSelectedIndex; } - // set the index value programatically - BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE); - // foxus child by index if it can get focus - void focusSelectedRadioBtn(); - - // Accept and retrieve strings of the radio group control names - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - - // Update the control as needed. Userdata must be a pointer to the button. - void onClickButton(LLUICtrl* clicked_radio); - - //======================================================================== - LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; - - // LLCtrlSelectionInterface functions - /*virtual*/ S32 getItemCount() const { return mRadioButtons.size(); } - /*virtual*/ BOOL getCanSelect() const { return TRUE; } - /*virtual*/ BOOL selectFirstItem() { return setSelectedIndex(0); } - /*virtual*/ BOOL selectNthItem( S32 index ) { return setSelectedIndex(index); } - /*virtual*/ BOOL selectItemRange( S32 first, S32 last ) { return setSelectedIndex(first); } - /*virtual*/ S32 getFirstSelectedIndex() const { return getSelectedIndex(); } - /*virtual*/ BOOL setCurrentByID( const LLUUID& id ); - /*virtual*/ LLUUID getCurrentID() const; // LLUUID::null if no items in menu - /*virtual*/ BOOL setSelectedByValue(const LLSD& value, BOOL selected); - /*virtual*/ LLSD getSelectedValue(); - /*virtual*/ BOOL isSelected(const LLSD& value) const; - /*virtual*/ BOOL operateOnSelection(EOperation op); - /*virtual*/ BOOL operateOnAll(EOperation op); + /*virtual*/ void initFromParams(const Params&); + + virtual ~LLRadioGroup(); + + virtual BOOL postBuild(); + + virtual BOOL handleKeyHere(KEY key, MASK mask); + + void setIndexEnabled(S32 index, BOOL enabled); + // return the index value of the selected item + S32 getSelectedIndex() const { return mSelectedIndex; } + // set the index value programatically + BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE); + // foxus child by index if it can get focus + void focusSelectedRadioBtn(); + + // Accept and retrieve strings of the radio group control names + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const; + + // Update the control as needed. Userdata must be a pointer to the button. + void onClickButton(LLUICtrl* clicked_radio); + + //======================================================================== + LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; + + // LLCtrlSelectionInterface functions + /*virtual*/ S32 getItemCount() const { return mRadioButtons.size(); } + /*virtual*/ BOOL getCanSelect() const { return TRUE; } + /*virtual*/ BOOL selectFirstItem() { return setSelectedIndex(0); } + /*virtual*/ BOOL selectNthItem( S32 index ) { return setSelectedIndex(index); } + /*virtual*/ BOOL selectItemRange( S32 first, S32 last ) { return setSelectedIndex(first); } + /*virtual*/ S32 getFirstSelectedIndex() const { return getSelectedIndex(); } + /*virtual*/ BOOL setCurrentByID( const LLUUID& id ); + /*virtual*/ LLUUID getCurrentID() const; // LLUUID::null if no items in menu + /*virtual*/ BOOL setSelectedByValue(const LLSD& value, BOOL selected); + /*virtual*/ LLSD getSelectedValue(); + /*virtual*/ BOOL isSelected(const LLSD& value) const; + /*virtual*/ BOOL operateOnSelection(EOperation op); + /*virtual*/ BOOL operateOnAll(EOperation op); private: - const LLFontGL* mFont; - S32 mSelectedIndex; + const LLFontGL* mFont; + S32 mSelectedIndex; - typedef std::vector<class LLRadioCtrl*> button_list_t; - button_list_t mRadioButtons; + typedef std::vector<class LLRadioCtrl*> button_list_t; + button_list_t mRadioButtons; - bool mAllowDeselect; // user can click on an already selected option to deselect it + bool mAllowDeselect; // user can click on an already selected option to deselect it }; #endif diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp index 115c4e23be..cec0734735 100644 --- a/indra/llui/llresizebar.cpp +++ b/indra/llui/llresizebar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llresizebar.cpp * @brief LLResizeBar base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,341 +36,341 @@ #include "llwindow.h" LLResizeBar::Params::Params() -: max_size("max_size", S32_MAX), - snapping_enabled("snapping_enabled", true), - resizing_view("resizing_view"), - side("side"), - allow_double_click_snapping("allow_double_click_snapping", true) +: max_size("max_size", S32_MAX), + snapping_enabled("snapping_enabled", true), + resizing_view("resizing_view"), + side("side"), + allow_double_click_snapping("allow_double_click_snapping", true) { - name = "resize_bar"; + name = "resize_bar"; } LLResizeBar::LLResizeBar(const LLResizeBar::Params& p) -: LLView(p), - mDragLastScreenX( 0 ), - mDragLastScreenY( 0 ), - mLastMouseScreenX( 0 ), - mLastMouseScreenY( 0 ), - mMinSize( p.min_size ), - mMaxSize( p.max_size ), - mSide( p.side ), - mSnappingEnabled(p.snapping_enabled), - mAllowDoubleClickSnapping(p.allow_double_click_snapping), - mResizingView(p.resizing_view), - mResizeListener(NULL), - mImagePanel(NULL) +: LLView(p), + mDragLastScreenX( 0 ), + mDragLastScreenY( 0 ), + mLastMouseScreenX( 0 ), + mLastMouseScreenY( 0 ), + mMinSize( p.min_size ), + mMaxSize( p.max_size ), + mSide( p.side ), + mSnappingEnabled(p.snapping_enabled), + mAllowDoubleClickSnapping(p.allow_double_click_snapping), + mResizingView(p.resizing_view), + mResizeListener(NULL), + mImagePanel(NULL) { - setFollowsNone(); - // set up some generically good follow code. - switch( mSide ) - { - case LEFT: - setFollowsLeft(); - setFollowsTop(); - setFollowsBottom(); - break; - case TOP: - setFollowsTop(); - setFollowsLeft(); - setFollowsRight(); - break; - case RIGHT: - setFollowsRight(); - setFollowsTop(); - setFollowsBottom(); - break; - case BOTTOM: - setFollowsBottom(); - setFollowsLeft(); - setFollowsRight(); - break; - default: - break; - } + setFollowsNone(); + // set up some generically good follow code. + switch( mSide ) + { + case LEFT: + setFollowsLeft(); + setFollowsTop(); + setFollowsBottom(); + break; + case TOP: + setFollowsTop(); + setFollowsLeft(); + setFollowsRight(); + break; + case RIGHT: + setFollowsRight(); + setFollowsTop(); + setFollowsBottom(); + break; + case BOTTOM: + setFollowsBottom(); + setFollowsLeft(); + setFollowsRight(); + break; + default: + break; + } } BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask) { - if (!canResize()) return FALSE; + if (!canResize()) return FALSE; - // Route future Mouse messages here preemptively. (Release on mouse up.) - // No handler needed for focus lost since this clas has no state that depends on it. - gFocusMgr.setMouseCapture( this ); + // Route future Mouse messages here preemptively. (Release on mouse up.) + // No handler needed for focus lost since this clas has no state that depends on it. + gFocusMgr.setMouseCapture( this ); - localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); - mLastMouseScreenX = mDragLastScreenX; - mLastMouseScreenY = mDragLastScreenY; + localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); + mLastMouseScreenX = mDragLastScreenX; + mLastMouseScreenY = mDragLastScreenY; - return TRUE; + return TRUE; } BOOL LLResizeBar::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if( hasMouseCapture() ) - { - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - handled = TRUE; - } - else - { - handled = TRUE; - } - return handled; + BOOL handled = FALSE; + + if( hasMouseCapture() ) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + handled = TRUE; + } + else + { + handled = TRUE; + } + return handled; } BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // We only handle the click if the click both started and ended within us - if( hasMouseCapture() ) - { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - S32 delta_x = screen_x - mDragLastScreenX; - S32 delta_y = screen_y - mDragLastScreenY; - - LLCoordGL mouse_dir; - // use hysteresis on mouse motion to preserve user intent when mouse stops moving - mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; - mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; - mLastMouseDir = mouse_dir; - mLastMouseScreenX = screen_x; - mLastMouseScreenY = screen_y; - - // Make sure the mouse in still over the application. We don't want to make the parent - // so big that we can't see the resize handle any more. - LLRect valid_rect = getRootView()->getRect(); - - if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView ) - { - // Resize the parent - LLRect orig_rect = mResizingView->getRect(); - LLRect scaled_rect = orig_rect; - - S32 new_width = orig_rect.getWidth(); - S32 new_height = orig_rect.getHeight(); - - switch( mSide ) - { - case LEFT: - new_width = llclamp(orig_rect.getWidth() - delta_x, mMinSize, mMaxSize); - delta_x = orig_rect.getWidth() - new_width; - scaled_rect.translate(delta_x, 0); - break; - - case TOP: - new_height = llclamp(orig_rect.getHeight() + delta_y, mMinSize, mMaxSize); - delta_y = new_height - orig_rect.getHeight(); - break; - - case RIGHT: - new_width = llclamp(orig_rect.getWidth() + delta_x, mMinSize, mMaxSize); - delta_x = new_width - orig_rect.getWidth(); - break; - - case BOTTOM: - new_height = llclamp(orig_rect.getHeight() - delta_y, mMinSize, mMaxSize); - delta_y = orig_rect.getHeight() - new_height; - scaled_rect.translate(0, delta_y); - break; - } - - notifyParent(LLSD().with("action", "resize") - .with("view_name", mResizingView->getName()) - .with("new_height", new_height) - .with("new_width", new_width)); - - scaled_rect.mTop = scaled_rect.mBottom + new_height; - scaled_rect.mRight = scaled_rect.mLeft + new_width; - mResizingView->setRect(scaled_rect); - - LLView* snap_view = NULL; - - if (mSnappingEnabled) - { - static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); - switch( mSide ) - { - case LEFT: - snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - break; - case TOP: - snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); - break; - case RIGHT: - snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - break; - case BOTTOM: - snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); - break; - } - } - - // register "snap" behavior with snapped view - mResizingView->setSnappedTo(snap_view); - - // restore original rectangle so the appropriate changes are detected - mResizingView->setRect(orig_rect); - // change view shape as user operation - mResizingView->setShape(scaled_rect, true); - - // update last valid mouse cursor position based on resized view's actual size - LLRect new_rect = mResizingView->getRect(); - - switch(mSide) - { - case LEFT: - { - S32 actual_delta_x = new_rect.mLeft - orig_rect.mLeft; - if (actual_delta_x != delta_x) - { - // restore everything by left - new_rect.mBottom = orig_rect.mBottom; - new_rect.mTop = orig_rect.mTop; - new_rect.mRight = orig_rect.mRight; - mResizingView->setShape(new_rect, true); - } - mDragLastScreenX += actual_delta_x; - - break; - } - case RIGHT: - { - S32 actual_delta_x = new_rect.mRight - orig_rect.mRight; - if (actual_delta_x != delta_x) - { - // restore everything by left - new_rect.mBottom = orig_rect.mBottom; - new_rect.mTop = orig_rect.mTop; - new_rect.mLeft = orig_rect.mLeft; - mResizingView->setShape(new_rect, true); - } - mDragLastScreenX += new_rect.mRight - orig_rect.mRight; - break; - } - case TOP: - { - S32 actual_delta_y = new_rect.mTop - orig_rect.mTop; - if (actual_delta_y != delta_y) - { - // restore everything by left - new_rect.mBottom = orig_rect.mBottom; - new_rect.mLeft = orig_rect.mLeft; - new_rect.mRight = orig_rect.mRight; - mResizingView->setShape(new_rect, true); - } - mDragLastScreenY += new_rect.mTop - orig_rect.mTop; - break; - } - case BOTTOM: - { - S32 actual_delta_y = new_rect.mBottom - orig_rect.mBottom; - if (actual_delta_y != delta_y) - { - // restore everything by left - new_rect.mTop = orig_rect.mTop; - new_rect.mLeft = orig_rect.mLeft; - new_rect.mRight = orig_rect.mRight; - mResizingView->setShape(new_rect, true); - } - mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom; - break; - } - default: - break; - } - } - - handled = TRUE; - } - else - { - handled = TRUE; - } - - if( handled && canResize() ) - { - switch( mSide ) - { - case LEFT: - case RIGHT: - getWindow()->setCursor(UI_CURSOR_SIZEWE); - break; - - case TOP: - case BOTTOM: - getWindow()->setCursor(UI_CURSOR_SIZENS); - break; - } - } - - if (mResizeListener) - { - mResizeListener(NULL); - } - - return handled; + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + S32 delta_x = screen_x - mDragLastScreenX; + S32 delta_y = screen_y - mDragLastScreenY; + + LLCoordGL mouse_dir; + // use hysteresis on mouse motion to preserve user intent when mouse stops moving + mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; + mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; + mLastMouseDir = mouse_dir; + mLastMouseScreenX = screen_x; + mLastMouseScreenY = screen_y; + + // Make sure the mouse in still over the application. We don't want to make the parent + // so big that we can't see the resize handle any more. + LLRect valid_rect = getRootView()->getRect(); + + if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView ) + { + // Resize the parent + LLRect orig_rect = mResizingView->getRect(); + LLRect scaled_rect = orig_rect; + + S32 new_width = orig_rect.getWidth(); + S32 new_height = orig_rect.getHeight(); + + switch( mSide ) + { + case LEFT: + new_width = llclamp(orig_rect.getWidth() - delta_x, mMinSize, mMaxSize); + delta_x = orig_rect.getWidth() - new_width; + scaled_rect.translate(delta_x, 0); + break; + + case TOP: + new_height = llclamp(orig_rect.getHeight() + delta_y, mMinSize, mMaxSize); + delta_y = new_height - orig_rect.getHeight(); + break; + + case RIGHT: + new_width = llclamp(orig_rect.getWidth() + delta_x, mMinSize, mMaxSize); + delta_x = new_width - orig_rect.getWidth(); + break; + + case BOTTOM: + new_height = llclamp(orig_rect.getHeight() - delta_y, mMinSize, mMaxSize); + delta_y = orig_rect.getHeight() - new_height; + scaled_rect.translate(0, delta_y); + break; + } + + notifyParent(LLSD().with("action", "resize") + .with("view_name", mResizingView->getName()) + .with("new_height", new_height) + .with("new_width", new_width)); + + scaled_rect.mTop = scaled_rect.mBottom + new_height; + scaled_rect.mRight = scaled_rect.mLeft + new_width; + mResizingView->setRect(scaled_rect); + + LLView* snap_view = NULL; + + if (mSnappingEnabled) + { + static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); + switch( mSide ) + { + case LEFT: + snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + break; + case TOP: + snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); + break; + case RIGHT: + snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + break; + case BOTTOM: + snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); + break; + } + } + + // register "snap" behavior with snapped view + mResizingView->setSnappedTo(snap_view); + + // restore original rectangle so the appropriate changes are detected + mResizingView->setRect(orig_rect); + // change view shape as user operation + mResizingView->setShape(scaled_rect, true); + + // update last valid mouse cursor position based on resized view's actual size + LLRect new_rect = mResizingView->getRect(); + + switch(mSide) + { + case LEFT: + { + S32 actual_delta_x = new_rect.mLeft - orig_rect.mLeft; + if (actual_delta_x != delta_x) + { + // restore everything by left + new_rect.mBottom = orig_rect.mBottom; + new_rect.mTop = orig_rect.mTop; + new_rect.mRight = orig_rect.mRight; + mResizingView->setShape(new_rect, true); + } + mDragLastScreenX += actual_delta_x; + + break; + } + case RIGHT: + { + S32 actual_delta_x = new_rect.mRight - orig_rect.mRight; + if (actual_delta_x != delta_x) + { + // restore everything by left + new_rect.mBottom = orig_rect.mBottom; + new_rect.mTop = orig_rect.mTop; + new_rect.mLeft = orig_rect.mLeft; + mResizingView->setShape(new_rect, true); + } + mDragLastScreenX += new_rect.mRight - orig_rect.mRight; + break; + } + case TOP: + { + S32 actual_delta_y = new_rect.mTop - orig_rect.mTop; + if (actual_delta_y != delta_y) + { + // restore everything by left + new_rect.mBottom = orig_rect.mBottom; + new_rect.mLeft = orig_rect.mLeft; + new_rect.mRight = orig_rect.mRight; + mResizingView->setShape(new_rect, true); + } + mDragLastScreenY += new_rect.mTop - orig_rect.mTop; + break; + } + case BOTTOM: + { + S32 actual_delta_y = new_rect.mBottom - orig_rect.mBottom; + if (actual_delta_y != delta_y) + { + // restore everything by left + new_rect.mTop = orig_rect.mTop; + new_rect.mLeft = orig_rect.mLeft; + new_rect.mRight = orig_rect.mRight; + mResizingView->setShape(new_rect, true); + } + mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom; + break; + } + default: + break; + } + } + + handled = TRUE; + } + else + { + handled = TRUE; + } + + if( handled && canResize() ) + { + switch( mSide ) + { + case LEFT: + case RIGHT: + getWindow()->setCursor(UI_CURSOR_SIZEWE); + break; + + case TOP: + case BOTTOM: + getWindow()->setCursor(UI_CURSOR_SIZENS); + break; + } + } + + if (mResizeListener) + { + mResizeListener(NULL); + } + + return handled; } // end LLResizeBar::handleHover BOOL LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask) { - LLRect orig_rect = mResizingView->getRect(); - LLRect scaled_rect = orig_rect; - - if (mSnappingEnabled && mAllowDoubleClickSnapping) - { - switch( mSide ) - { - case LEFT: - mResizingView->findSnapEdge(scaled_rect.mLeft, LLCoordGL(0, 0), SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, S32_MAX); - scaled_rect.mLeft = scaled_rect.mRight - llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize); - break; - case TOP: - mResizingView->findSnapEdge(scaled_rect.mTop, LLCoordGL(0, 0), SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, S32_MAX); - scaled_rect.mTop = scaled_rect.mBottom + llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize); - break; - case RIGHT: - mResizingView->findSnapEdge(scaled_rect.mRight, LLCoordGL(0, 0), SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, S32_MAX); - scaled_rect.mRight = scaled_rect.mLeft + llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize); - break; - case BOTTOM: - mResizingView->findSnapEdge(scaled_rect.mBottom, LLCoordGL(0, 0), SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, S32_MAX); - scaled_rect.mBottom = scaled_rect.mTop - llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize); - break; - } - - mResizingView->setShape(scaled_rect, true); - } - - return TRUE; + LLRect orig_rect = mResizingView->getRect(); + LLRect scaled_rect = orig_rect; + + if (mSnappingEnabled && mAllowDoubleClickSnapping) + { + switch( mSide ) + { + case LEFT: + mResizingView->findSnapEdge(scaled_rect.mLeft, LLCoordGL(0, 0), SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, S32_MAX); + scaled_rect.mLeft = scaled_rect.mRight - llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize); + break; + case TOP: + mResizingView->findSnapEdge(scaled_rect.mTop, LLCoordGL(0, 0), SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, S32_MAX); + scaled_rect.mTop = scaled_rect.mBottom + llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize); + break; + case RIGHT: + mResizingView->findSnapEdge(scaled_rect.mRight, LLCoordGL(0, 0), SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, S32_MAX); + scaled_rect.mRight = scaled_rect.mLeft + llclamp(scaled_rect.getWidth(), mMinSize, mMaxSize); + break; + case BOTTOM: + mResizingView->findSnapEdge(scaled_rect.mBottom, LLCoordGL(0, 0), SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, S32_MAX); + scaled_rect.mBottom = scaled_rect.mTop - llclamp(scaled_rect.getHeight(), mMinSize, mMaxSize); + break; + } + + mResizingView->setShape(scaled_rect, true); + } + + return TRUE; } void LLResizeBar::setImagePanel(LLPanel * panelp) { - const LLView::child_list_t * children = getChildList(); - if (getChildCount() == 2) - { - LLPanel * image_panelp = dynamic_cast<LLPanel*>(children->back()); - if (image_panelp) - { - removeChild(image_panelp); - delete image_panelp; - } - } - - addChild(panelp); - sendChildToBack(panelp); + const LLView::child_list_t * children = getChildList(); + if (getChildCount() == 2) + { + LLPanel * image_panelp = dynamic_cast<LLPanel*>(children->back()); + if (image_panelp) + { + removeChild(image_panelp); + delete image_panelp; + } + } + + addChild(panelp); + sendChildToBack(panelp); } LLPanel * LLResizeBar::getImagePanel() const { - return getChildCount() > 0 ? (LLPanel *)getChildList()->back() : NULL; + return getChildCount() > 0 ? (LLPanel *)getChildList()->back() : NULL; } diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 20a2406484..0fcecd1dbe 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -1,25 +1,25 @@ -/** +/** * @file llresizebar.h * @brief LLResizeBar base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,55 +32,55 @@ class LLResizeBar : public LLView { public: - enum Side { LEFT, TOP, RIGHT, BOTTOM }; + enum Side { LEFT, TOP, RIGHT, BOTTOM }; - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Mandatory<LLView*> resizing_view; - Mandatory<Side> side; + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Mandatory<LLView*> resizing_view; + Mandatory<Side> side; - Optional<S32> min_size; - Optional<S32> max_size; - Optional<bool> snapping_enabled; - Optional<bool> allow_double_click_snapping; + Optional<S32> min_size; + Optional<S32> max_size; + Optional<bool> snapping_enabled; + Optional<bool> allow_double_click_snapping; - Params(); - }; + Params(); + }; protected: - LLResizeBar(const LLResizeBar::Params& p); - friend class LLUICtrlFactory; + LLResizeBar(const LLResizeBar::Params& p); + friend class LLUICtrlFactory; public: - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; } - void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; } - void setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; } - bool canResize() { return getEnabled() && mMaxSize > mMinSize; } - void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;} - void setImagePanel(LLPanel * panelp); - LLPanel * getImagePanel() const; + void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; } + void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; } + void setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; } + bool canResize() { return getEnabled() && mMaxSize > mMinSize; } + void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;} + void setImagePanel(LLPanel * panelp); + LLPanel * getImagePanel() const; private: - S32 mDragLastScreenX; - S32 mDragLastScreenY; - S32 mLastMouseScreenX; - S32 mLastMouseScreenY; - LLCoordGL mLastMouseDir; - S32 mMinSize; - S32 mMaxSize; - const Side mSide; - bool mSnappingEnabled, - mAllowDoubleClickSnapping; - LLView* mResizingView; - boost::function<void(void*)> mResizeListener; - LLPointer<LLUIImage> mDragHandleImage; - LLPanel * mImagePanel; + S32 mDragLastScreenX; + S32 mDragLastScreenY; + S32 mLastMouseScreenX; + S32 mLastMouseScreenY; + LLCoordGL mLastMouseDir; + S32 mMinSize; + S32 mMaxSize; + const Side mSide; + bool mSnappingEnabled, + mAllowDoubleClickSnapping; + LLView* mResizingView; + boost::function<void(void*)> mResizeListener; + LLPointer<LLUIImage> mDragHandleImage; + LLPanel * mImagePanel; }; #endif // LL_RESIZEBAR_H diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp index 13ef0fdb7f..29ae13b7ff 100644 --- a/indra/llui/llresizehandle.cpp +++ b/indra/llui/llresizehandle.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llresizehandle.cpp * @brief LLResizeHandle base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,35 +39,35 @@ const S32 RESIZE_BORDER_WIDTH = 3; LLResizeHandle::Params::Params() -: corner("corner"), - min_width("min_width"), - min_height("min_height") +: corner("corner"), + min_width("min_width"), + min_height("min_height") { - name = "resize_handle"; + name = "resize_handle"; } LLResizeHandle::LLResizeHandle(const LLResizeHandle::Params& p) -: LLView(p), - mDragLastScreenX( 0 ), - mDragLastScreenY( 0 ), - mLastMouseScreenX( 0 ), - mLastMouseScreenY( 0 ), - mImage( NULL ), - mMinWidth( p.min_width ), - mMinHeight( p.min_height ), - mCorner( p.corner ) +: LLView(p), + mDragLastScreenX( 0 ), + mDragLastScreenY( 0 ), + mLastMouseScreenX( 0 ), + mLastMouseScreenY( 0 ), + mImage( NULL ), + mMinWidth( p.min_width ), + mMinHeight( p.min_height ), + mCorner( p.corner ) { - if( RIGHT_BOTTOM == mCorner) - { - mImage = LLUI::getUIImage("Resize_Corner"); - } - switch( p.corner ) - { - case LEFT_TOP: setFollows( FOLLOWS_LEFT | FOLLOWS_TOP ); break; - case LEFT_BOTTOM: setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM ); break; - case RIGHT_TOP: setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP ); break; - case RIGHT_BOTTOM: setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); break; - } + if( RIGHT_BOTTOM == mCorner) + { + mImage = LLUI::getUIImage("Resize_Corner"); + } + switch( p.corner ) + { + case LEFT_TOP: setFollows( FOLLOWS_LEFT | FOLLOWS_TOP ); break; + case LEFT_BOTTOM: setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM ); break; + case RIGHT_TOP: setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP ); break; + case RIGHT_BOTTOM: setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); break; + } } LLResizeHandle::~LLResizeHandle() @@ -78,308 +78,308 @@ LLResizeHandle::~LLResizeHandle() BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - if( pointInHandle(x, y) ) - { - handled = TRUE; - // Route future Mouse messages here preemptively. (Release on mouse up.) - // No handler needed for focus lost since this clas has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - - localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); - mLastMouseScreenX = mDragLastScreenX; - mLastMouseScreenY = mDragLastScreenY; - } - - return handled; + BOOL handled = FALSE; + if( pointInHandle(x, y) ) + { + handled = TRUE; + // Route future Mouse messages here preemptively. (Release on mouse up.) + // No handler needed for focus lost since this clas has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + + localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY); + mLastMouseScreenX = mDragLastScreenX; + mLastMouseScreenY = mDragLastScreenY; + } + + return handled; } BOOL LLResizeHandle::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if( hasMouseCapture() ) - { - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - handled = TRUE; - } - else if( pointInHandle(x, y) ) - { - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if( hasMouseCapture() ) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + handled = TRUE; + } + else if( pointInHandle(x, y) ) + { + handled = TRUE; + } + + return handled; } BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // We only handle the click if the click both started and ended within us - if( hasMouseCapture() ) - { - // Make sure the mouse in still over the application. We don't want to make the parent - // so big that we can't see the resize handle any more. - - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - const LLRect valid_rect = getRootView()->getRect(); - screen_x = llclamp( screen_x, valid_rect.mLeft, valid_rect.mRight ); - screen_y = llclamp( screen_y, valid_rect.mBottom, valid_rect.mTop ); - - LLView* resizing_view = getParent(); - if( resizing_view ) - { - // undock floater when user resize it - LLFloater* floater_parent = dynamic_cast<LLFloater*>(getParent()); - if (floater_parent && floater_parent->isDocked()) - { - floater_parent->setDocked(false, false); - } - - // Resize the parent - LLRect orig_rect = resizing_view->getRect(); - LLRect scaled_rect = orig_rect; - S32 delta_x = screen_x - mDragLastScreenX; - S32 delta_y = screen_y - mDragLastScreenY; - LLCoordGL mouse_dir; - // use hysteresis on mouse motion to preserve user intent when mouse stops moving - mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; - mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; - mLastMouseScreenX = screen_x; - mLastMouseScreenY = screen_y; - mLastMouseDir = mouse_dir; - - S32 x_multiple = 1; - S32 y_multiple = 1; - switch( mCorner ) - { - case LEFT_TOP: - x_multiple = -1; - y_multiple = 1; - break; - case LEFT_BOTTOM: - x_multiple = -1; - y_multiple = -1; - break; - case RIGHT_TOP: - x_multiple = 1; - y_multiple = 1; - break; - case RIGHT_BOTTOM: - x_multiple = 1; - y_multiple = -1; - break; - } - - S32 new_width = orig_rect.getWidth() + x_multiple * delta_x; - if( new_width < mMinWidth ) - { - new_width = mMinWidth; - delta_x = x_multiple * (mMinWidth - orig_rect.getWidth()); - } - - S32 new_height = orig_rect.getHeight() + y_multiple * delta_y; - if( new_height < mMinHeight ) - { - new_height = mMinHeight; - delta_y = y_multiple * (mMinHeight - orig_rect.getHeight()); - } - - switch( mCorner ) - { - case LEFT_TOP: - scaled_rect.translate(delta_x, 0); - break; - case LEFT_BOTTOM: - scaled_rect.translate(delta_x, delta_y); - break; - case RIGHT_TOP: - break; - case RIGHT_BOTTOM: - scaled_rect.translate(0, delta_y); - break; - } - - // temporarily set new parent rect - scaled_rect.mRight = scaled_rect.mLeft + new_width; - scaled_rect.mTop = scaled_rect.mBottom + new_height; - resizing_view->setRect(scaled_rect); - - LLView* snap_view = NULL; - LLView* test_view = NULL; - - static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); - // now do snapping - switch(mCorner) - { - case LEFT_TOP: - snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); - if (!snap_view) - { - snap_view = test_view; - } - break; - case LEFT_BOTTOM: - snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); - if (!snap_view) - { - snap_view = test_view; - } - break; - case RIGHT_TOP: - snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); - if (!snap_view) - { - snap_view = test_view; - } - break; - case RIGHT_BOTTOM: - snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); - test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); - if (!snap_view) - { - snap_view = test_view; - } - break; - } - - // register "snap" behavior with snapped view - resizing_view->setSnappedTo(snap_view); - - // reset parent rect - resizing_view->setRect(orig_rect); - - // translate and scale to new shape - resizing_view->setShape(scaled_rect, true); - - // update last valid mouse cursor position based on resized view's actual size - LLRect new_rect = resizing_view->getRect(); - S32 actual_delta_x = 0; - S32 actual_delta_y = 0; - switch(mCorner) - { - case LEFT_TOP: - actual_delta_x = new_rect.mLeft - orig_rect.mLeft; - actual_delta_y = new_rect.mTop - orig_rect.mTop; - if (actual_delta_x != delta_x - || actual_delta_y != delta_y) - { - new_rect.mRight = orig_rect.mRight; - new_rect.mBottom = orig_rect.mBottom; - resizing_view->setShape(new_rect, true); - } - - mDragLastScreenX += actual_delta_x; - mDragLastScreenY += actual_delta_y; - break; - case LEFT_BOTTOM: - actual_delta_x = new_rect.mLeft - orig_rect.mLeft; - actual_delta_y = new_rect.mBottom - orig_rect.mBottom; - if (actual_delta_x != delta_x - || actual_delta_y != delta_y) - { - new_rect.mRight = orig_rect.mRight; - new_rect.mTop = orig_rect.mTop; - resizing_view->setShape(new_rect, true); - } - - mDragLastScreenX += actual_delta_x; - mDragLastScreenY += actual_delta_y; - break; - case RIGHT_TOP: - actual_delta_x = new_rect.mRight - orig_rect.mRight; - actual_delta_y = new_rect.mTop - orig_rect.mTop; - if (actual_delta_x != delta_x - || actual_delta_y != delta_y) - { - new_rect.mLeft = orig_rect.mLeft; - new_rect.mBottom = orig_rect.mBottom; - resizing_view->setShape(new_rect, true); - } - - mDragLastScreenX += actual_delta_x; - mDragLastScreenY += actual_delta_y; - break; - case RIGHT_BOTTOM: - actual_delta_x = new_rect.mRight - orig_rect.mRight; - actual_delta_y = new_rect.mBottom - orig_rect.mBottom; - if (actual_delta_x != delta_x - || actual_delta_y != delta_y) - { - new_rect.mLeft = orig_rect.mLeft; - new_rect.mTop = orig_rect.mTop; - resizing_view->setShape(new_rect, true); - } - - mDragLastScreenX += actual_delta_x; - mDragLastScreenY += actual_delta_y; - break; - default: - break; - } - } - - handled = TRUE; - } - else // don't have mouse capture - { - if( pointInHandle( x, y ) ) - { - handled = TRUE; - } - } - - if( handled ) - { - switch( mCorner ) - { - case RIGHT_BOTTOM: - case LEFT_TOP: - getWindow()->setCursor(UI_CURSOR_SIZENWSE); - break; - case LEFT_BOTTOM: - case RIGHT_TOP: - getWindow()->setCursor(UI_CURSOR_SIZENESW); - break; - } - } - - return handled; + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // Make sure the mouse in still over the application. We don't want to make the parent + // so big that we can't see the resize handle any more. + + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + const LLRect valid_rect = getRootView()->getRect(); + screen_x = llclamp( screen_x, valid_rect.mLeft, valid_rect.mRight ); + screen_y = llclamp( screen_y, valid_rect.mBottom, valid_rect.mTop ); + + LLView* resizing_view = getParent(); + if( resizing_view ) + { + // undock floater when user resize it + LLFloater* floater_parent = dynamic_cast<LLFloater*>(getParent()); + if (floater_parent && floater_parent->isDocked()) + { + floater_parent->setDocked(false, false); + } + + // Resize the parent + LLRect orig_rect = resizing_view->getRect(); + LLRect scaled_rect = orig_rect; + S32 delta_x = screen_x - mDragLastScreenX; + S32 delta_y = screen_y - mDragLastScreenY; + LLCoordGL mouse_dir; + // use hysteresis on mouse motion to preserve user intent when mouse stops moving + mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX; + mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY; + mLastMouseScreenX = screen_x; + mLastMouseScreenY = screen_y; + mLastMouseDir = mouse_dir; + + S32 x_multiple = 1; + S32 y_multiple = 1; + switch( mCorner ) + { + case LEFT_TOP: + x_multiple = -1; + y_multiple = 1; + break; + case LEFT_BOTTOM: + x_multiple = -1; + y_multiple = -1; + break; + case RIGHT_TOP: + x_multiple = 1; + y_multiple = 1; + break; + case RIGHT_BOTTOM: + x_multiple = 1; + y_multiple = -1; + break; + } + + S32 new_width = orig_rect.getWidth() + x_multiple * delta_x; + if( new_width < mMinWidth ) + { + new_width = mMinWidth; + delta_x = x_multiple * (mMinWidth - orig_rect.getWidth()); + } + + S32 new_height = orig_rect.getHeight() + y_multiple * delta_y; + if( new_height < mMinHeight ) + { + new_height = mMinHeight; + delta_y = y_multiple * (mMinHeight - orig_rect.getHeight()); + } + + switch( mCorner ) + { + case LEFT_TOP: + scaled_rect.translate(delta_x, 0); + break; + case LEFT_BOTTOM: + scaled_rect.translate(delta_x, delta_y); + break; + case RIGHT_TOP: + break; + case RIGHT_BOTTOM: + scaled_rect.translate(0, delta_y); + break; + } + + // temporarily set new parent rect + scaled_rect.mRight = scaled_rect.mLeft + new_width; + scaled_rect.mTop = scaled_rect.mBottom + new_height; + resizing_view->setRect(scaled_rect); + + LLView* snap_view = NULL; + LLView* test_view = NULL; + + static LLUICachedControl<S32> snap_margin ("SnapMargin", 0); + // now do snapping + switch(mCorner) + { + case LEFT_TOP: + snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); + if (!snap_view) + { + snap_view = test_view; + } + break; + case LEFT_BOTTOM: + snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); + if (!snap_view) + { + snap_view = test_view; + } + break; + case RIGHT_TOP: + snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin); + if (!snap_view) + { + snap_view = test_view; + } + break; + case RIGHT_BOTTOM: + snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin); + test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin); + if (!snap_view) + { + snap_view = test_view; + } + break; + } + + // register "snap" behavior with snapped view + resizing_view->setSnappedTo(snap_view); + + // reset parent rect + resizing_view->setRect(orig_rect); + + // translate and scale to new shape + resizing_view->setShape(scaled_rect, true); + + // update last valid mouse cursor position based on resized view's actual size + LLRect new_rect = resizing_view->getRect(); + S32 actual_delta_x = 0; + S32 actual_delta_y = 0; + switch(mCorner) + { + case LEFT_TOP: + actual_delta_x = new_rect.mLeft - orig_rect.mLeft; + actual_delta_y = new_rect.mTop - orig_rect.mTop; + if (actual_delta_x != delta_x + || actual_delta_y != delta_y) + { + new_rect.mRight = orig_rect.mRight; + new_rect.mBottom = orig_rect.mBottom; + resizing_view->setShape(new_rect, true); + } + + mDragLastScreenX += actual_delta_x; + mDragLastScreenY += actual_delta_y; + break; + case LEFT_BOTTOM: + actual_delta_x = new_rect.mLeft - orig_rect.mLeft; + actual_delta_y = new_rect.mBottom - orig_rect.mBottom; + if (actual_delta_x != delta_x + || actual_delta_y != delta_y) + { + new_rect.mRight = orig_rect.mRight; + new_rect.mTop = orig_rect.mTop; + resizing_view->setShape(new_rect, true); + } + + mDragLastScreenX += actual_delta_x; + mDragLastScreenY += actual_delta_y; + break; + case RIGHT_TOP: + actual_delta_x = new_rect.mRight - orig_rect.mRight; + actual_delta_y = new_rect.mTop - orig_rect.mTop; + if (actual_delta_x != delta_x + || actual_delta_y != delta_y) + { + new_rect.mLeft = orig_rect.mLeft; + new_rect.mBottom = orig_rect.mBottom; + resizing_view->setShape(new_rect, true); + } + + mDragLastScreenX += actual_delta_x; + mDragLastScreenY += actual_delta_y; + break; + case RIGHT_BOTTOM: + actual_delta_x = new_rect.mRight - orig_rect.mRight; + actual_delta_y = new_rect.mBottom - orig_rect.mBottom; + if (actual_delta_x != delta_x + || actual_delta_y != delta_y) + { + new_rect.mLeft = orig_rect.mLeft; + new_rect.mTop = orig_rect.mTop; + resizing_view->setShape(new_rect, true); + } + + mDragLastScreenX += actual_delta_x; + mDragLastScreenY += actual_delta_y; + break; + default: + break; + } + } + + handled = TRUE; + } + else // don't have mouse capture + { + if( pointInHandle( x, y ) ) + { + handled = TRUE; + } + } + + if( handled ) + { + switch( mCorner ) + { + case RIGHT_BOTTOM: + case LEFT_TOP: + getWindow()->setCursor(UI_CURSOR_SIZENWSE); + break; + case LEFT_BOTTOM: + case RIGHT_TOP: + getWindow()->setCursor(UI_CURSOR_SIZENESW); + break; + } + } + + return handled; } // end handleHover // assumes GL state is set for 2D void LLResizeHandle::draw() { - if( mImage.notNull() && getVisible() && (RIGHT_BOTTOM == mCorner) ) - { - mImage->draw(0, 0); - } + if( mImage.notNull() && getVisible() && (RIGHT_BOTTOM == mCorner) ) + { + mImage->draw(0, 0); + } } BOOL LLResizeHandle::pointInHandle( S32 x, S32 y ) { - if( pointInView(x, y) ) - { - const S32 TOP_BORDER = (getRect().getHeight() - RESIZE_BORDER_WIDTH); - const S32 RIGHT_BORDER = (getRect().getWidth() - RESIZE_BORDER_WIDTH); - - switch( mCorner ) - { - case LEFT_TOP: return (x <= RESIZE_BORDER_WIDTH) || (y >= TOP_BORDER); - case LEFT_BOTTOM: return (x <= RESIZE_BORDER_WIDTH) || (y <= RESIZE_BORDER_WIDTH); - case RIGHT_TOP: return (x >= RIGHT_BORDER) || (y >= TOP_BORDER); - case RIGHT_BOTTOM: return TRUE; - } - } - return FALSE; + if( pointInView(x, y) ) + { + const S32 TOP_BORDER = (getRect().getHeight() - RESIZE_BORDER_WIDTH); + const S32 RIGHT_BORDER = (getRect().getWidth() - RESIZE_BORDER_WIDTH); + + switch( mCorner ) + { + case LEFT_TOP: return (x <= RESIZE_BORDER_WIDTH) || (y >= TOP_BORDER); + case LEFT_BOTTOM: return (x <= RESIZE_BORDER_WIDTH) || (y <= RESIZE_BORDER_WIDTH); + case RIGHT_TOP: return (x >= RIGHT_BORDER) || (y >= TOP_BORDER); + case RIGHT_BOTTOM: return TRUE; + } + } + return FALSE; } diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h index ae20ecaa77..d29894f607 100644 --- a/indra/llui/llresizehandle.h +++ b/indra/llui/llresizehandle.h @@ -1,25 +1,25 @@ -/** +/** * @file llresizehandle.h * @brief LLResizeHandle base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,40 +35,40 @@ class LLResizeHandle : public LLView { public: - enum ECorner { LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM }; + enum ECorner { LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM }; - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Mandatory<ECorner> corner; - Optional<S32> min_width; - Optional<S32> min_height; - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Mandatory<ECorner> corner; + Optional<S32> min_width; + Optional<S32> min_height; + Params(); + }; ~LLResizeHandle(); protected: - LLResizeHandle(const LLResizeHandle::Params&); - friend class LLUICtrlFactory; + LLResizeHandle(const LLResizeHandle::Params&); + friend class LLUICtrlFactory; public: - virtual void draw(); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual void draw(); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + + void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } - void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } - private: - BOOL pointInHandle( S32 x, S32 y ); + BOOL pointInHandle( S32 x, S32 y ); - S32 mDragLastScreenX; - S32 mDragLastScreenY; - S32 mLastMouseScreenX; - S32 mLastMouseScreenY; - LLCoordGL mLastMouseDir; - LLPointer<LLUIImage> mImage; - S32 mMinWidth; - S32 mMinHeight; - const ECorner mCorner; + S32 mDragLastScreenX; + S32 mDragLastScreenY; + S32 mLastMouseScreenX; + S32 mLastMouseScreenY; + LLCoordGL mLastMouseDir; + LLPointer<LLUIImage> mImage; + S32 mMinWidth; + S32 mMinHeight; + const ECorner mCorner; }; const S32 RESIZE_HANDLE_HEIGHT = 11; diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index d65c220974..a6a4a541f2 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llresmgr.cpp * @brief Localized resource manager * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,256 +37,256 @@ LLResMgr::LLResMgr() { - // Set default - setLocale( LLLOCALE_USA ); + // Set default + setLocale( LLLOCALE_USA ); } void LLResMgr::setLocale( LLLOCALE_ID locale_id ) { - mLocale = locale_id; + mLocale = locale_id; } -char LLResMgr::getDecimalPoint() const -{ - char decimal = localeconv()->decimal_point[0]; +char LLResMgr::getDecimalPoint() const +{ + char decimal = localeconv()->decimal_point[0]; #if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(decimal == 0) - { - decimal = '.'; - } + // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. + if(decimal == 0) + { + decimal = '.'; + } #endif - return decimal; + return decimal; } -char LLResMgr::getThousandsSeparator() const +char LLResMgr::getThousandsSeparator() const { - char separator = localeconv()->thousands_sep[0]; + char separator = localeconv()->thousands_sep[0]; #if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(separator == 0) - { - separator = ','; - } + // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. + if(separator == 0) + { + separator = ','; + } #endif - return separator; + return separator; } char LLResMgr::getMonetaryDecimalPoint() const { - char decimal = localeconv()->mon_decimal_point[0]; + char decimal = localeconv()->mon_decimal_point[0]; #if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(decimal == 0) - { - decimal = '.'; - } + // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. + if(decimal == 0) + { + decimal = '.'; + } #endif - return decimal; + return decimal; } -char LLResMgr::getMonetaryThousandsSeparator() const +char LLResMgr::getMonetaryThousandsSeparator() const { - char separator = localeconv()->mon_thousands_sep[0]; + char separator = localeconv()->mon_thousands_sep[0]; #if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(separator == 0) - { - separator = ','; - } + // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. + if(separator == 0) + { + separator = ','; + } #endif - return separator; + return separator; } // Sets output to a string of integers with monetary separators inserted according to the locale. std::string LLResMgr::getMonetaryString( S32 input ) const { - std::string output; + std::string output; + + LLLocale locale(LLLocale::USER_LOCALE); + struct lconv *conv = localeconv(); - LLLocale locale(LLLocale::USER_LOCALE); - struct lconv *conv = localeconv(); - #if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - // Fake up a conv structure with some reasonable values for the fields this function uses. - struct lconv fakeconv; - char fake_neg[2] = "-"; - char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits - if(conv->negative_sign[0] == 0) // Real locales all seem to have something here... - { - fakeconv = *conv; // start with what's there. - switch(mLocale) - { - default: // Unknown -- use the US defaults. - case LLLOCALE_USA: - case LLLOCALE_UK: // UK ends up being the same as US for the items used here. - fakeconv.negative_sign = fake_neg; - fakeconv.mon_grouping = fake_mon_group; - fakeconv.n_sign_posn = 1; // negative sign before the string - break; - } - conv = &fakeconv; - } + // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. + // Fake up a conv structure with some reasonable values for the fields this function uses. + struct lconv fakeconv; + char fake_neg[2] = "-"; + char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits + if(conv->negative_sign[0] == 0) // Real locales all seem to have something here... + { + fakeconv = *conv; // start with what's there. + switch(mLocale) + { + default: // Unknown -- use the US defaults. + case LLLOCALE_USA: + case LLLOCALE_UK: // UK ends up being the same as US for the items used here. + fakeconv.negative_sign = fake_neg; + fakeconv.mon_grouping = fake_mon_group; + fakeconv.n_sign_posn = 1; // negative sign before the string + break; + } + conv = &fakeconv; + } #endif - char* negative_sign = conv->negative_sign; - char separator = getMonetaryThousandsSeparator(); - char* grouping = conv->mon_grouping; - - // Note on mon_grouping: - // Specifies a string that defines the size of each group of digits in formatted monetary quantities. - // The operand for the mon_grouping keyword consists of a sequence of semicolon-separated integers. - // Each integer specifies the number of digits in a group. The initial integer defines the size of - // the group immediately to the left of the decimal delimiter. The following integers define succeeding - // groups to the left of the previous group. If the last integer is not -1, the size of the previous - // group (if any) is repeatedly used for the remainder of the digits. If the last integer is -1, no - // further grouping is performed. - - - // Note: we assume here that the currency symbol goes on the left. (Hey, it's Lindens! We can just decide.) - BOOL negative = (input < 0 ); - BOOL negative_before = negative && (conv->n_sign_posn != 2); - BOOL negative_after = negative && (conv->n_sign_posn == 2); - - std::string digits = llformat("%u", abs(input)); - if( !grouping || !grouping[0] ) - { - if( negative_before ) - { - output.append( negative_sign ); - } - output.append( digits ); - if( negative_after ) - { - output.append( negative_sign ); - } - return output; - } - - S32 groupings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - S32 cur_group; - for( cur_group = 0; grouping[ cur_group ]; cur_group++ ) - { - if( grouping[ cur_group ] != ';' ) - { - groupings[cur_group] = grouping[ cur_group ]; - } - cur_group++; - - if( groupings[cur_group] < 0 ) - { - break; - } - } - S32 group_count = cur_group; - - char reversed_output[20] = ""; /* Flawfinder: ignore */ - char forward_output[20] = ""; /* Flawfinder: ignore */ - S32 output_pos = 0; - - cur_group = 0; - S32 pos = digits.size()-1; - S32 count_within_group = 0; - while( (pos >= 0) && (groupings[cur_group] >= 0) ) - { - count_within_group++; - if( count_within_group > groupings[cur_group] ) - { - count_within_group = 1; - reversed_output[ output_pos++ ] = separator; - - if( (cur_group + 1) >= group_count ) - { - break; - } - else - if( groupings[cur_group + 1] > 0 ) - { - cur_group++; - } - } - reversed_output[ output_pos++ ] = digits[pos--]; - } - - while( pos >= 0 ) - { - reversed_output[ output_pos++ ] = digits[pos--]; - } - - - reversed_output[ output_pos ] = '\0'; - forward_output[ output_pos ] = '\0'; - - for( S32 i = 0; i < output_pos; i++ ) - { - forward_output[ output_pos - 1 - i ] = reversed_output[ i ]; - } - - if( negative_before ) - { - output.append( negative_sign ); - } - output.append( forward_output ); - if( negative_after ) - { - output.append( negative_sign ); - } - return output; + char* negative_sign = conv->negative_sign; + char separator = getMonetaryThousandsSeparator(); + char* grouping = conv->mon_grouping; + + // Note on mon_grouping: + // Specifies a string that defines the size of each group of digits in formatted monetary quantities. + // The operand for the mon_grouping keyword consists of a sequence of semicolon-separated integers. + // Each integer specifies the number of digits in a group. The initial integer defines the size of + // the group immediately to the left of the decimal delimiter. The following integers define succeeding + // groups to the left of the previous group. If the last integer is not -1, the size of the previous + // group (if any) is repeatedly used for the remainder of the digits. If the last integer is -1, no + // further grouping is performed. + + + // Note: we assume here that the currency symbol goes on the left. (Hey, it's Lindens! We can just decide.) + BOOL negative = (input < 0 ); + BOOL negative_before = negative && (conv->n_sign_posn != 2); + BOOL negative_after = negative && (conv->n_sign_posn == 2); + + std::string digits = llformat("%u", abs(input)); + if( !grouping || !grouping[0] ) + { + if( negative_before ) + { + output.append( negative_sign ); + } + output.append( digits ); + if( negative_after ) + { + output.append( negative_sign ); + } + return output; + } + + S32 groupings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + S32 cur_group; + for( cur_group = 0; grouping[ cur_group ]; cur_group++ ) + { + if( grouping[ cur_group ] != ';' ) + { + groupings[cur_group] = grouping[ cur_group ]; + } + cur_group++; + + if( groupings[cur_group] < 0 ) + { + break; + } + } + S32 group_count = cur_group; + + char reversed_output[20] = ""; /* Flawfinder: ignore */ + char forward_output[20] = ""; /* Flawfinder: ignore */ + S32 output_pos = 0; + + cur_group = 0; + S32 pos = digits.size()-1; + S32 count_within_group = 0; + while( (pos >= 0) && (groupings[cur_group] >= 0) ) + { + count_within_group++; + if( count_within_group > groupings[cur_group] ) + { + count_within_group = 1; + reversed_output[ output_pos++ ] = separator; + + if( (cur_group + 1) >= group_count ) + { + break; + } + else + if( groupings[cur_group + 1] > 0 ) + { + cur_group++; + } + } + reversed_output[ output_pos++ ] = digits[pos--]; + } + + while( pos >= 0 ) + { + reversed_output[ output_pos++ ] = digits[pos--]; + } + + + reversed_output[ output_pos ] = '\0'; + forward_output[ output_pos ] = '\0'; + + for( S32 i = 0; i < output_pos; i++ ) + { + forward_output[ output_pos - 1 - i ] = reversed_output[ i ]; + } + + if( negative_before ) + { + output.append( negative_sign ); + } + output.append( forward_output ); + if( negative_after ) + { + output.append( negative_sign ); + } + return output; } void LLResMgr::getIntegerString( std::string& output, S32 input ) const { - // handle special case of input value being zero - if (input == 0) - { - output = "0"; - return; - } - - // *NOTE: this method does not handle negative input integers correctly - S32 fraction = 0; - std::string fraction_string; - S32 remaining_count = input; - while(remaining_count > 0) - { - fraction = (remaining_count) % 1000; - - if (!output.empty()) - { - if (fraction == remaining_count) - { - fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator()); - } - else - { - fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator()); - } - output = fraction_string + output; - } - else - { - if (fraction == remaining_count) - { - fraction_string = llformat("%d", fraction); - } - else - { - fraction_string = llformat("%3.3d", fraction); - } - output = fraction_string; - } - remaining_count /= 1000; - } + // handle special case of input value being zero + if (input == 0) + { + output = "0"; + return; + } + + // *NOTE: this method does not handle negative input integers correctly + S32 fraction = 0; + std::string fraction_string; + S32 remaining_count = input; + while(remaining_count > 0) + { + fraction = (remaining_count) % 1000; + + if (!output.empty()) + { + if (fraction == remaining_count) + { + fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator()); + } + else + { + fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator()); + } + output = fraction_string + output; + } + else + { + if (fraction == remaining_count) + { + fraction_string = llformat("%d", fraction); + } + else + { + fraction_string = llformat("%3.3d", fraction); + } + output = fraction_string; + } + remaining_count /= 1000; + } } #if LL_WINDOWS @@ -303,20 +303,20 @@ const std::string LLLocale::SYSTEM_LOCALE("C"); LLLocale::LLLocale(const std::string& locale_string) { - mPrevLocaleString = setlocale( LC_ALL, NULL ); - char* new_locale_string = setlocale( LC_ALL, locale_string.c_str()); - if ( new_locale_string == NULL) - { - LL_WARNS_ONCE("LLLocale") << "Failed to set locale " << locale_string << LL_ENDL; - setlocale(LC_ALL, SYSTEM_LOCALE.c_str()); - } - //else - //{ - // LL_INFOS() << "Set locale to " << new_locale_string << LL_ENDL; - //} + mPrevLocaleString = setlocale( LC_ALL, NULL ); + char* new_locale_string = setlocale( LC_ALL, locale_string.c_str()); + if ( new_locale_string == NULL) + { + LL_WARNS_ONCE("LLLocale") << "Failed to set locale " << locale_string << LL_ENDL; + setlocale(LC_ALL, SYSTEM_LOCALE.c_str()); + } + //else + //{ + // LL_INFOS() << "Set locale to " << new_locale_string << LL_ENDL; + //} } -LLLocale::~LLLocale() +LLLocale::~LLLocale() { - setlocale( LC_ALL, mPrevLocaleString.c_str() ); + setlocale( LC_ALL, mPrevLocaleString.c_str() ); } diff --git a/indra/llui/llresmgr.h b/indra/llui/llresmgr.h index b19d8d40b8..7ad6659a44 100644 --- a/indra/llui/llresmgr.h +++ b/indra/llui/llresmgr.h @@ -1,25 +1,25 @@ -/** +/** * @file llresmgr.h * @brief Localized resource manager * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,43 +35,43 @@ enum LLLOCALE_ID { - LLLOCALE_USA, - LLLOCALE_UK, - LLLOCALE_COUNT // Number of values in this enum. Keep at end. + LLLOCALE_USA, + LLLOCALE_UK, + LLLOCALE_COUNT // Number of values in this enum. Keep at end. }; class LLResMgr : public LLSingleton<LLResMgr> { - LLSINGLETON(LLResMgr); + LLSINGLETON(LLResMgr); public: - void setLocale( LLLOCALE_ID locale_id ); - LLLOCALE_ID getLocale() const { return mLocale; } + void setLocale( LLLOCALE_ID locale_id ); + LLLOCALE_ID getLocale() const { return mLocale; } - char getDecimalPoint() const; - char getThousandsSeparator() const; + char getDecimalPoint() const; + char getThousandsSeparator() const; - char getMonetaryDecimalPoint() const; - char getMonetaryThousandsSeparator() const; - std::string getMonetaryString( S32 input ) const; - void getIntegerString( std::string& output, S32 input ) const; + char getMonetaryDecimalPoint() const; + char getMonetaryThousandsSeparator() const; + std::string getMonetaryString( S32 input ) const; + void getIntegerString( std::string& output, S32 input ) const; private: - LLLOCALE_ID mLocale; + LLLOCALE_ID mLocale; }; class LLLocale { public: - LLLocale(const std::string& locale_string); - virtual ~LLLocale(); + LLLocale(const std::string& locale_string); + virtual ~LLLocale(); - static const std::string USER_LOCALE; - static const std::string SYSTEM_LOCALE; + static const std::string USER_LOCALE; + static const std::string SYSTEM_LOCALE; private: - std::string mPrevLocaleString; + std::string mPrevLocaleString; }; #endif // LL_RESMGR_ diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp index 4bd1561425..1b4008cff2 100644 --- a/indra/llui/llrngwriter.cpp +++ b/indra/llui/llrngwriter.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrngwriter.cpp * @brief Generates Relax NG schema from param blocks * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,9 +33,9 @@ #include "boost/bind.hpp" -static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; +static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; // // LLRNGWriter - writes Relax NG schema files based on a param block @@ -43,276 +43,276 @@ static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; LLRNGWriter::LLRNGWriter() : Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) { - // register various callbacks for inspecting the contents of a param block - registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4)); - registerInspectFunc<std::string>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); - registerInspectFunc<U8>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedByte", _1, _2, _3, _4)); - registerInspectFunc<S8>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedByte", _1, _2, _3, _4)); - registerInspectFunc<U16>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedShort", _1, _2, _3, _4)); - registerInspectFunc<S16>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedShort", _1, _2, _3, _4)); - registerInspectFunc<U32>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedInt", _1, _2, _3, _4)); - registerInspectFunc<S32>(boost::bind(&LLRNGWriter::writeAttribute, this, "integer", _1, _2, _3, _4)); - registerInspectFunc<F32>(boost::bind(&LLRNGWriter::writeAttribute, this, "float", _1, _2, _3, _4)); - registerInspectFunc<F64>(boost::bind(&LLRNGWriter::writeAttribute, this, "double", _1, _2, _3, _4)); - registerInspectFunc<LLColor4>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); - registerInspectFunc<LLUIColor>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); - registerInspectFunc<LLUUID>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); - registerInspectFunc<LLSD>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); + // register various callbacks for inspecting the contents of a param block + registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4)); + registerInspectFunc<std::string>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); + registerInspectFunc<U8>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedByte", _1, _2, _3, _4)); + registerInspectFunc<S8>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedByte", _1, _2, _3, _4)); + registerInspectFunc<U16>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedShort", _1, _2, _3, _4)); + registerInspectFunc<S16>(boost::bind(&LLRNGWriter::writeAttribute, this, "signedShort", _1, _2, _3, _4)); + registerInspectFunc<U32>(boost::bind(&LLRNGWriter::writeAttribute, this, "unsignedInt", _1, _2, _3, _4)); + registerInspectFunc<S32>(boost::bind(&LLRNGWriter::writeAttribute, this, "integer", _1, _2, _3, _4)); + registerInspectFunc<F32>(boost::bind(&LLRNGWriter::writeAttribute, this, "float", _1, _2, _3, _4)); + registerInspectFunc<F64>(boost::bind(&LLRNGWriter::writeAttribute, this, "double", _1, _2, _3, _4)); + registerInspectFunc<LLColor4>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); + registerInspectFunc<LLUIColor>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); + registerInspectFunc<LLUUID>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); + registerInspectFunc<LLSD>(boost::bind(&LLRNGWriter::writeAttribute, this, "string", _1, _2, _3, _4)); } void LLRNGWriter::writeRNG(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace) { - mGrammarNode = node; - mGrammarNode->setName("grammar"); - mGrammarNode->createChild("xmlns", true)->setStringValue("http://relaxng.org/ns/structure/1.0"); - mGrammarNode->createChild("datatypeLibrary", true)->setStringValue("http://www.w3.org/2001/XMLSchema-datatypes"); - mGrammarNode->createChild("ns", true)->setStringValue(xml_namespace); + mGrammarNode = node; + mGrammarNode->setName("grammar"); + mGrammarNode->createChild("xmlns", true)->setStringValue("http://relaxng.org/ns/structure/1.0"); + mGrammarNode->createChild("datatypeLibrary", true)->setStringValue("http://www.w3.org/2001/XMLSchema-datatypes"); + mGrammarNode->createChild("ns", true)->setStringValue(xml_namespace); - node = mGrammarNode->createChild("start", false); - node = node->createChild("ref", false); - node->createChild("name", true)->setStringValue(type_name); + node = mGrammarNode->createChild("start", false); + node = node->createChild("ref", false); + node->createChild("name", true)->setStringValue(type_name); - addDefinition(type_name, block); + addDefinition(type_name, block); } void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam::BaseBlock& block) { - if (mDefinedElements.find(type_name) != mDefinedElements.end()) return; - mDefinedElements.insert(type_name); - - LLXMLNodePtr node = mGrammarNode->createChild("define", false); - node->createChild("name", true)->setStringValue(type_name); - - mElementNode = node->createChild("element", false); - mElementNode->createChild("name", true)->setStringValue(type_name); - mChildrenNode = mElementNode->createChild("zeroOrMore", false)->createChild("choice", false); - - mAttributesWritten.first = mElementNode; - mAttributesWritten.second.clear(); - mElementsWritten.clear(); - - block.inspectBlock(*this); - - // add includes for all possible children - const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); - const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); - - // add include declarations for all valid children - for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); - it != widget_registryp->currentRegistrar().endItems(); - ++it) - { - std::string child_name = it->first; - if (child_name == type_name) - { - continue; - } - - LLXMLNodePtr old_element_node = mElementNode; - LLXMLNodePtr old_child_node = mChildrenNode; - //FIXME: add LLDefaultParamBlockRegistry back when working on schema generation - //addDefinition(child_name, (*LLDefaultParamBlockRegistry::instance().getValue(type))()); - mElementNode = old_element_node; - mChildrenNode = old_child_node; - - mChildrenNode->createChild("ref", false)->createChild("name", true)->setStringValue(child_name); - } - - if (mChildrenNode->mChildren.isNull()) - { - // remove unused children node - mChildrenNode->mParent->mParent->deleteChild(mChildrenNode->mParent); - } + if (mDefinedElements.find(type_name) != mDefinedElements.end()) return; + mDefinedElements.insert(type_name); + + LLXMLNodePtr node = mGrammarNode->createChild("define", false); + node->createChild("name", true)->setStringValue(type_name); + + mElementNode = node->createChild("element", false); + mElementNode->createChild("name", true)->setStringValue(type_name); + mChildrenNode = mElementNode->createChild("zeroOrMore", false)->createChild("choice", false); + + mAttributesWritten.first = mElementNode; + mAttributesWritten.second.clear(); + mElementsWritten.clear(); + + block.inspectBlock(*this); + + // add includes for all possible children + const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); + const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); + + // add include declarations for all valid children + for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); + it != widget_registryp->currentRegistrar().endItems(); + ++it) + { + std::string child_name = it->first; + if (child_name == type_name) + { + continue; + } + + LLXMLNodePtr old_element_node = mElementNode; + LLXMLNodePtr old_child_node = mChildrenNode; + //FIXME: add LLDefaultParamBlockRegistry back when working on schema generation + //addDefinition(child_name, (*LLDefaultParamBlockRegistry::instance().getValue(type))()); + mElementNode = old_element_node; + mChildrenNode = old_child_node; + + mChildrenNode->createChild("ref", false)->createChild("name", true)->setStringValue(child_name); + } + + if (mChildrenNode->mChildren.isNull()) + { + // remove unused children node + mChildrenNode->mParent->mParent->deleteChild(mChildrenNode->mParent); + } } void LLRNGWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values) { - if (max_count == 0) return; - - name_stack_t non_empty_names; - std::string attribute_name; - for (name_stack_t::const_iterator it = stack.begin(); - it != stack.end(); - ++it) - { - const std::string& name = it->first; - if (!name.empty()) - { - non_empty_names.push_back(*it); - } - } - - if (non_empty_names.empty()) return; - - for (name_stack_t::const_iterator it = non_empty_names.begin(); - it != non_empty_names.end(); - ++it) - { - if (!attribute_name.empty()) - { - attribute_name += "."; - } - attribute_name += it->first; - } - - // singular attribute, e.g. <foo bar="1"/> - if (non_empty_names.size() == 1 && max_count == 1) - { - if (mAttributesWritten.second.find(attribute_name) == mAttributesWritten.second.end()) - { - LLXMLNodePtr node = createCardinalityNode(mElementNode, min_count, max_count)->createChild("attribute", false); - node->createChild("name", true)->setStringValue(attribute_name); - node->createChild("data", false)->createChild("type", true)->setStringValue(type); - - mAttributesWritten.second.insert(attribute_name); - } - } - // compound attribute - else - { - std::string element_name; - - // traverse all but last element, leaving that as an attribute name - name_stack_t::const_iterator end_it = non_empty_names.end(); - end_it--; - - for (name_stack_t::const_iterator it = non_empty_names.begin(); - it != end_it; - ++it) - { - if (it != non_empty_names.begin()) - { - element_name += "."; - } - element_name += it->first; - } - - elements_map_t::iterator found_it = mElementsWritten.find(element_name); - // <choice> - // <group> - // <optional> - // <attribute name="foo.bar"><data type="string"/></attribute> - // </optional> - // <optional> - // <attribute name="foo.baz"><data type="integer"/></attribute> - // </optional> - // </group> - // <element name="foo"> - // <optional> - // <attribute name="bar"><data type="string"/></attribute> - // </optional> - // <optional> - // <attribute name="baz"><data type="string"/></attribute> - // </optional> - // </element> - // <element name="outer.foo"> - // <ref name="foo"/> - // </element> - // </choice> - - if (found_it != mElementsWritten.end()) - { - // reuse existing element - LLXMLNodePtr choice_node = found_it->second.first; - - // attribute with this name not already written? - if (found_it->second.second.find(attribute_name) == found_it->second.second.end()) - { - // append to <group> - LLXMLNodePtr node = choice_node->mChildren->head; - node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - node->createChild("name", true)->setStringValue(attribute_name); - addTypeNode(node, type, possible_values); - - // append to <element> - node = choice_node->mChildren->head->mNext->mChildren->head; - node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - node->createChild("name", true)->setStringValue(non_empty_names.back().first); - addTypeNode(node, type, possible_values); - - // append to <element> - //node = choice_node->mChildren->head->mNext->mNext->mChildren->head; - //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - //node->createChild("name", true)->setStringValue(non_empty_names.back().first); - //addTypeNode(node, type, possible_values); - - found_it->second.second.insert(attribute_name); - } - } - else - { - LLXMLNodePtr choice_node = mElementNode->createChild("choice", false); - - LLXMLNodePtr node = choice_node->createChild("group", false); - node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - node->createChild("name", true)->setStringValue(attribute_name); - addTypeNode(node, type, possible_values); - - node = choice_node->createChild("optional", false); - node = node->createChild("element", false); - node->createChild("name", true)->setStringValue(element_name); - node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - node->createChild("name", true)->setStringValue(non_empty_names.back().first); - addTypeNode(node, type, possible_values); - - //node = choice_node->createChild("optional", false); - //node = node->createChild("element", false); - //node->createChild("name", true)->setStringValue(mDefinitionName + "." + element_name); - //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); - //node->createChild("name", true)->setStringValue(non_empty_names.back().first); - //addTypeNode(node, type, possible_values); - - attribute_data_t& attribute_data = mElementsWritten[element_name]; - attribute_data.first = choice_node; - attribute_data.second.insert(attribute_name); - } - } + if (max_count == 0) return; + + name_stack_t non_empty_names; + std::string attribute_name; + for (name_stack_t::const_iterator it = stack.begin(); + it != stack.end(); + ++it) + { + const std::string& name = it->first; + if (!name.empty()) + { + non_empty_names.push_back(*it); + } + } + + if (non_empty_names.empty()) return; + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != non_empty_names.end(); + ++it) + { + if (!attribute_name.empty()) + { + attribute_name += "."; + } + attribute_name += it->first; + } + + // singular attribute, e.g. <foo bar="1"/> + if (non_empty_names.size() == 1 && max_count == 1) + { + if (mAttributesWritten.second.find(attribute_name) == mAttributesWritten.second.end()) + { + LLXMLNodePtr node = createCardinalityNode(mElementNode, min_count, max_count)->createChild("attribute", false); + node->createChild("name", true)->setStringValue(attribute_name); + node->createChild("data", false)->createChild("type", true)->setStringValue(type); + + mAttributesWritten.second.insert(attribute_name); + } + } + // compound attribute + else + { + std::string element_name; + + // traverse all but last element, leaving that as an attribute name + name_stack_t::const_iterator end_it = non_empty_names.end(); + end_it--; + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != end_it; + ++it) + { + if (it != non_empty_names.begin()) + { + element_name += "."; + } + element_name += it->first; + } + + elements_map_t::iterator found_it = mElementsWritten.find(element_name); + // <choice> + // <group> + // <optional> + // <attribute name="foo.bar"><data type="string"/></attribute> + // </optional> + // <optional> + // <attribute name="foo.baz"><data type="integer"/></attribute> + // </optional> + // </group> + // <element name="foo"> + // <optional> + // <attribute name="bar"><data type="string"/></attribute> + // </optional> + // <optional> + // <attribute name="baz"><data type="string"/></attribute> + // </optional> + // </element> + // <element name="outer.foo"> + // <ref name="foo"/> + // </element> + // </choice> + + if (found_it != mElementsWritten.end()) + { + // reuse existing element + LLXMLNodePtr choice_node = found_it->second.first; + + // attribute with this name not already written? + if (found_it->second.second.find(attribute_name) == found_it->second.second.end()) + { + // append to <group> + LLXMLNodePtr node = choice_node->mChildren->head; + node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + node->createChild("name", true)->setStringValue(attribute_name); + addTypeNode(node, type, possible_values); + + // append to <element> + node = choice_node->mChildren->head->mNext->mChildren->head; + node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + node->createChild("name", true)->setStringValue(non_empty_names.back().first); + addTypeNode(node, type, possible_values); + + // append to <element> + //node = choice_node->mChildren->head->mNext->mNext->mChildren->head; + //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + //node->createChild("name", true)->setStringValue(non_empty_names.back().first); + //addTypeNode(node, type, possible_values); + + found_it->second.second.insert(attribute_name); + } + } + else + { + LLXMLNodePtr choice_node = mElementNode->createChild("choice", false); + + LLXMLNodePtr node = choice_node->createChild("group", false); + node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + node->createChild("name", true)->setStringValue(attribute_name); + addTypeNode(node, type, possible_values); + + node = choice_node->createChild("optional", false); + node = node->createChild("element", false); + node->createChild("name", true)->setStringValue(element_name); + node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + node->createChild("name", true)->setStringValue(non_empty_names.back().first); + addTypeNode(node, type, possible_values); + + //node = choice_node->createChild("optional", false); + //node = node->createChild("element", false); + //node->createChild("name", true)->setStringValue(mDefinitionName + "." + element_name); + //node = createCardinalityNode(node, min_count, max_count)->createChild("attribute", false); + //node->createChild("name", true)->setStringValue(non_empty_names.back().first); + //addTypeNode(node, type, possible_values); + + attribute_data_t& attribute_data = mElementsWritten[element_name]; + attribute_data.first = choice_node; + attribute_data.second.insert(attribute_name); + } + } } void LLRNGWriter::addTypeNode(LLXMLNodePtr parent_node, const std::string& type, const std::vector<std::string>* possible_values) { - if (possible_values) - { - LLXMLNodePtr enum_node = parent_node->createChild("choice", false); - for (std::vector<std::string>::const_iterator it = possible_values->begin(); - it != possible_values->end(); - ++it) - { - enum_node->createChild("value", false)->setStringValue(*it); - } - } - else - { - parent_node->createChild("data", false)->createChild("type", true)->setStringValue(type); - } + if (possible_values) + { + LLXMLNodePtr enum_node = parent_node->createChild("choice", false); + for (std::vector<std::string>::const_iterator it = possible_values->begin(); + it != possible_values->end(); + ++it) + { + enum_node->createChild("value", false)->setStringValue(*it); + } + } + else + { + parent_node->createChild("data", false)->createChild("type", true)->setStringValue(type); + } } LLXMLNodePtr LLRNGWriter::createCardinalityNode(LLXMLNodePtr parent_node, S32 min_count, S32 max_count) { - // unlinked by default, meaning this attribute is forbidden - LLXMLNodePtr count_node = new LLXMLNode(); - if (min_count == 0) - { - if (max_count == 1) - { - count_node = parent_node->createChild("optional", false); - } - else if (max_count > 1) - { - count_node = parent_node->createChild("zeroOrMore", false); - } - } - else if (min_count >= 1) - { - if (max_count == 1 && min_count == 1) - { - // just add raw element, will count as 1 and only 1 - count_node = parent_node; - } - else - { - count_node = parent_node->createChild("oneOrMore", false); - } - } - return count_node; + // unlinked by default, meaning this attribute is forbidden + LLXMLNodePtr count_node = new LLXMLNode(); + if (min_count == 0) + { + if (max_count == 1) + { + count_node = parent_node->createChild("optional", false); + } + else if (max_count > 1) + { + count_node = parent_node->createChild("zeroOrMore", false); + } + } + else if (min_count >= 1) + { + if (max_count == 1 && min_count == 1) + { + // just add raw element, will count as 1 and only 1 + count_node = parent_node; + } + else + { + count_node = parent_node->createChild("oneOrMore", false); + } + } + return count_node; } diff --git a/indra/llui/llrngwriter.h b/indra/llui/llrngwriter.h index c33aa28613..33ec049a1a 100644 --- a/indra/llui/llrngwriter.h +++ b/indra/llui/llrngwriter.h @@ -1,25 +1,25 @@ -/** +/** * @file llrngwriter.h * @brief Generates Relax NG schema files from a param block * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,32 +32,32 @@ class LLRNGWriter : public LLInitParam::Parser { - LOG_CLASS(LLRNGWriter); + LOG_CLASS(LLRNGWriter); public: - void writeRNG(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); - void addDefinition(const std::string& type_name, const LLInitParam::BaseBlock& block); + void writeRNG(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + void addDefinition(const std::string& type_name, const LLInitParam::BaseBlock& block); - /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } - LLRNGWriter(); + LLRNGWriter(); private: - LLXMLNodePtr createCardinalityNode(LLXMLNodePtr parent_node, S32 min_count, S32 max_count); - void addTypeNode(LLXMLNodePtr parent_node, const std::string& type, const std::vector<std::string>* possible_values); - - void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); - LLXMLNodePtr mElementNode; - LLXMLNodePtr mChildrenNode; - LLXMLNodePtr mGrammarNode; - std::string mDefinitionName; - - typedef std::pair<LLXMLNodePtr, std::set<std::string> > attribute_data_t; - typedef std::map<std::string, attribute_data_t> elements_map_t; - typedef std::set<std::string> defined_elements_t; - - defined_elements_t mDefinedElements; - attribute_data_t mAttributesWritten; - elements_map_t mElementsWritten; + LLXMLNodePtr createCardinalityNode(LLXMLNodePtr parent_node, S32 min_count, S32 max_count); + void addTypeNode(LLXMLNodePtr parent_node, const std::string& type, const std::vector<std::string>* possible_values); + + void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); + LLXMLNodePtr mElementNode; + LLXMLNodePtr mChildrenNode; + LLXMLNodePtr mGrammarNode; + std::string mDefinitionName; + + typedef std::pair<LLXMLNodePtr, std::set<std::string> > attribute_data_t; + typedef std::map<std::string, attribute_data_t> elements_map_t; + typedef std::set<std::string> defined_elements_t; + + defined_elements_t mDefinedElements; + attribute_data_t mAttributesWritten; + elements_map_t mElementsWritten; }; #endif //LLRNGWRITER_H diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index b2be9fb1e1..fda4a750cd 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llscrollbar.cpp * @brief Scrollbar UI widget * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,549 +45,549 @@ static LLDefaultChildRegistry::Register<LLScrollbar> register_scrollbar("scroll_bar"); LLScrollbar::Params::Params() -: orientation ("orientation", HORIZONTAL), - doc_size ("doc_size", 0), - doc_pos ("doc_pos", 0), - page_size ("page_size", 0), - step_size ("step_size", 1), - thumb_image_vertical("thumb_image_vertical"), - thumb_image_horizontal("thumb_image_horizontal"), - track_image_vertical("track_image_vertical"), - track_image_horizontal("track_image_horizontal"), - track_color("track_color"), - thumb_color("thumb_color"), - thickness("thickness"), - up_button("up_button"), - down_button("down_button"), - left_button("left_button"), - right_button("right_button"), - bg_visible("bg_visible", false), - bg_color("bg_color", LLColor4::black) +: orientation ("orientation", HORIZONTAL), + doc_size ("doc_size", 0), + doc_pos ("doc_pos", 0), + page_size ("page_size", 0), + step_size ("step_size", 1), + thumb_image_vertical("thumb_image_vertical"), + thumb_image_horizontal("thumb_image_horizontal"), + track_image_vertical("track_image_vertical"), + track_image_horizontal("track_image_horizontal"), + track_color("track_color"), + thumb_color("thumb_color"), + thickness("thickness"), + up_button("up_button"), + down_button("down_button"), + left_button("left_button"), + right_button("right_button"), + bg_visible("bg_visible", false), + bg_color("bg_color", LLColor4::black) {} LLScrollbar::LLScrollbar(const Params & p) -: LLUICtrl(p), - mChangeCallback( p.change_callback() ), - mOrientation( p.orientation ), - mDocSize( p.doc_size ), - mDocPos( p.doc_pos ), - mPageSize( p.page_size ), - mStepSize( p.step_size ), - mDocChanged(FALSE), - mDragStartX( 0 ), - mDragStartY( 0 ), - mHoverGlowStrength(0.15f), - mCurGlowStrength(0.f), - mTrackColor( p.track_color() ), - mThumbColor ( p.thumb_color() ), - mThumbImageV(p.thumb_image_vertical), - mThumbImageH(p.thumb_image_horizontal), - mTrackImageV(p.track_image_vertical), - mTrackImageH(p.track_image_horizontal), - mThickness(p.thickness.isProvided() ? p.thickness : LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize")), - mBGVisible(p.bg_visible), - mBGColor(p.bg_color) +: LLUICtrl(p), + mChangeCallback( p.change_callback() ), + mOrientation( p.orientation ), + mDocSize( p.doc_size ), + mDocPos( p.doc_pos ), + mPageSize( p.page_size ), + mStepSize( p.step_size ), + mDocChanged(FALSE), + mDragStartX( 0 ), + mDragStartY( 0 ), + mHoverGlowStrength(0.15f), + mCurGlowStrength(0.f), + mTrackColor( p.track_color() ), + mThumbColor ( p.thumb_color() ), + mThumbImageV(p.thumb_image_vertical), + mThumbImageH(p.thumb_image_horizontal), + mTrackImageV(p.track_image_vertical), + mTrackImageH(p.track_image_horizontal), + mThickness(p.thickness.isProvided() ? p.thickness : LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize")), + mBGVisible(p.bg_visible), + mBGColor(p.bg_color) { - updateThumbRect(); - - // Page up and page down buttons - LLRect line_up_rect; - LLRect line_down_rect; - - if( VERTICAL == mOrientation ) - { - line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), mThickness, mThickness ); - line_down_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); - } - else // HORIZONTAL - { - line_up_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); - line_down_rect.setOriginAndSize( getRect().getWidth() - mThickness, 0, mThickness, mThickness ); - } - - LLButton::Params up_btn(mOrientation == VERTICAL ? p.up_button : p.left_button); - up_btn.name(std::string("Line Up")); - up_btn.rect(line_up_rect); - up_btn.click_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2)); - up_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2)); - up_btn.tab_stop(false); - up_btn.follows.flags = (mOrientation == VERTICAL ? (FOLLOWS_RIGHT | FOLLOWS_TOP) : (FOLLOWS_LEFT | FOLLOWS_BOTTOM)); - - addChild(LLUICtrlFactory::create<LLButton>(up_btn)); - - LLButton::Params down_btn(mOrientation == VERTICAL ? p.down_button : p.right_button); - down_btn.name(std::string("Line Down")); - down_btn.rect(line_down_rect); - down_btn.follows.flags(FOLLOWS_RIGHT|FOLLOWS_BOTTOM); - down_btn.click_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2)); - down_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2)); - down_btn.tab_stop(false); - - addChild(LLUICtrlFactory::create<LLButton>(down_btn)); + updateThumbRect(); + + // Page up and page down buttons + LLRect line_up_rect; + LLRect line_down_rect; + + if( VERTICAL == mOrientation ) + { + line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), mThickness, mThickness ); + line_down_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); + } + else // HORIZONTAL + { + line_up_rect.setOriginAndSize( 0, 0, mThickness, mThickness ); + line_down_rect.setOriginAndSize( getRect().getWidth() - mThickness, 0, mThickness, mThickness ); + } + + LLButton::Params up_btn(mOrientation == VERTICAL ? p.up_button : p.left_button); + up_btn.name(std::string("Line Up")); + up_btn.rect(line_up_rect); + up_btn.click_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2)); + up_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2)); + up_btn.tab_stop(false); + up_btn.follows.flags = (mOrientation == VERTICAL ? (FOLLOWS_RIGHT | FOLLOWS_TOP) : (FOLLOWS_LEFT | FOLLOWS_BOTTOM)); + + addChild(LLUICtrlFactory::create<LLButton>(up_btn)); + + LLButton::Params down_btn(mOrientation == VERTICAL ? p.down_button : p.right_button); + down_btn.name(std::string("Line Down")); + down_btn.rect(line_down_rect); + down_btn.follows.flags(FOLLOWS_RIGHT|FOLLOWS_BOTTOM); + down_btn.click_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2)); + down_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2)); + down_btn.tab_stop(false); + + addChild(LLUICtrlFactory::create<LLButton>(down_btn)); } LLScrollbar::~LLScrollbar() { - // Children buttons killed by parent class + // Children buttons killed by parent class } void LLScrollbar::setDocParams( S32 size, S32 pos ) { - mDocSize = size; - setDocPos(pos); - mDocChanged = TRUE; + mDocSize = size; + setDocPos(pos); + mDocChanged = TRUE; - updateThumbRect(); + updateThumbRect(); } // returns true if document position really changed bool LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { - pos = llclamp(pos, 0, getDocPosMax()); - if (pos != mDocPos) - { - mDocPos = pos; - mDocChanged = TRUE; - - if( mChangeCallback ) - { - mChangeCallback( mDocPos, this ); - } - - if( update_thumb ) - { - updateThumbRect(); - } - return true; - } - return false; + pos = llclamp(pos, 0, getDocPosMax()); + if (pos != mDocPos) + { + mDocPos = pos; + mDocChanged = TRUE; + + if( mChangeCallback ) + { + mChangeCallback( mDocPos, this ); + } + + if( update_thumb ) + { + updateThumbRect(); + } + return true; + } + return false; } void LLScrollbar::setDocSize(S32 size) { - if (size != mDocSize) - { - mDocSize = size; - setDocPos(mDocPos); - mDocChanged = TRUE; - - updateThumbRect(); - } + if (size != mDocSize) + { + mDocSize = size; + setDocPos(mDocPos); + mDocChanged = TRUE; + + updateThumbRect(); + } } void LLScrollbar::setPageSize( S32 page_size ) { - if (page_size != mPageSize) - { - mPageSize = page_size; - setDocPos(mDocPos); - mDocChanged = TRUE; - - updateThumbRect(); - } + if (page_size != mPageSize) + { + mPageSize = page_size; + setDocPos(mDocPos); + mDocChanged = TRUE; + + updateThumbRect(); + } } bool LLScrollbar::isAtBeginning() const { - return mDocPos == 0; + return mDocPos == 0; } bool LLScrollbar::isAtEnd() const { - return mDocPos == getDocPosMax(); + return mDocPos == getDocPosMax(); } void LLScrollbar::updateThumbRect() { -// llassert( 0 <= mDocSize ); -// llassert( 0 <= mDocPos && mDocPos <= getDocPosMax() ); - - const S32 THUMB_MIN_LENGTH = 16; - - S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); - S32 thumb_bg_length = llmax(0, window_length - 2 * mThickness); - S32 visible_lines = llmin( mDocSize, mPageSize ); - S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length; - - S32 variable_lines = mDocSize - visible_lines; - - if( mOrientation == LLScrollbar::VERTICAL ) - { - S32 thumb_start_max = thumb_bg_length + mThickness; - S32 thumb_start_min = mThickness + THUMB_MIN_LENGTH; - S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max; - - mThumbRect.mLeft = 0; - mThumbRect.mTop = thumb_start; - mThumbRect.mRight = mThickness; - mThumbRect.mBottom = thumb_start - thumb_length; - } - else - { - // Horizontal - S32 thumb_start_max = thumb_bg_length + mThickness - thumb_length; - S32 thumb_start_min = mThickness; - S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min; - - mThumbRect.mLeft = thumb_start; - mThumbRect.mTop = mThickness; - mThumbRect.mRight = thumb_start + thumb_length; - mThumbRect.mBottom = 0; - } +// llassert( 0 <= mDocSize ); +// llassert( 0 <= mDocPos && mDocPos <= getDocPosMax() ); + + const S32 THUMB_MIN_LENGTH = 16; + + S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); + S32 thumb_bg_length = llmax(0, window_length - 2 * mThickness); + S32 visible_lines = llmin( mDocSize, mPageSize ); + S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length; + + S32 variable_lines = mDocSize - visible_lines; + + if( mOrientation == LLScrollbar::VERTICAL ) + { + S32 thumb_start_max = thumb_bg_length + mThickness; + S32 thumb_start_min = mThickness + THUMB_MIN_LENGTH; + S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max; + + mThumbRect.mLeft = 0; + mThumbRect.mTop = thumb_start; + mThumbRect.mRight = mThickness; + mThumbRect.mBottom = thumb_start - thumb_length; + } + else + { + // Horizontal + S32 thumb_start_max = thumb_bg_length + mThickness - thumb_length; + S32 thumb_start_min = mThickness; + S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min; + + mThumbRect.mLeft = thumb_start; + mThumbRect.mTop = mThickness; + mThumbRect.mRight = thumb_start + thumb_length; + mThumbRect.mBottom = 0; + } } BOOL LLScrollbar::handleMouseDown(S32 x, S32 y, MASK mask) { - // Check children first - BOOL handled_by_child = LLView::childrenHandleMouseDown(x, y, mask) != NULL; - if( !handled_by_child ) - { - if( mThumbRect.pointInRect(x,y) ) - { - // Start dragging the thumb - // No handler needed for focus lost since this clas has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - mDragStartX = x; - mDragStartY = y; - mOrigRect.mTop = mThumbRect.mTop; - mOrigRect.mBottom = mThumbRect.mBottom; - mOrigRect.mLeft = mThumbRect.mLeft; - mOrigRect.mRight = mThumbRect.mRight; - mLastDelta = 0; - } - else - { - if( - ( (LLScrollbar::VERTICAL == mOrientation) && (mThumbRect.mTop < y) ) || - ( (LLScrollbar::HORIZONTAL == mOrientation) && (x < mThumbRect.mLeft) ) - ) - { - // Page up - pageUp(0); - } - else - if( - ( (LLScrollbar::VERTICAL == mOrientation) && (y < mThumbRect.mBottom) ) || - ( (LLScrollbar::HORIZONTAL == mOrientation) && (mThumbRect.mRight < x) ) - ) - { - // Page down - pageDown(0); - } - } - } - - return TRUE; + // Check children first + BOOL handled_by_child = LLView::childrenHandleMouseDown(x, y, mask) != NULL; + if( !handled_by_child ) + { + if( mThumbRect.pointInRect(x,y) ) + { + // Start dragging the thumb + // No handler needed for focus lost since this clas has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + mDragStartX = x; + mDragStartY = y; + mOrigRect.mTop = mThumbRect.mTop; + mOrigRect.mBottom = mThumbRect.mBottom; + mOrigRect.mLeft = mThumbRect.mLeft; + mOrigRect.mRight = mThumbRect.mRight; + mLastDelta = 0; + } + else + { + if( + ( (LLScrollbar::VERTICAL == mOrientation) && (mThumbRect.mTop < y) ) || + ( (LLScrollbar::HORIZONTAL == mOrientation) && (x < mThumbRect.mLeft) ) + ) + { + // Page up + pageUp(0); + } + else + if( + ( (LLScrollbar::VERTICAL == mOrientation) && (y < mThumbRect.mBottom) ) || + ( (LLScrollbar::HORIZONTAL == mOrientation) && (mThumbRect.mRight < x) ) + ) + { + // Page down + pageDown(0); + } + } + } + + return TRUE; } BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) { - // Note: we don't bother sending the event to the children (the arrow buttons) - // because they'll capture the mouse whenever they need hover events. - - BOOL handled = FALSE; - if( hasMouseCapture() ) - { - S32 height = getRect().getHeight(); - S32 width = getRect().getWidth(); - - if( VERTICAL == mOrientation ) - { -// S32 old_pos = mThumbRect.mTop; - - S32 delta_pixels = y - mDragStartY; - if( mOrigRect.mBottom + delta_pixels < mThickness ) - { - delta_pixels = mThickness - mOrigRect.mBottom - 1; - } - else - if( mOrigRect.mTop + delta_pixels > height - mThickness ) - { - delta_pixels = height - mThickness - mOrigRect.mTop + 1; - } - - mThumbRect.mTop = mOrigRect.mTop + delta_pixels; - mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels; - - S32 thumb_length = mThumbRect.getHeight(); - S32 thumb_track_length = height - 2 * mThickness; - - - if( delta_pixels != mLastDelta || mDocChanged) - { - // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). - S32 usable_track_length = thumb_track_length - thumb_length; - if( 0 < usable_track_length ) - { - S32 variable_lines = getDocPosMax(); - S32 pos = mThumbRect.mTop; - F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length; - - S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ); - // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly - // out of sync (less than a line's worth) to make the thumb feel responsive. - changeLine( new_pos - mDocPos, FALSE ); - } - } - - mLastDelta = delta_pixels; - - } - else - { - // Horizontal -// S32 old_pos = mThumbRect.mLeft; - - S32 delta_pixels = x - mDragStartX; - - if( mOrigRect.mLeft + delta_pixels < mThickness ) - { - delta_pixels = mThickness - mOrigRect.mLeft - 1; - } - else - if( mOrigRect.mRight + delta_pixels > width - mThickness ) - { - delta_pixels = width - mThickness - mOrigRect.mRight + 1; - } - - mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels; - mThumbRect.mRight = mOrigRect.mRight + delta_pixels; - - S32 thumb_length = mThumbRect.getWidth(); - S32 thumb_track_length = width - 2 * mThickness; - - if( delta_pixels != mLastDelta || mDocChanged) - { - // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). - S32 usable_track_length = thumb_track_length - thumb_length; - if( 0 < usable_track_length ) - { - S32 variable_lines = getDocPosMax(); - S32 pos = mThumbRect.mLeft; - F32 ratio = F32(pos - mThickness) / usable_track_length; - - S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines); - - // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly - // out of sync (less than a line's worth) to make the thumb feel responsive. - changeLine( new_pos - mDocPos, FALSE ); - } - } - - mLastDelta = delta_pixels; - } - - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - handled = TRUE; - } - else - { - handled = childrenHandleHover( x, y, mask ) != NULL; - } - - // Opaque - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; - handled = TRUE; - } - - mDocChanged = FALSE; - return handled; + // Note: we don't bother sending the event to the children (the arrow buttons) + // because they'll capture the mouse whenever they need hover events. + + BOOL handled = FALSE; + if( hasMouseCapture() ) + { + S32 height = getRect().getHeight(); + S32 width = getRect().getWidth(); + + if( VERTICAL == mOrientation ) + { +// S32 old_pos = mThumbRect.mTop; + + S32 delta_pixels = y - mDragStartY; + if( mOrigRect.mBottom + delta_pixels < mThickness ) + { + delta_pixels = mThickness - mOrigRect.mBottom - 1; + } + else + if( mOrigRect.mTop + delta_pixels > height - mThickness ) + { + delta_pixels = height - mThickness - mOrigRect.mTop + 1; + } + + mThumbRect.mTop = mOrigRect.mTop + delta_pixels; + mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels; + + S32 thumb_length = mThumbRect.getHeight(); + S32 thumb_track_length = height - 2 * mThickness; + + + if( delta_pixels != mLastDelta || mDocChanged) + { + // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). + S32 usable_track_length = thumb_track_length - thumb_length; + if( 0 < usable_track_length ) + { + S32 variable_lines = getDocPosMax(); + S32 pos = mThumbRect.mTop; + F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length; + + S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ); + // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly + // out of sync (less than a line's worth) to make the thumb feel responsive. + changeLine( new_pos - mDocPos, FALSE ); + } + } + + mLastDelta = delta_pixels; + + } + else + { + // Horizontal +// S32 old_pos = mThumbRect.mLeft; + + S32 delta_pixels = x - mDragStartX; + + if( mOrigRect.mLeft + delta_pixels < mThickness ) + { + delta_pixels = mThickness - mOrigRect.mLeft - 1; + } + else + if( mOrigRect.mRight + delta_pixels > width - mThickness ) + { + delta_pixels = width - mThickness - mOrigRect.mRight + 1; + } + + mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels; + mThumbRect.mRight = mOrigRect.mRight + delta_pixels; + + S32 thumb_length = mThumbRect.getWidth(); + S32 thumb_track_length = width - 2 * mThickness; + + if( delta_pixels != mLastDelta || mDocChanged) + { + // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). + S32 usable_track_length = thumb_track_length - thumb_length; + if( 0 < usable_track_length ) + { + S32 variable_lines = getDocPosMax(); + S32 pos = mThumbRect.mLeft; + F32 ratio = F32(pos - mThickness) / usable_track_length; + + S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines); + + // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly + // out of sync (less than a line's worth) to make the thumb feel responsive. + changeLine( new_pos - mDocPos, FALSE ); + } + } + + mLastDelta = delta_pixels; + } + + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + handled = TRUE; + } + else + { + handled = childrenHandleHover( x, y, mask ) != NULL; + } + + // Opaque + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + handled = TRUE; + } + + mDocChanged = FALSE; + return handled; } // end handleHover BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks) { - BOOL handled = changeLine( clicks * mStepSize, TRUE ); - return handled; + BOOL handled = changeLine( clicks * mStepSize, TRUE ); + return handled; } BOOL LLScrollbar::handleScrollHWheel(S32 x, S32 y, S32 clicks) { - BOOL handled = FALSE; - if (LLScrollbar::HORIZONTAL == mOrientation) - { - handled = changeLine(clicks * mStepSize, TRUE); - } - return handled; + BOOL handled = FALSE; + if (LLScrollbar::HORIZONTAL == mOrientation) + { + handled = changeLine(clicks * mStepSize, TRUE); + } + return handled; } BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg) + EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg) { - // enable this to get drag and drop to control scrollbars - //if (!drop) - //{ - // //TODO: refactor this - // S32 variable_lines = getDocPosMax(); - // S32 pos = (VERTICAL == mOrientation) ? y : x; - // S32 thumb_length = (VERTICAL == mOrientation) ? mThumbRect.getHeight() : mThumbRect.getWidth(); - // S32 thumb_track_length = (VERTICAL == mOrientation) ? (getRect().getHeight() - 2 * SCROLLBAR_SIZE) : (getRect().getWidth() - 2 * SCROLLBAR_SIZE); - // S32 usable_track_length = thumb_track_length - thumb_length; - // F32 ratio = (VERTICAL == mOrientation) ? F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length - // : F32(pos - SCROLLBAR_SIZE) / usable_track_length; - // S32 new_pos = (VERTICAL == mOrientation) ? llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ) - // : llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines ); - // changeLine( new_pos - mDocPos, TRUE ); - //} - //return TRUE; - return FALSE; + // enable this to get drag and drop to control scrollbars + //if (!drop) + //{ + // //TODO: refactor this + // S32 variable_lines = getDocPosMax(); + // S32 pos = (VERTICAL == mOrientation) ? y : x; + // S32 thumb_length = (VERTICAL == mOrientation) ? mThumbRect.getHeight() : mThumbRect.getWidth(); + // S32 thumb_track_length = (VERTICAL == mOrientation) ? (getRect().getHeight() - 2 * SCROLLBAR_SIZE) : (getRect().getWidth() - 2 * SCROLLBAR_SIZE); + // S32 usable_track_length = thumb_track_length - thumb_length; + // F32 ratio = (VERTICAL == mOrientation) ? F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length + // : F32(pos - SCROLLBAR_SIZE) / usable_track_length; + // S32 new_pos = (VERTICAL == mOrientation) ? llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ) + // : llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines ); + // changeLine( new_pos - mDocPos, TRUE ); + //} + //return TRUE; + return FALSE; } BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - handled = TRUE; - } - else - { - // Opaque, so don't just check children - handled = LLView::handleMouseUp( x, y, mask ); - } - - return handled; + BOOL handled = FALSE; + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + handled = TRUE; + } + else + { + // Opaque, so don't just check children + handled = LLView::handleMouseUp( x, y, mask ); + } + + return handled; } BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask) { - // just treat a double click as a second click - return handleMouseDown(x, y, mask); + // just treat a double click as a second click + return handleMouseDown(x, y, mask); } void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) { - if (width == getRect().getWidth() && height == getRect().getHeight()) return; - LLView::reshape( width, height, called_from_parent ); - LLButton* up_button = getChild<LLButton>("Line Up"); - LLButton* down_button = getChild<LLButton>("Line Down"); - - if (mOrientation == VERTICAL) - { - up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); - down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); - up_button->setOrigin(0, getRect().getHeight() - up_button->getRect().getHeight()); - down_button->setOrigin(0, 0); - } - else - { - up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight()); - down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight()); - up_button->setOrigin(0, 0); - down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), 0); - } - updateThumbRect(); + if (width == getRect().getWidth() && height == getRect().getHeight()) return; + LLView::reshape( width, height, called_from_parent ); + LLButton* up_button = getChild<LLButton>("Line Up"); + LLButton* down_button = getChild<LLButton>("Line Down"); + + if (mOrientation == VERTICAL) + { + up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); + down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); + up_button->setOrigin(0, getRect().getHeight() - up_button->getRect().getHeight()); + down_button->setOrigin(0, 0); + } + else + { + up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight()); + down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight()); + up_button->setOrigin(0, 0); + down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), 0); + } + updateThumbRect(); } void LLScrollbar::draw() { - if (!getRect().isValid()) return; - - if(mBGVisible) - { - gl_rect_2d(getLocalRect(), mBGColor.get(), TRUE); - } - - S32 local_mouse_x; - S32 local_mouse_y; - LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); - BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this; - BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); - if (hovered) - { - mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLSmoothInterpolation::getInterpolant(0.05f)); - } - else - { - mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); - } - - // Draw background and thumb. - if ( ( mOrientation == VERTICAL&&(mThumbImageV.isNull() || mThumbImageH.isNull()) ) - || (mOrientation == HORIZONTAL&&(mTrackImageH.isNull() || mTrackImageV.isNull()) )) - { - gl_rect_2d(mOrientation == HORIZONTAL ? mThickness : 0, - mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(), - mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), - mOrientation == VERTICAL ? mThickness : 0, mTrackColor.get(), TRUE); - - gl_rect_2d(mThumbRect, mThumbColor.get(), TRUE); - - } - else - { - // Thumb - LLRect outline_rect = mThumbRect; - outline_rect.stretch(2); - // Background - - if(mOrientation == HORIZONTAL) - { - mTrackImageH->drawSolid(mThickness //S32 x - , 0 //S32 y - , getRect().getWidth() - 2 * mThickness //S32 width - , getRect().getHeight() //S32 height - , mTrackColor.get()); //const LLColor4& color - - if (gFocusMgr.getKeyboardFocus() == this) - { - mTrackImageH->draw(outline_rect, gFocusMgr.getFocusColor()); - } - - mThumbImageH->draw(mThumbRect, mThumbColor.get()); - if (mCurGlowStrength > 0.01f) - { - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - mThumbImageH->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength)); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - - } - else if(mOrientation == VERTICAL) - { - mTrackImageV->drawSolid( 0 //S32 x - , mThickness //S32 y - , getRect().getWidth() //S32 width - , getRect().getHeight() - 2 * mThickness //S32 height - , mTrackColor.get()); //const LLColor4& color - if (gFocusMgr.getKeyboardFocus() == this) - { - mTrackImageV->draw(outline_rect, gFocusMgr.getFocusColor()); - } - - mThumbImageV->draw(mThumbRect, mThumbColor.get()); - if (mCurGlowStrength > 0.01f) - { - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - mThumbImageV->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength)); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - } - - // Draw children - LLView::draw(); + if (!getRect().isValid()) return; + + if(mBGVisible) + { + gl_rect_2d(getLocalRect(), mBGColor.get(), TRUE); + } + + S32 local_mouse_x; + S32 local_mouse_y; + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this; + BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); + if (hovered) + { + mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLSmoothInterpolation::getInterpolant(0.05f)); + } + else + { + mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); + } + + // Draw background and thumb. + if ( ( mOrientation == VERTICAL&&(mThumbImageV.isNull() || mThumbImageH.isNull()) ) + || (mOrientation == HORIZONTAL&&(mTrackImageH.isNull() || mTrackImageV.isNull()) )) + { + gl_rect_2d(mOrientation == HORIZONTAL ? mThickness : 0, + mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(), + mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), + mOrientation == VERTICAL ? mThickness : 0, mTrackColor.get(), TRUE); + + gl_rect_2d(mThumbRect, mThumbColor.get(), TRUE); + + } + else + { + // Thumb + LLRect outline_rect = mThumbRect; + outline_rect.stretch(2); + // Background + + if(mOrientation == HORIZONTAL) + { + mTrackImageH->drawSolid(mThickness //S32 x + , 0 //S32 y + , getRect().getWidth() - 2 * mThickness //S32 width + , getRect().getHeight() //S32 height + , mTrackColor.get()); //const LLColor4& color + + if (gFocusMgr.getKeyboardFocus() == this) + { + mTrackImageH->draw(outline_rect, gFocusMgr.getFocusColor()); + } + + mThumbImageH->draw(mThumbRect, mThumbColor.get()); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + mThumbImageH->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + } + else if(mOrientation == VERTICAL) + { + mTrackImageV->drawSolid( 0 //S32 x + , mThickness //S32 y + , getRect().getWidth() //S32 width + , getRect().getHeight() - 2 * mThickness //S32 height + , mTrackColor.get()); //const LLColor4& color + if (gFocusMgr.getKeyboardFocus() == this) + { + mTrackImageV->draw(outline_rect, gFocusMgr.getFocusColor()); + } + + mThumbImageV->draw(mThumbRect, mThumbColor.get()); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + mThumbImageV->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + } + + // Draw children + LLView::draw(); } // end draw bool LLScrollbar::changeLine( S32 delta, BOOL update_thumb ) { - return setDocPos(mDocPos + delta, update_thumb); + return setDocPos(mDocPos + delta, update_thumb); } -void LLScrollbar::setValue(const LLSD& value) -{ - setDocPos((S32) value.asInteger()); +void LLScrollbar::setValue(const LLSD& value) +{ + setDocPos((S32) value.asInteger()); } @@ -600,67 +600,67 @@ BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask) BOOL handled = FALSE; - switch( key ) - { - case KEY_HOME: - setDocPos( 0 ); - handled = TRUE; - break; - - case KEY_END: - setDocPos( getDocPosMax() ); - handled = TRUE; - break; - - case KEY_DOWN: - setDocPos( getDocPos() + mStepSize ); - handled = TRUE; - break; - - case KEY_UP: - setDocPos( getDocPos() - mStepSize ); - handled = TRUE; - break; - - case KEY_PAGE_DOWN: - pageDown(1); - break; - - case KEY_PAGE_UP: - pageUp(1); - break; - } - - return handled; + switch( key ) + { + case KEY_HOME: + setDocPos( 0 ); + handled = TRUE; + break; + + case KEY_END: + setDocPos( getDocPosMax() ); + handled = TRUE; + break; + + case KEY_DOWN: + setDocPos( getDocPos() + mStepSize ); + handled = TRUE; + break; + + case KEY_UP: + setDocPos( getDocPos() - mStepSize ); + handled = TRUE; + break; + + case KEY_PAGE_DOWN: + pageDown(1); + break; + + case KEY_PAGE_UP: + pageUp(1); + break; + } + + return handled; } void LLScrollbar::pageUp(S32 overlap) { - if (mDocSize > mPageSize) - { - changeLine( -(mPageSize - overlap), TRUE ); - } + if (mDocSize > mPageSize) + { + changeLine( -(mPageSize - overlap), TRUE ); + } } void LLScrollbar::pageDown(S32 overlap) { - if (mDocSize > mPageSize) - { - changeLine( mPageSize - overlap, TRUE ); - } + if (mDocSize > mPageSize) + { + changeLine( mPageSize - overlap, TRUE ); + } } void LLScrollbar::onLineUpBtnPressed( const LLSD& data ) { - changeLine( -mStepSize, TRUE ); + changeLine( -mStepSize, TRUE ); } void LLScrollbar::onLineDownBtnPressed( const LLSD& data ) { - changeLine( mStepSize, TRUE ); + changeLine( mStepSize, TRUE ); } void LLScrollbar::setThickness(S32 thickness) { - mThickness = thickness < 0 ? LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize") : thickness; + mThickness = thickness < 0 ? LLUI::getInstance()->mSettingGroups["config"]->getS32("UIScrollbarSize") : thickness; } diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 9be9d22db8..bbfc3a0340 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -1,25 +1,25 @@ -/** +/** * @file llscrollbar.h * @brief Scrollbar UI widget * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,127 +40,127 @@ class LLScrollbar { public: - typedef boost::function<void (S32, LLScrollbar*)> callback_t; - struct Params - : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Mandatory<EOrientation> orientation; - Mandatory<S32> doc_size; - Mandatory<S32> doc_pos; - Mandatory<S32> page_size; + typedef boost::function<void (S32, LLScrollbar*)> callback_t; + struct Params + : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Mandatory<EOrientation> orientation; + Mandatory<S32> doc_size; + Mandatory<S32> doc_pos; + Mandatory<S32> page_size; - Optional<callback_t> change_callback; - Optional<S32> step_size; - Optional<S32> thickness; + Optional<callback_t> change_callback; + Optional<S32> step_size; + Optional<S32> thickness; - Optional<LLUIImage*> thumb_image_vertical, - thumb_image_horizontal, - track_image_horizontal, - track_image_vertical; + Optional<LLUIImage*> thumb_image_vertical, + thumb_image_horizontal, + track_image_horizontal, + track_image_vertical; - Optional<bool> bg_visible; + Optional<bool> bg_visible; - Optional<LLUIColor> track_color, - thumb_color, - bg_color; + Optional<LLUIColor> track_color, + thumb_color, + bg_color; - Optional<LLButton::Params> up_button; - Optional<LLButton::Params> down_button; - Optional<LLButton::Params> left_button; - Optional<LLButton::Params> right_button; + Optional<LLButton::Params> up_button; + Optional<LLButton::Params> down_button; + Optional<LLButton::Params> left_button; + Optional<LLButton::Params> right_button; - Params(); - }; + Params(); + }; protected: - LLScrollbar (const Params & p); - friend class LLUICtrlFactory; + LLScrollbar (const Params & p); + friend class LLUICtrlFactory; public: - virtual ~LLScrollbar(); + virtual ~LLScrollbar(); + + virtual void setValue(const LLSD& value); - virtual void setValue(const LLSD& value); + // Overrides from LLView + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg); - // Overrides from LLView - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void draw(); - virtual void draw(); + // How long the "document" is. + void setDocSize( S32 size ); + S32 getDocSize() const { return mDocSize; } - // How long the "document" is. - void setDocSize( S32 size ); - S32 getDocSize() const { return mDocSize; } + // How many "lines" the "document" has scrolled. + // 0 <= DocPos <= DocSize - DocVisibile + bool setDocPos( S32 pos, BOOL update_thumb = TRUE ); + S32 getDocPos() const { return mDocPos; } - // How many "lines" the "document" has scrolled. - // 0 <= DocPos <= DocSize - DocVisibile - bool setDocPos( S32 pos, BOOL update_thumb = TRUE ); - S32 getDocPos() const { return mDocPos; } + bool isAtBeginning() const; + bool isAtEnd() const; - bool isAtBeginning() const; - bool isAtEnd() const; + // Setting both at once. + void setDocParams( S32 size, S32 pos ); - // Setting both at once. - void setDocParams( S32 size, S32 pos ); + // How many "lines" of the "document" is can appear on a page. + void setPageSize( S32 page_size ); + S32 getPageSize() const { return mPageSize; } - // How many "lines" of the "document" is can appear on a page. - void setPageSize( S32 page_size ); - S32 getPageSize() const { return mPageSize; } - - // The farthest the document can be scrolled (top of the last page). - S32 getDocPosMax() const { return llmax( 0, mDocSize - mPageSize); } + // The farthest the document can be scrolled (top of the last page). + S32 getDocPosMax() const { return llmax( 0, mDocSize - mPageSize); } - void pageUp(S32 overlap); - void pageDown(S32 overlap); + void pageUp(S32 overlap); + void pageDown(S32 overlap); - void onLineUpBtnPressed(const LLSD& data); - void onLineDownBtnPressed(const LLSD& data); + void onLineUpBtnPressed(const LLSD& data); + void onLineDownBtnPressed(const LLSD& data); - S32 getThickness() const { return mThickness; } - void setThickness(S32 thickness); + S32 getThickness() const { return mThickness; } + void setThickness(S32 thickness); private: - void updateThumbRect(); - bool changeLine(S32 delta, BOOL update_thumb ); + void updateThumbRect(); + bool changeLine(S32 delta, BOOL update_thumb ); - callback_t mChangeCallback; + callback_t mChangeCallback; - const EOrientation mOrientation; - S32 mDocSize; // Size of the document that the scrollbar is modeling. Units depend on the user. 0 <= mDocSize. - S32 mDocPos; // Position within the doc that the scrollbar is modeling, in "lines" (user size) - S32 mPageSize; // Maximum number of lines that can be seen at one time. - S32 mStepSize; - BOOL mDocChanged; + const EOrientation mOrientation; + S32 mDocSize; // Size of the document that the scrollbar is modeling. Units depend on the user. 0 <= mDocSize. + S32 mDocPos; // Position within the doc that the scrollbar is modeling, in "lines" (user size) + S32 mPageSize; // Maximum number of lines that can be seen at one time. + S32 mStepSize; + BOOL mDocChanged; - LLRect mThumbRect; - S32 mDragStartX; - S32 mDragStartY; - F32 mHoverGlowStrength; - F32 mCurGlowStrength; + LLRect mThumbRect; + S32 mDragStartX; + S32 mDragStartY; + F32 mHoverGlowStrength; + F32 mCurGlowStrength; - LLRect mOrigRect; - S32 mLastDelta; + LLRect mOrigRect; + S32 mLastDelta; - LLUIColor mTrackColor; - LLUIColor mThumbColor; - LLUIColor mBGColor; + LLUIColor mTrackColor; + LLUIColor mThumbColor; + LLUIColor mBGColor; - bool mBGVisible; + bool mBGVisible; - LLUIImagePtr mThumbImageV; - LLUIImagePtr mThumbImageH; - LLUIImagePtr mTrackImageV; - LLUIImagePtr mTrackImageH; + LLUIImagePtr mThumbImageV; + LLUIImagePtr mThumbImageH; + LLUIImagePtr mTrackImageV; + LLUIImagePtr mTrackImageH; - S32 mThickness; + S32 mThickness; }; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 22d27b1f2a..d0b28e8f22 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llscrollcontainer.cpp * @brief LLScrollContainer base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,144 +66,144 @@ static ScrollContainerRegistry::Register<LLContainerView> r2("container_view"); static ScrollContainerRegistry::Register<LLPanel> r3("panel", &LLPanel::fromXML); LLScrollContainer::Params::Params() -: is_opaque("opaque"), - bg_color("color"), - border_visible("border_visible"), - hide_scrollbar("hide_scrollbar"), - ignore_arrow_keys("ignore_arrow_keys"), - min_auto_scroll_rate("min_auto_scroll_rate", 100), - max_auto_scroll_rate("max_auto_scroll_rate", 1000), - max_auto_scroll_zone("max_auto_scroll_zone", 16), - reserve_scroll_corner("reserve_scroll_corner", false), - size("size", -1) +: is_opaque("opaque"), + bg_color("color"), + border_visible("border_visible"), + hide_scrollbar("hide_scrollbar"), + ignore_arrow_keys("ignore_arrow_keys"), + min_auto_scroll_rate("min_auto_scroll_rate", 100), + max_auto_scroll_rate("max_auto_scroll_rate", 1000), + max_auto_scroll_zone("max_auto_scroll_zone", 16), + reserve_scroll_corner("reserve_scroll_corner", false), + size("size", -1) {} // Default constructor LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p) -: LLUICtrl(p), - mAutoScrolling( FALSE ), - mAutoScrollRate( 0.f ), - mBackgroundColor(p.bg_color()), - mIsOpaque(p.is_opaque), - mHideScrollbar(p.hide_scrollbar), - mIgnoreArrowKeys(p.ignore_arrow_keys), - mReserveScrollCorner(p.reserve_scroll_corner), - mMinAutoScrollRate(p.min_auto_scroll_rate), - mMaxAutoScrollRate(p.max_auto_scroll_rate), - mMaxAutoScrollZone(p.max_auto_scroll_zone), - mScrolledView(NULL), - mSize(p.size) +: LLUICtrl(p), + mAutoScrolling( FALSE ), + mAutoScrollRate( 0.f ), + mBackgroundColor(p.bg_color()), + mIsOpaque(p.is_opaque), + mHideScrollbar(p.hide_scrollbar), + mIgnoreArrowKeys(p.ignore_arrow_keys), + mReserveScrollCorner(p.reserve_scroll_corner), + mMinAutoScrollRate(p.min_auto_scroll_rate), + mMaxAutoScrollRate(p.max_auto_scroll_rate), + mMaxAutoScrollZone(p.max_auto_scroll_zone), + mScrolledView(NULL), + mSize(p.size) { - static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); - S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); - - LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - LLViewBorder::Params params; - params.name("scroll border"); - params.rect(border_rect); - params.visible(p.border_visible); - params.bevel_style(LLViewBorder::BEVEL_IN); - mBorder = LLUICtrlFactory::create<LLViewBorder> (params); - LLView::addChild( mBorder ); - - mInnerRect = getLocalRect(); - mInnerRect.stretch( -getBorderWidth() ); - - LLRect vertical_scroll_rect = mInnerRect; - vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size; - LLScrollbar::Params sbparams; - sbparams.name("scrollable vertical"); - sbparams.rect(vertical_scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(mInnerRect.getHeight()); - sbparams.doc_pos(0); - sbparams.page_size(mInnerRect.getHeight()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.visible(false); - sbparams.change_callback(p.scroll_callback); - mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams); - LLView::addChild( mScrollbar[VERTICAL] ); - - LLRect horizontal_scroll_rect; - horizontal_scroll_rect.mTop = scrollbar_size; - horizontal_scroll_rect.mRight = mInnerRect.getWidth(); - sbparams.name("scrollable horizontal"); - sbparams.rect(horizontal_scroll_rect); - sbparams.orientation(LLScrollbar::HORIZONTAL); - sbparams.doc_size(mInnerRect.getWidth()); - sbparams.doc_pos(0); - sbparams.page_size(mInnerRect.getWidth()); - sbparams.step_size(VERTICAL_MULTIPLE); - sbparams.visible(false); - sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); - sbparams.change_callback(p.scroll_callback); - mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams); - LLView::addChild( mScrollbar[HORIZONTAL] ); + static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); + S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); + + LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + LLViewBorder::Params params; + params.name("scroll border"); + params.rect(border_rect); + params.visible(p.border_visible); + params.bevel_style(LLViewBorder::BEVEL_IN); + mBorder = LLUICtrlFactory::create<LLViewBorder> (params); + LLView::addChild( mBorder ); + + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); + + LLRect vertical_scroll_rect = mInnerRect; + vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size; + LLScrollbar::Params sbparams; + sbparams.name("scrollable vertical"); + sbparams.rect(vertical_scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(mInnerRect.getHeight()); + sbparams.doc_pos(0); + sbparams.page_size(mInnerRect.getHeight()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.visible(false); + sbparams.change_callback(p.scroll_callback); + mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams); + LLView::addChild( mScrollbar[VERTICAL] ); + + LLRect horizontal_scroll_rect; + horizontal_scroll_rect.mTop = scrollbar_size; + horizontal_scroll_rect.mRight = mInnerRect.getWidth(); + sbparams.name("scrollable horizontal"); + sbparams.rect(horizontal_scroll_rect); + sbparams.orientation(LLScrollbar::HORIZONTAL); + sbparams.doc_size(mInnerRect.getWidth()); + sbparams.doc_pos(0); + sbparams.page_size(mInnerRect.getWidth()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.visible(false); + sbparams.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + sbparams.change_callback(p.scroll_callback); + mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams); + LLView::addChild( mScrollbar[HORIZONTAL] ); } // Destroys the object LLScrollContainer::~LLScrollContainer( void ) { - // mScrolledView and mScrollbar are child views, so the LLView - // destructor takes care of memory deallocation. - for( S32 i = 0; i < ORIENTATION_COUNT; i++ ) - { - mScrollbar[i] = NULL; - } - mScrolledView = NULL; + // mScrolledView and mScrollbar are child views, so the LLView + // destructor takes care of memory deallocation. + for( S32 i = 0; i < ORIENTATION_COUNT; i++ ) + { + mScrollbar[i] = NULL; + } + mScrolledView = NULL; } // internal scrollbar handlers // virtual void LLScrollContainer::scrollHorizontal( S32 new_pos ) { - if( mScrolledView ) - { - LLRect doc_rect = mScrolledView->getRect(); - S32 old_pos = -(doc_rect.mLeft - mInnerRect.mLeft); - mScrolledView->translate( -(new_pos - old_pos), 0 ); - } + if( mScrolledView ) + { + LLRect doc_rect = mScrolledView->getRect(); + S32 old_pos = -(doc_rect.mLeft - mInnerRect.mLeft); + mScrolledView->translate( -(new_pos - old_pos), 0 ); + } } // virtual void LLScrollContainer::scrollVertical( S32 new_pos ) { - if( mScrolledView ) - { - LLRect doc_rect = mScrolledView->getRect(); - S32 old_pos = doc_rect.mTop - mInnerRect.mTop; - mScrolledView->translate( 0, new_pos - old_pos ); - } + if( mScrolledView ) + { + LLRect doc_rect = mScrolledView->getRect(); + S32 old_pos = doc_rect.mTop - mInnerRect.mTop; + mScrolledView->translate( 0, new_pos - old_pos ); + } } // LLView functionality void LLScrollContainer::reshape(S32 width, S32 height, - BOOL called_from_parent) + BOOL called_from_parent) { - LLUICtrl::reshape( width, height, called_from_parent ); + LLUICtrl::reshape( width, height, called_from_parent ); - mInnerRect = getLocalRect(); - mInnerRect.stretch( -getBorderWidth() ); + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); - if (mScrolledView) - { - const LLRect& scrolled_rect = mScrolledView->getRect(); + if (mScrolledView) + { + const LLRect& scrolled_rect = mScrolledView->getRect(); - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_v_scrollbar = FALSE; + BOOL show_h_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); - mScrollbar[VERTICAL]->setPageSize( visible_height ); + mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); + mScrollbar[VERTICAL]->setPageSize( visible_height ); - mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); - mScrollbar[HORIZONTAL]->setPageSize( visible_width ); - updateScroll(); - } + mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); + mScrollbar[HORIZONTAL]->setPageSize( visible_width ); + updateScroll(); + } } // virtual @@ -227,576 +227,576 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask) } } - // allow scrolled view to handle keystrokes in case it delegated keyboard focus - // to the scroll container. - // NOTE: this should not recurse indefinitely as handleKeyHere - // should not propagate to parent controls, so mScrolledView should *not* - // call LLScrollContainer::handleKeyHere in turn - if (mScrolledView && mScrolledView->handleKeyHere(key, mask)) - { - return TRUE; - } - for( S32 i = 0; i < ORIENTATION_COUNT; i++ ) - { - if( mScrollbar[i]->handleKeyHere(key, mask) ) - { - updateScroll(); - return TRUE; - } - } - - return FALSE; + // allow scrolled view to handle keystrokes in case it delegated keyboard focus + // to the scroll container. + // NOTE: this should not recurse indefinitely as handleKeyHere + // should not propagate to parent controls, so mScrolledView should *not* + // call LLScrollContainer::handleKeyHere in turn + if (mScrolledView && mScrolledView->handleKeyHere(key, mask)) + { + return TRUE; + } + for( S32 i = 0; i < ORIENTATION_COUNT; i++ ) + { + if( mScrollbar[i]->handleKeyHere(key, mask) ) + { + updateScroll(); + return TRUE; + } + } + + return FALSE; } BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char) { - if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) - { - return TRUE; - } - return FALSE; + if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) + { + return TRUE; + } + return FALSE; } BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - // Give event to my child views - they may have scroll bars - // (Bad UI design, but technically possible.) - if (LLUICtrl::handleScrollWheel(x,y,clicks)) - return TRUE; - - // When the vertical scrollbar is visible, scroll wheel - // only affects vertical scrolling. It's confusing to have - // scroll wheel perform both vertical and horizontal in a - // single container. - LLScrollbar* vertical = mScrollbar[VERTICAL]; - if (vertical->getVisible() - && vertical->getEnabled()) - { - // Pretend the mouse is over the scrollbar - if (vertical->handleScrollWheel( 0, 0, clicks ) ) - { - updateScroll(); - } - // Always eat the event - return TRUE; - } - - LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; - // Test enablement and visibility for consistency with - // LLView::childrenHandleScrollWheel(). - if (horizontal->getVisible() - && horizontal->getEnabled() - && horizontal->handleScrollWheel( 0, 0, clicks ) ) - { - updateScroll(); - return TRUE; - } - return FALSE; + // Give event to my child views - they may have scroll bars + // (Bad UI design, but technically possible.) + if (LLUICtrl::handleScrollWheel(x,y,clicks)) + return TRUE; + + // When the vertical scrollbar is visible, scroll wheel + // only affects vertical scrolling. It's confusing to have + // scroll wheel perform both vertical and horizontal in a + // single container. + LLScrollbar* vertical = mScrollbar[VERTICAL]; + if (vertical->getVisible() + && vertical->getEnabled()) + { + // Pretend the mouse is over the scrollbar + if (vertical->handleScrollWheel( 0, 0, clicks ) ) + { + updateScroll(); + } + // Always eat the event + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + // Test enablement and visibility for consistency with + // LLView::childrenHandleScrollWheel(). + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; + } + return FALSE; } BOOL LLScrollContainer::handleScrollHWheel(S32 x, S32 y, S32 clicks) { - if (LLUICtrl::handleScrollHWheel(x,y,clicks)) - { - return TRUE; - } - - LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; - if (horizontal->getVisible() - && horizontal->getEnabled() - && horizontal->handleScrollHWheel( 0, 0, clicks ) ) - { - updateScroll(); - return TRUE; - } - - return FALSE; + if (LLUICtrl::handleScrollHWheel(x,y,clicks)) + { + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollHWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; + } + + return FALSE; } BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - // Scroll folder view if needed. Never accepts a drag or drop. - *accept = ACCEPT_NO; - BOOL handled = autoScroll(x, y); + // Scroll folder view if needed. Never accepts a drag or drop. + *accept = ACCEPT_NO; + BOOL handled = autoScroll(x, y); - if( !handled ) - { - handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg) != NULL; - } + if( !handled ) + { + handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg) != NULL; + } - return TRUE; + return TRUE; } bool LLScrollContainer::canAutoScroll(S32 x, S32 y) { - if (mAutoScrolling) - { - return true; // already scrolling - } - return autoScroll(x, y, false); + if (mAutoScrolling) + { + return true; // already scrolling + } + return autoScroll(x, y, false); } bool LLScrollContainer::autoScroll(S32 x, S32 y) { - return autoScroll(x, y, true); + return autoScroll(x, y, true); } bool LLScrollContainer::autoScroll(S32 x, S32 y, bool do_scroll) { - static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); - S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); - - bool scrolling = false; - if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() ) - { - LLRect screen_local_extents; - screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); - - LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 ); - // Note: Will also include scrollers as scroll zones, so opposite - // scroll zones might have different size due to visible scrollers - if( mScrollbar[HORIZONTAL]->getVisible() ) - { - inner_rect_local.mBottom += scrollbar_size; - } - if( mScrollbar[VERTICAL]->getVisible() ) - { - inner_rect_local.mRight -= scrollbar_size; - } - - // clip rect against root view - inner_rect_local.intersectWith(screen_local_extents); - - S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); - // autoscroll region should take up no more than one third of visible scroller area - S32 auto_scroll_region_width = llmin(inner_rect_local.getWidth() / 3, (S32)mMaxAutoScrollZone); - S32 auto_scroll_region_height = llmin(inner_rect_local.getHeight() / 3, (S32)mMaxAutoScrollZone); - - if( mScrollbar[HORIZONTAL]->getVisible() ) - { - LLRect left_scroll_rect = screen_local_extents; - left_scroll_rect.mRight = inner_rect_local.mLeft + auto_scroll_region_width; - if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) ) - { - if (do_scroll) - { - mScrollbar[HORIZONTAL]->setDocPos(mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed); - mAutoScrolling = TRUE; - } - scrolling = true; - } - - LLRect right_scroll_rect = screen_local_extents; - right_scroll_rect.mLeft = inner_rect_local.mRight - auto_scroll_region_width; - if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) ) - { - if (do_scroll) - { - mScrollbar[HORIZONTAL]->setDocPos(mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed); - mAutoScrolling = TRUE; - } - scrolling = true; - } - } - if( mScrollbar[VERTICAL]->getVisible() ) - { - LLRect bottom_scroll_rect = screen_local_extents; - bottom_scroll_rect.mTop = inner_rect_local.mBottom + auto_scroll_region_height; - if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) ) - { - if (do_scroll) - { - mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed); - mAutoScrolling = TRUE; - } - scrolling = true; - } - - LLRect top_scroll_rect = screen_local_extents; - top_scroll_rect.mBottom = inner_rect_local.mTop - auto_scroll_region_height; - if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) ) - { - if (do_scroll) - { - mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed); - mAutoScrolling = TRUE; - } - scrolling = true; - } - } - } - return scrolling; + static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); + S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); + + bool scrolling = false; + if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() ) + { + LLRect screen_local_extents; + screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); + + LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 ); + // Note: Will also include scrollers as scroll zones, so opposite + // scroll zones might have different size due to visible scrollers + if( mScrollbar[HORIZONTAL]->getVisible() ) + { + inner_rect_local.mBottom += scrollbar_size; + } + if( mScrollbar[VERTICAL]->getVisible() ) + { + inner_rect_local.mRight -= scrollbar_size; + } + + // clip rect against root view + inner_rect_local.intersectWith(screen_local_extents); + + S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); + // autoscroll region should take up no more than one third of visible scroller area + S32 auto_scroll_region_width = llmin(inner_rect_local.getWidth() / 3, (S32)mMaxAutoScrollZone); + S32 auto_scroll_region_height = llmin(inner_rect_local.getHeight() / 3, (S32)mMaxAutoScrollZone); + + if( mScrollbar[HORIZONTAL]->getVisible() ) + { + LLRect left_scroll_rect = screen_local_extents; + left_scroll_rect.mRight = inner_rect_local.mLeft + auto_scroll_region_width; + if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) ) + { + if (do_scroll) + { + mScrollbar[HORIZONTAL]->setDocPos(mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed); + mAutoScrolling = TRUE; + } + scrolling = true; + } + + LLRect right_scroll_rect = screen_local_extents; + right_scroll_rect.mLeft = inner_rect_local.mRight - auto_scroll_region_width; + if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) ) + { + if (do_scroll) + { + mScrollbar[HORIZONTAL]->setDocPos(mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed); + mAutoScrolling = TRUE; + } + scrolling = true; + } + } + if( mScrollbar[VERTICAL]->getVisible() ) + { + LLRect bottom_scroll_rect = screen_local_extents; + bottom_scroll_rect.mTop = inner_rect_local.mBottom + auto_scroll_region_height; + if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) ) + { + if (do_scroll) + { + mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed); + mAutoScrolling = TRUE; + } + scrolling = true; + } + + LLRect top_scroll_rect = screen_local_extents; + top_scroll_rect.mBottom = inner_rect_local.mTop - auto_scroll_region_height; + if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) ) + { + if (do_scroll) + { + mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed); + mAutoScrolling = TRUE; + } + scrolling = true; + } + } + } + return scrolling; } void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const { - const LLRect& doc_rect = getScrolledViewRect(); - static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); - S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); - - S32 doc_width = doc_rect.getWidth(); - S32 doc_height = doc_rect.getHeight(); - - S32 border_width = getBorderWidth(); - *visible_width = getRect().getWidth() - 2 * border_width; - *visible_height = getRect().getHeight() - 2 * border_width; - - *show_v_scrollbar = FALSE; - *show_h_scrollbar = FALSE; - - if (!mHideScrollbar) - { - // Note: 1 pixel change can happen on final animation and should not trigger - // the display of sliders. - if ((doc_height - *visible_height) > 1) - { - *show_v_scrollbar = TRUE; - *visible_width -= scrollbar_size; - } - if ((doc_width - *visible_width) > 1) - { - *show_h_scrollbar = TRUE; - *visible_height -= scrollbar_size; - // Note: Do *not* recompute *show_v_scrollbar here because with - // The view inside the scroll container should not be extended - // to container's full height to ensure the correct computation - // of *show_v_scrollbar after subtracting horizontal scrollbar_size. - - if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) ) - { - *show_v_scrollbar = TRUE; - *visible_width -= scrollbar_size; - } - } - } + const LLRect& doc_rect = getScrolledViewRect(); + static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); + S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); + + S32 doc_width = doc_rect.getWidth(); + S32 doc_height = doc_rect.getHeight(); + + S32 border_width = getBorderWidth(); + *visible_width = getRect().getWidth() - 2 * border_width; + *visible_height = getRect().getHeight() - 2 * border_width; + + *show_v_scrollbar = FALSE; + *show_h_scrollbar = FALSE; + + if (!mHideScrollbar) + { + // Note: 1 pixel change can happen on final animation and should not trigger + // the display of sliders. + if ((doc_height - *visible_height) > 1) + { + *show_v_scrollbar = TRUE; + *visible_width -= scrollbar_size; + } + if ((doc_width - *visible_width) > 1) + { + *show_h_scrollbar = TRUE; + *visible_height -= scrollbar_size; + // Note: Do *not* recompute *show_v_scrollbar here because with + // The view inside the scroll container should not be extended + // to container's full height to ensure the correct computation + // of *show_v_scrollbar after subtracting horizontal scrollbar_size. + + if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) ) + { + *show_v_scrollbar = TRUE; + *visible_width -= scrollbar_size; + } + } + } } - + void LLScrollContainer::draw() { - static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); - S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); - - if (mAutoScrolling) - { - // add acceleration to autoscroll - mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), mMaxAutoScrollRate); - } - else - { - // reset to minimum for next time - mAutoScrollRate = mMinAutoScrollRate; - } - // clear this flag to be set on next call to autoScroll - mAutoScrolling = FALSE; - - // auto-focus when scrollbar active - // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc) - if (!hasFocus() - && (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture())) - { - focusFirstItem(); - } - - if (getRect().isValid()) - { - // Draw background - if( mIsOpaque ) - { - F32 alpha = getCurrentTransparency(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); - } - - // Draw mScrolledViews and update scroll bars. - // get a scissor region ready, and draw the scrolling view. The - // scissor region ensures that we don't draw outside of the bounds - // of the rectangle. - if( mScrolledView ) - { - updateScroll(); - - // Draw the scrolled area. - { - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - - LLLocalClipRect clip(LLRect(mInnerRect.mLeft, - mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, - mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), - mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) - )); - drawChild(mScrolledView); - } - } - - // Highlight border if a child of this container has keyboard focus - if( mBorder->getVisible() ) - { - mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); - } - - // Draw all children except mScrolledView - // Note: scrollbars have been adjusted by above drawing code - for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); - child_iter != getChildList()->rend(); ++child_iter) - { - LLView *viewp = *child_iter; - if( sDebugRects ) - { - sDepth++; - } - if( (viewp != mScrolledView) && viewp->getVisible() ) - { - drawChild(viewp); - } - if( sDebugRects ) - { - sDepth--; - } - } - } + static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); + S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); + + if (mAutoScrolling) + { + // add acceleration to autoscroll + mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), mMaxAutoScrollRate); + } + else + { + // reset to minimum for next time + mAutoScrollRate = mMinAutoScrollRate; + } + // clear this flag to be set on next call to autoScroll + mAutoScrolling = FALSE; + + // auto-focus when scrollbar active + // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc) + if (!hasFocus() + && (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture())) + { + focusFirstItem(); + } + + if (getRect().isValid()) + { + // Draw background + if( mIsOpaque ) + { + F32 alpha = getCurrentTransparency(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha); + } + + // Draw mScrolledViews and update scroll bars. + // get a scissor region ready, and draw the scrolling view. The + // scissor region ensures that we don't draw outside of the bounds + // of the rectangle. + if( mScrolledView ) + { + updateScroll(); + + // Draw the scrolled area. + { + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_v_scrollbar = FALSE; + BOOL show_h_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + + LLLocalClipRect clip(LLRect(mInnerRect.mLeft, + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, + mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), + mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + )); + drawChild(mScrolledView); + } + } + + // Highlight border if a child of this container has keyboard focus + if( mBorder->getVisible() ) + { + mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); + } + + // Draw all children except mScrolledView + // Note: scrollbars have been adjusted by above drawing code + for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); + child_iter != getChildList()->rend(); ++child_iter) + { + LLView *viewp = *child_iter; + if( sDebugRects ) + { + sDepth++; + } + if( (viewp != mScrolledView) && viewp->getVisible() ) + { + drawChild(viewp); + } + if( sDebugRects ) + { + sDepth--; + } + } + } } // end draw bool LLScrollContainer::addChild(LLView* view, S32 tab_group) { - if (!mScrolledView) - { - // Use the first panel or container as the scrollable view (bit of a hack) - mScrolledView = view; - } + if (!mScrolledView) + { + // Use the first panel or container as the scrollable view (bit of a hack) + mScrolledView = view; + } - bool ret_val = LLView::addChild(view, tab_group); + bool ret_val = LLView::addChild(view, tab_group); - //bring the scrollbars to the front - sendChildToFront( mScrollbar[HORIZONTAL] ); - sendChildToFront( mScrollbar[VERTICAL] ); + //bring the scrollbars to the front + sendChildToFront( mScrollbar[HORIZONTAL] ); + sendChildToFront( mScrollbar[VERTICAL] ); - return ret_val; + return ret_val; } void LLScrollContainer::updateScroll() { - if (!getVisible() || !mScrolledView) - { - return; - } - static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); - S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); - - LLRect doc_rect = mScrolledView->getRect(); - S32 doc_width = doc_rect.getWidth(); - S32 doc_height = doc_rect.getHeight(); - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_v_scrollbar = FALSE; - BOOL show_h_scrollbar = FALSE; - calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - - S32 border_width = getBorderWidth(); - if( show_v_scrollbar ) - { - if( doc_rect.mTop < getRect().getHeight() - border_width ) - { - mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); - } - - scrollVertical( mScrollbar[VERTICAL]->getDocPos() ); - mScrollbar[VERTICAL]->setVisible( TRUE ); - - S32 v_scrollbar_height = visible_height; - if( !show_h_scrollbar && mReserveScrollCorner ) - { - v_scrollbar_height -= scrollbar_size; - } - mScrollbar[VERTICAL]->reshape( scrollbar_size, v_scrollbar_height, TRUE ); - - // Make room for the horizontal scrollbar (or not) - S32 v_scrollbar_offset = 0; - if( show_h_scrollbar || mReserveScrollCorner ) - { - v_scrollbar_offset = scrollbar_size; - } - LLRect r = mScrollbar[VERTICAL]->getRect(); - r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset ); - mScrollbar[VERTICAL]->setRect( r ); - } - else - { - mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); - - mScrollbar[VERTICAL]->setVisible( FALSE ); - mScrollbar[VERTICAL]->setDocPos( 0 ); - } - - if( show_h_scrollbar ) - { - if( doc_rect.mLeft > border_width ) - { - mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); - mScrollbar[HORIZONTAL]->setDocPos( 0 ); - } - else - { - scrollHorizontal( mScrollbar[HORIZONTAL]->getDocPos() ); - } - - mScrollbar[HORIZONTAL]->setVisible( TRUE ); - S32 h_scrollbar_width = visible_width; - if( !show_v_scrollbar && mReserveScrollCorner ) - { - h_scrollbar_width -= scrollbar_size; - } - mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, scrollbar_size, TRUE ); - } - else - { - mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); - - mScrollbar[HORIZONTAL]->setVisible( FALSE ); - mScrollbar[HORIZONTAL]->setDocPos( 0 ); - } - - mScrollbar[HORIZONTAL]->setDocSize( doc_width ); - mScrollbar[HORIZONTAL]->setPageSize( visible_width ); - - mScrollbar[VERTICAL]->setDocSize( doc_height ); - mScrollbar[VERTICAL]->setPageSize( visible_height ); + if (!getVisible() || !mScrolledView) + { + return; + } + static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0); + S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize); + + LLRect doc_rect = mScrolledView->getRect(); + S32 doc_width = doc_rect.getWidth(); + S32 doc_height = doc_rect.getHeight(); + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_v_scrollbar = FALSE; + BOOL show_h_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + + S32 border_width = getBorderWidth(); + if( show_v_scrollbar ) + { + if( doc_rect.mTop < getRect().getHeight() - border_width ) + { + mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); + } + + scrollVertical( mScrollbar[VERTICAL]->getDocPos() ); + mScrollbar[VERTICAL]->setVisible( TRUE ); + + S32 v_scrollbar_height = visible_height; + if( !show_h_scrollbar && mReserveScrollCorner ) + { + v_scrollbar_height -= scrollbar_size; + } + mScrollbar[VERTICAL]->reshape( scrollbar_size, v_scrollbar_height, TRUE ); + + // Make room for the horizontal scrollbar (or not) + S32 v_scrollbar_offset = 0; + if( show_h_scrollbar || mReserveScrollCorner ) + { + v_scrollbar_offset = scrollbar_size; + } + LLRect r = mScrollbar[VERTICAL]->getRect(); + r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset ); + mScrollbar[VERTICAL]->setRect( r ); + } + else + { + mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); + + mScrollbar[VERTICAL]->setVisible( FALSE ); + mScrollbar[VERTICAL]->setDocPos( 0 ); + } + + if( show_h_scrollbar ) + { + if( doc_rect.mLeft > border_width ) + { + mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); + mScrollbar[HORIZONTAL]->setDocPos( 0 ); + } + else + { + scrollHorizontal( mScrollbar[HORIZONTAL]->getDocPos() ); + } + + mScrollbar[HORIZONTAL]->setVisible( TRUE ); + S32 h_scrollbar_width = visible_width; + if( !show_v_scrollbar && mReserveScrollCorner ) + { + h_scrollbar_width -= scrollbar_size; + } + mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, scrollbar_size, TRUE ); + } + else + { + mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); + + mScrollbar[HORIZONTAL]->setVisible( FALSE ); + mScrollbar[HORIZONTAL]->setDocPos( 0 ); + } + + mScrollbar[HORIZONTAL]->setDocSize( doc_width ); + mScrollbar[HORIZONTAL]->setPageSize( visible_width ); + + mScrollbar[VERTICAL]->setDocSize( doc_height ); + mScrollbar[VERTICAL]->setPageSize( visible_height ); } // end updateScroll void LLScrollContainer::setBorderVisible(BOOL b) { - mBorder->setVisible( b ); - // Recompute inner rect, as border visibility changes it - mInnerRect = getLocalRect(); - mInnerRect.stretch( -getBorderWidth() ); + mBorder->setVisible( b ); + // Recompute inner rect, as border visibility changes it + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); } LLRect LLScrollContainer::getVisibleContentRect() { - updateScroll(); - LLRect visible_rect = getContentWindowRect(); - LLRect contents_rect = mScrolledView->getRect(); - visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom); - return visible_rect; + updateScroll(); + LLRect visible_rect = getContentWindowRect(); + LLRect contents_rect = mScrolledView->getRect(); + visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom); + return visible_rect; } LLRect LLScrollContainer::getContentWindowRect() { - updateScroll(); - LLRect scroller_view_rect; - S32 visible_width = 0; - S32 visible_height = 0; - BOOL show_h_scrollbar = FALSE; - BOOL show_v_scrollbar = FALSE; - calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - S32 border_width = getBorderWidth(); - scroller_view_rect.setOriginAndSize(border_width, - show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, - visible_width, - visible_height); - return scroller_view_rect; + updateScroll(); + LLRect scroller_view_rect; + S32 visible_width = 0; + S32 visible_height = 0; + BOOL show_h_scrollbar = FALSE; + BOOL show_v_scrollbar = FALSE; + calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); + S32 border_width = getBorderWidth(); + scroller_view_rect.setOriginAndSize(border_width, + show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, + visible_width, + visible_height); + return scroller_view_rect; } // rect is in document coordinates, constraint is in display coordinates relative to content window rect void LLScrollContainer::scrollToShowRect(const LLRect& rect, const LLRect& constraint) { - if (!mScrolledView) - { - LL_WARNS() << "LLScrollContainer::scrollToShowRect with no view!" << LL_ENDL; - return; - } - - LLRect content_window_rect = getContentWindowRect(); - // get document rect - LLRect scrolled_rect = mScrolledView->getRect(); - - // shrink target rect to fit within constraint region, biasing towards top left - LLRect rect_to_constrain = rect; - rect_to_constrain.mBottom = llmax(rect_to_constrain.mBottom, rect_to_constrain.mTop - constraint.getHeight()); - rect_to_constrain.mRight = llmin(rect_to_constrain.mRight, rect_to_constrain.mLeft + constraint.getWidth()); - - // calculate allowable positions for scroller window in document coordinates - LLRect allowable_scroll_rect(rect_to_constrain.mRight - constraint.mRight, - rect_to_constrain.mBottom - constraint.mBottom, - rect_to_constrain.mLeft - constraint.mLeft, - rect_to_constrain.mTop - constraint.mTop); - - // translate from allowable region for lower left corner to upper left corner - allowable_scroll_rect.translate(0, content_window_rect.getHeight()); - - S32 vert_pos = llclamp(mScrollbar[VERTICAL]->getDocPos(), - mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mTop, // min vertical scroll - mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mBottom); // max vertical scroll - - mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); - mScrollbar[VERTICAL]->setPageSize( content_window_rect.getHeight() ); - mScrollbar[VERTICAL]->setDocPos( vert_pos ); - - S32 horizontal_pos = llclamp(mScrollbar[HORIZONTAL]->getDocPos(), - allowable_scroll_rect.mLeft, - allowable_scroll_rect.mRight); - - mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); - mScrollbar[HORIZONTAL]->setPageSize( content_window_rect.getWidth() ); - mScrollbar[HORIZONTAL]->setDocPos( horizontal_pos ); - - // propagate scroll to document - updateScroll(); - - // In case we are in accordion tab notify parent to show selected rectangle - LLRect screen_rc; - localRectToScreen(rect_to_constrain, &screen_rc); - notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); + if (!mScrolledView) + { + LL_WARNS() << "LLScrollContainer::scrollToShowRect with no view!" << LL_ENDL; + return; + } + + LLRect content_window_rect = getContentWindowRect(); + // get document rect + LLRect scrolled_rect = mScrolledView->getRect(); + + // shrink target rect to fit within constraint region, biasing towards top left + LLRect rect_to_constrain = rect; + rect_to_constrain.mBottom = llmax(rect_to_constrain.mBottom, rect_to_constrain.mTop - constraint.getHeight()); + rect_to_constrain.mRight = llmin(rect_to_constrain.mRight, rect_to_constrain.mLeft + constraint.getWidth()); + + // calculate allowable positions for scroller window in document coordinates + LLRect allowable_scroll_rect(rect_to_constrain.mRight - constraint.mRight, + rect_to_constrain.mBottom - constraint.mBottom, + rect_to_constrain.mLeft - constraint.mLeft, + rect_to_constrain.mTop - constraint.mTop); + + // translate from allowable region for lower left corner to upper left corner + allowable_scroll_rect.translate(0, content_window_rect.getHeight()); + + S32 vert_pos = llclamp(mScrollbar[VERTICAL]->getDocPos(), + mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mTop, // min vertical scroll + mScrollbar[VERTICAL]->getDocSize() - allowable_scroll_rect.mBottom); // max vertical scroll + + mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); + mScrollbar[VERTICAL]->setPageSize( content_window_rect.getHeight() ); + mScrollbar[VERTICAL]->setDocPos( vert_pos ); + + S32 horizontal_pos = llclamp(mScrollbar[HORIZONTAL]->getDocPos(), + allowable_scroll_rect.mLeft, + allowable_scroll_rect.mRight); + + mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); + mScrollbar[HORIZONTAL]->setPageSize( content_window_rect.getWidth() ); + mScrollbar[HORIZONTAL]->setDocPos( horizontal_pos ); + + // propagate scroll to document + updateScroll(); + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(rect_to_constrain, &screen_rc); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); } void LLScrollContainer::pageUp(S32 overlap) { - mScrollbar[VERTICAL]->pageUp(overlap); - updateScroll(); + mScrollbar[VERTICAL]->pageUp(overlap); + updateScroll(); } void LLScrollContainer::pageDown(S32 overlap) { - mScrollbar[VERTICAL]->pageDown(overlap); - updateScroll(); + mScrollbar[VERTICAL]->pageDown(overlap); + updateScroll(); } void LLScrollContainer::goToTop() { - mScrollbar[VERTICAL]->setDocPos(0); - updateScroll(); + mScrollbar[VERTICAL]->setDocPos(0); + updateScroll(); } void LLScrollContainer::goToBottom() { - mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize()); - updateScroll(); + mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize()); + updateScroll(); } S32 LLScrollContainer::getBorderWidth() const { - if (mBorder->getVisible()) - { - return mBorder->getBorderWidth(); - } + if (mBorder->getVisible()) + { + return mBorder->getBorderWidth(); + } - return 0; + return 0; } void LLScrollContainer::setSize(S32 size) { - mSize = size; - mScrollbar[VERTICAL]->setThickness(size); - mScrollbar[HORIZONTAL]->setThickness(size); + mSize = size; + mScrollbar[VERTICAL]->setThickness(size); + mScrollbar[HORIZONTAL]->setThickness(size); } diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 79dc70cac9..1295406a3d 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -1,25 +1,25 @@ -/** +/** * @file llscrollcontainer.h * @brief LLScrollContainer class header file. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,7 +39,7 @@ class LLViewBorder; class LLUICtrlFactory; /***************************************************************************** - * + * * A decorator view class meant to encapsulate a clipped region which is * scrollable. It automatically takes care of pixel perfect scrolling * and cliipping, as well as turning the scrollbars on or off based on @@ -49,108 +49,108 @@ class LLUICtrlFactory; struct ScrollContainerRegistry : public LLChildRegistry<ScrollContainerRegistry> { - LLSINGLETON_EMPTY_CTOR(ScrollContainerRegistry); + LLSINGLETON_EMPTY_CTOR(ScrollContainerRegistry); }; class LLScrollContainer : public LLUICtrl { public: - // Note: vertical comes before horizontal because vertical - // scrollbars have priority for mouse and keyboard events. - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> is_opaque, - reserve_scroll_corner, - border_visible, - hide_scrollbar, - ignore_arrow_keys; - Optional<F32> min_auto_scroll_rate, - max_auto_scroll_rate; - Optional<U32> max_auto_scroll_zone; - Optional<LLUIColor> bg_color; - Optional<LLScrollbar::callback_t> scroll_callback; - Optional<S32> size; - - Params(); - }; - - // my valid children are stored in this registry - typedef ScrollContainerRegistry child_registry_t; + // Note: vertical comes before horizontal because vertical + // scrollbars have priority for mouse and keyboard events. + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> is_opaque, + reserve_scroll_corner, + border_visible, + hide_scrollbar, + ignore_arrow_keys; + Optional<F32> min_auto_scroll_rate, + max_auto_scroll_rate; + Optional<U32> max_auto_scroll_zone; + Optional<LLUIColor> bg_color; + Optional<LLScrollbar::callback_t> scroll_callback; + Optional<S32> size; + + Params(); + }; + + // my valid children are stored in this registry + typedef ScrollContainerRegistry child_registry_t; protected: - LLScrollContainer(const Params&); - friend class LLUICtrlFactory; + LLScrollContainer(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLScrollContainer( void ); + virtual ~LLScrollContainer( void ); - virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); } + virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); } - void setBorderVisible( BOOL b ); + void setBorderVisible( BOOL b ); - void scrollToShowRect( const LLRect& rect, const LLRect& constraint); - void scrollToShowRect( const LLRect& rect) { scrollToShowRect(rect, LLRect(0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0)); } + void scrollToShowRect( const LLRect& rect, const LLRect& constraint); + void scrollToShowRect( const LLRect& rect) { scrollToShowRect(rect, LLRect(0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0)); } - void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } - LLRect getVisibleContentRect(); - LLRect getContentWindowRect(); - virtual const LLRect getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } - void pageUp(S32 overlap = 0); - void pageDown(S32 overlap = 0); - void goToTop(); - void goToBottom(); - bool isAtTop() const { return mScrollbar[VERTICAL]->isAtBeginning(); } - bool isAtBottom() const { return mScrollbar[VERTICAL]->isAtEnd(); } + void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } + LLRect getVisibleContentRect(); + LLRect getContentWindowRect(); + virtual const LLRect getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } + void pageUp(S32 overlap = 0); + void pageDown(S32 overlap = 0); + void goToTop(); + void goToBottom(); + bool isAtTop() const { return mScrollbar[VERTICAL]->isAtBeginning(); } + bool isAtBottom() const { return mScrollbar[VERTICAL]->isAtEnd(); } S32 getDocPosVertical() const { return mScrollbar[VERTICAL]->getDocPos(); } S32 getDocPosHorizontal() const { return mScrollbar[HORIZONTAL]->getDocPos(); } - S32 getBorderWidth() const; + S32 getBorderWidth() const; - // LLView functionality - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + // LLView functionality + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleScrollHWheel( S32 x, S32 y, S32 clicks ); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); - virtual void draw(); - virtual bool addChild(LLView* view, S32 tab_group = 0); + virtual void draw(); + virtual bool addChild(LLView* view, S32 tab_group = 0); - bool canAutoScroll(S32 x, S32 y); - bool autoScroll(S32 x, S32 y); + bool canAutoScroll(S32 x, S32 y); + bool autoScroll(S32 x, S32 y); - S32 getSize() const { return mSize; } - void setSize(S32 thickness); + S32 getSize() const { return mSize; } + void setSize(S32 thickness); protected: - LLView* mScrolledView; + LLView* mScrolledView; private: - // internal scrollbar handlers - virtual void scrollHorizontal( S32 new_pos ); - virtual void scrollVertical( S32 new_pos ); - void updateScroll(); - bool autoScroll(S32 x, S32 y, bool do_scroll); - void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const; - - LLScrollbar* mScrollbar[ORIENTATION_COUNT]; - S32 mSize; - BOOL mIsOpaque; - LLUIColor mBackgroundColor; - LLRect mInnerRect; - LLViewBorder* mBorder; - BOOL mReserveScrollCorner; - BOOL mAutoScrolling; - F32 mAutoScrollRate; - F32 mMinAutoScrollRate; - F32 mMaxAutoScrollRate; - U32 mMaxAutoScrollZone; - bool mHideScrollbar; - bool mIgnoreArrowKeys; + // internal scrollbar handlers + virtual void scrollHorizontal( S32 new_pos ); + virtual void scrollVertical( S32 new_pos ); + void updateScroll(); + bool autoScroll(S32 x, S32 y, bool do_scroll); + void calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const; + + LLScrollbar* mScrollbar[ORIENTATION_COUNT]; + S32 mSize; + BOOL mIsOpaque; + LLUIColor mBackgroundColor; + LLRect mInnerRect; + LLViewBorder* mBorder; + BOOL mReserveScrollCorner; + BOOL mAutoScrolling; + F32 mAutoScrollRate; + F32 mMinAutoScrollRate; + F32 mMaxAutoScrollRate; + U32 mMaxAutoScrollZone; + bool mHideScrollbar; + bool mIgnoreArrowKeys; }; diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp index 3a819e7d06..b07f22d7ef 100644 --- a/indra/llui/llscrollingpanellist.cpp +++ b/indra/llui/llscrollingpanellist.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llscrollingpanellist.cpp - * @brief + * @brief * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,215 +38,215 @@ static LLDefaultChildRegistry::Register<LLScrollingPanelList> r("scrolling_panel // This could probably be integrated with LLScrollContainer -SJB LLScrollingPanelList::Params::Params() - : is_horizontal("is_horizontal") - , padding("padding") - , spacing("spacing") + : is_horizontal("is_horizontal") + , padding("padding") + , spacing("spacing") { } LLScrollingPanelList::LLScrollingPanelList(const Params& p) - : LLUICtrl(p) - , mIsHorizontal(p.is_horizontal) - , mPadding(p.padding.isProvided() ? p.padding : DEFAULT_PADDING) - , mSpacing(p.spacing.isProvided() ? p.spacing : DEFAULT_SPACING) + : LLUICtrl(p) + , mIsHorizontal(p.is_horizontal) + , mPadding(p.padding.isProvided() ? p.padding : DEFAULT_PADDING) + , mSpacing(p.spacing.isProvided() ? p.spacing : DEFAULT_SPACING) { } void LLScrollingPanelList::clearPanels() { - deleteAllChildren(); - mPanelList.clear(); - rearrange(); + deleteAllChildren(); + mPanelList.clear(); + rearrange(); } S32 LLScrollingPanelList::addPanel(LLScrollingPanel* panel, bool back) { - if (back) - { - addChild(panel); - mPanelList.push_back(panel); - } - else - { - addChildInBack(panel); - mPanelList.push_front(panel); - } - - rearrange(); - - return mIsHorizontal ? getRect().getWidth() : getRect().getHeight(); + if (back) + { + addChild(panel); + mPanelList.push_back(panel); + } + else + { + addChildInBack(panel); + mPanelList.push_front(panel); + } + + rearrange(); + + return mIsHorizontal ? getRect().getWidth() : getRect().getHeight(); } -void LLScrollingPanelList::removePanel(LLScrollingPanel* panel) +void LLScrollingPanelList::removePanel(LLScrollingPanel* panel) { - U32 index = 0; - LLScrollingPanelList::panel_list_t::const_iterator iter; - - if (!mPanelList.empty()) - { - for (iter = mPanelList.begin(); iter != mPanelList.end(); ++iter, ++index) - { - if (*iter == panel) - { - break; - } - } - if (iter != mPanelList.end()) - { - removePanel(index); - } - } + U32 index = 0; + LLScrollingPanelList::panel_list_t::const_iterator iter; + + if (!mPanelList.empty()) + { + for (iter = mPanelList.begin(); iter != mPanelList.end(); ++iter, ++index) + { + if (*iter == panel) + { + break; + } + } + if (iter != mPanelList.end()) + { + removePanel(index); + } + } } void LLScrollingPanelList::removePanel( U32 panel_index ) { - if ( mPanelList.empty() || panel_index >= mPanelList.size() ) - { - LL_WARNS() << "Panel index " << panel_index << " is out of range!" << LL_ENDL; - return; - } - else - { - removeChild( mPanelList.at(panel_index) ); - mPanelList.erase( mPanelList.begin() + panel_index ); - } - - rearrange(); + if ( mPanelList.empty() || panel_index >= mPanelList.size() ) + { + LL_WARNS() << "Panel index " << panel_index << " is out of range!" << LL_ENDL; + return; + } + else + { + removeChild( mPanelList.at(panel_index) ); + mPanelList.erase( mPanelList.begin() + panel_index ); + } + + rearrange(); } void LLScrollingPanelList::updatePanels(BOOL allow_modify) { for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) + iter != mPanelList.end(); ++iter) { - LLScrollingPanel *childp = *iter; - childp->updatePanel(allow_modify); + LLScrollingPanel *childp = *iter; + childp->updatePanel(allow_modify); } } void LLScrollingPanelList::rearrange() { - // Resize this view - S32 new_width, new_height; - if (!mPanelList.empty()) - { - new_width = new_height = mPadding * 2; - for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) - { - LLScrollingPanel* childp = *iter; - const LLRect& rect = childp->getRect(); - if (mIsHorizontal) - { - new_width += rect.getWidth() + mSpacing; - new_height = llmax(new_height, rect.getHeight()); - } - else - { - new_height += rect.getHeight() + mSpacing; - new_width = llmax(new_width, rect.getWidth()); - } - } - - if (mIsHorizontal) - { - new_width -= mSpacing; - } - else - { - new_height -= mSpacing; - } - } - else - { - new_width = new_height = 1; - } - - LLRect rc = getRect(); - if (mIsHorizontal || !followsRight()) - { - rc.mRight = rc.mLeft + new_width; - } - if (!mIsHorizontal || !followsBottom()) - { - rc.mBottom = rc.mTop - new_height; - } - - if (rc.mRight != getRect().mRight || rc.mBottom != getRect().mBottom) - { - setRect(rc); - notifySizeChanged(); - } - - // Reposition each of the child views - S32 pos = mIsHorizontal ? mPadding : rc.getHeight() - mPadding; - for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) - { - LLScrollingPanel* childp = *iter; - const LLRect& rect = childp->getRect(); - if (mIsHorizontal) - { - childp->translate(pos - rect.mLeft, rc.getHeight() - mPadding - rect.mTop); - pos += rect.getWidth() + mSpacing; - } - else - { - childp->translate(mPadding - rect.mLeft, pos - rect.mTop); - pos -= rect.getHeight() + mSpacing; - } - } + // Resize this view + S32 new_width, new_height; + if (!mPanelList.empty()) + { + new_width = new_height = mPadding * 2; + for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); + iter != mPanelList.end(); ++iter) + { + LLScrollingPanel* childp = *iter; + const LLRect& rect = childp->getRect(); + if (mIsHorizontal) + { + new_width += rect.getWidth() + mSpacing; + new_height = llmax(new_height, rect.getHeight()); + } + else + { + new_height += rect.getHeight() + mSpacing; + new_width = llmax(new_width, rect.getWidth()); + } + } + + if (mIsHorizontal) + { + new_width -= mSpacing; + } + else + { + new_height -= mSpacing; + } + } + else + { + new_width = new_height = 1; + } + + LLRect rc = getRect(); + if (mIsHorizontal || !followsRight()) + { + rc.mRight = rc.mLeft + new_width; + } + if (!mIsHorizontal || !followsBottom()) + { + rc.mBottom = rc.mTop - new_height; + } + + if (rc.mRight != getRect().mRight || rc.mBottom != getRect().mBottom) + { + setRect(rc); + notifySizeChanged(); + } + + // Reposition each of the child views + S32 pos = mIsHorizontal ? mPadding : rc.getHeight() - mPadding; + for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); + iter != mPanelList.end(); ++iter) + { + LLScrollingPanel* childp = *iter; + const LLRect& rect = childp->getRect(); + if (mIsHorizontal) + { + childp->translate(pos - rect.mLeft, rc.getHeight() - mPadding - rect.mTop); + pos += rect.getWidth() + mSpacing; + } + else + { + childp->translate(mPadding - rect.mLeft, pos - rect.mTop); + pos -= rect.getHeight() + mSpacing; + } + } } void LLScrollingPanelList::updatePanelVisiblilty() { - // Determine visibility of children. - - LLRect parent_screen_rect; - getParent()->localPointToScreen( - mPadding, mPadding, - &parent_screen_rect.mLeft, &parent_screen_rect.mBottom ); - getParent()->localPointToScreen( - getParent()->getRect().getWidth() - mPadding, - getParent()->getRect().getHeight() - mPadding, - &parent_screen_rect.mRight, &parent_screen_rect.mTop ); - - for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) - { - LLScrollingPanel *childp = *iter; - const LLRect& local_rect = childp->getRect(); - LLRect screen_rect; - childp->localPointToScreen( - 0, 0, - &screen_rect.mLeft, &screen_rect.mBottom ); - childp->localPointToScreen( - local_rect.getWidth(), local_rect.getHeight(), - &screen_rect.mRight, &screen_rect.mTop ); - - BOOL intersects = - ( (screen_rect.mRight > parent_screen_rect.mLeft) && (screen_rect.mLeft < parent_screen_rect.mRight) ) && - ( (screen_rect.mTop > parent_screen_rect.mBottom) && (screen_rect.mBottom < parent_screen_rect.mTop) ); - - childp->setVisible( intersects ); - } + // Determine visibility of children. + + LLRect parent_screen_rect; + getParent()->localPointToScreen( + mPadding, mPadding, + &parent_screen_rect.mLeft, &parent_screen_rect.mBottom ); + getParent()->localPointToScreen( + getParent()->getRect().getWidth() - mPadding, + getParent()->getRect().getHeight() - mPadding, + &parent_screen_rect.mRight, &parent_screen_rect.mTop ); + + for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); + iter != mPanelList.end(); ++iter) + { + LLScrollingPanel *childp = *iter; + const LLRect& local_rect = childp->getRect(); + LLRect screen_rect; + childp->localPointToScreen( + 0, 0, + &screen_rect.mLeft, &screen_rect.mBottom ); + childp->localPointToScreen( + local_rect.getWidth(), local_rect.getHeight(), + &screen_rect.mRight, &screen_rect.mTop ); + + BOOL intersects = + ( (screen_rect.mRight > parent_screen_rect.mLeft) && (screen_rect.mLeft < parent_screen_rect.mRight) ) && + ( (screen_rect.mTop > parent_screen_rect.mBottom) && (screen_rect.mBottom < parent_screen_rect.mTop) ); + + childp->setVisible( intersects ); + } } void LLScrollingPanelList::draw() { - updatePanelVisiblilty(); + updatePanelVisiblilty(); - LLUICtrl::draw(); + LLUICtrl::draw(); } void LLScrollingPanelList::notifySizeChanged() { - LLSD info; - info["action"] = "size_changes"; - info["height"] = getRect().getHeight(); - info["width"] = getRect().getWidth(); - notifyParent(info); + LLSD info; + info["action"] = "size_changes"; + info["height"] = getRect().getHeight(); + info["width"] = getRect().getWidth(); + notifyParent(info); } // EOF diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index d625039427..ad717a455b 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -1,24 +1,24 @@ -/** +/** * @file llscrollingpanellist.h * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,8 +39,8 @@ class LLScrollingPanel : public LLPanel { public: - LLScrollingPanel(const LLPanel::Params& params) : LLPanel(params) {} - virtual void updatePanel(BOOL allow_modify) = 0; + LLScrollingPanel(const LLPanel::Params& params) : LLPanel(params) {} + virtual void updatePanel(BOOL allow_modify) = 0; }; @@ -50,53 +50,53 @@ public: class LLScrollingPanelList : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<bool> is_horizontal; - Optional<S32> padding; - Optional<S32> spacing; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<bool> is_horizontal; + Optional<S32> padding; + Optional<S32> spacing; + + Params(); + }; - Params(); - }; + LLScrollingPanelList(const Params& p); - LLScrollingPanelList(const Params& p); - - static const S32 DEFAULT_SPACING = 6; - static const S32 DEFAULT_PADDING = 2; + static const S32 DEFAULT_SPACING = 6; + static const S32 DEFAULT_PADDING = 2; - typedef std::deque<LLScrollingPanel*> panel_list_t; + typedef std::deque<LLScrollingPanel*> panel_list_t; - virtual void setValue(const LLSD& value) {}; + virtual void setValue(const LLSD& value) {}; - virtual void draw(); + virtual void draw(); - void clearPanels(); - S32 addPanel(LLScrollingPanel* panel, bool back = false); - void removePanel(LLScrollingPanel* panel); - void removePanel(U32 panel_index); - void updatePanels(BOOL allow_modify); - void rearrange(); + void clearPanels(); + S32 addPanel(LLScrollingPanel* panel, bool back = false); + void removePanel(LLScrollingPanel* panel); + void removePanel(U32 panel_index); + void updatePanels(BOOL allow_modify); + void rearrange(); - const panel_list_t& getPanelList() const { return mPanelList; } - bool getIsHorizontal() const { return mIsHorizontal; } - void setPadding(S32 padding) { mPadding = padding; rearrange(); } - void setSpacing(S32 spacing) { mSpacing = spacing; rearrange(); } - S32 getPadding() const { return mPadding; } - S32 getSpacing() const { return mSpacing; } + const panel_list_t& getPanelList() const { return mPanelList; } + bool getIsHorizontal() const { return mIsHorizontal; } + void setPadding(S32 padding) { mPadding = padding; rearrange(); } + void setSpacing(S32 spacing) { mSpacing = spacing; rearrange(); } + S32 getPadding() const { return mPadding; } + S32 getSpacing() const { return mSpacing; } private: - void updatePanelVisiblilty(); + void updatePanelVisiblilty(); - /** - * Notify parent about size change, makes sense when used inside accordion - */ - void notifySizeChanged(); + /** + * Notify parent about size change, makes sense when used inside accordion + */ + void notifySizeChanged(); - bool mIsHorizontal; - S32 mPadding; - S32 mSpacing; + bool mIsHorizontal; + S32 mPadding; + S32 mSpacing; - panel_list_t mPanelList; + panel_list_t mPanelList; }; #endif //LL_LLSCROLLINGPANELLIST_H diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index f73c9aa539..7fcb91bba3 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llscrolllistcell.cpp - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,64 +30,64 @@ #include "llscrolllistcell.h" #include "llcheckboxctrl.h" -#include "llui.h" // LLUIImage +#include "llui.h" // LLUIImage #include "lluictrlfactory.h" -//static +//static LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_p) { - LLScrollListCell* cell = NULL; - - if (cell_p.type() == "icon") - { - cell = new LLScrollListIcon(cell_p); - } - else if (cell_p.type() == "checkbox") - { - cell = new LLScrollListCheck(cell_p); - } - else if (cell_p.type() == "date") - { - cell = new LLScrollListDate(cell_p); - } - else if (cell_p.type() == "icontext") - { - cell = new LLScrollListIconText(cell_p); - } + LLScrollListCell* cell = NULL; + + if (cell_p.type() == "icon") + { + cell = new LLScrollListIcon(cell_p); + } + else if (cell_p.type() == "checkbox") + { + cell = new LLScrollListCheck(cell_p); + } + else if (cell_p.type() == "date") + { + cell = new LLScrollListDate(cell_p); + } + else if (cell_p.type() == "icontext") + { + cell = new LLScrollListIconText(cell_p); + } else if (cell_p.type() == "bar") { cell = new LLScrollListBar(cell_p); } - else // default is "text" - { - cell = new LLScrollListText(cell_p); - } + else // default is "text" + { + cell = new LLScrollListText(cell_p); + } - if (cell_p.value.isProvided()) - { - cell->setValue(cell_p.value); - } + if (cell_p.value.isProvided()) + { + cell->setValue(cell_p.value); + } - return cell; + return cell; } LLScrollListCell::LLScrollListCell(const LLScrollListCell::Params& p) -: mWidth(p.width), - mToolTip(p.tool_tip) +: mWidth(p.width), + mToolTip(p.tool_tip) {} // virtual const LLSD LLScrollListCell::getValue() const { - return LLStringUtil::null; + return LLStringUtil::null; } // virtual const LLSD LLScrollListCell::getAltValue() const { - return LLStringUtil::null; + return LLStringUtil::null; } @@ -95,10 +95,10 @@ const LLSD LLScrollListCell::getAltValue() const // LLScrollListIcon // LLScrollListIcon::LLScrollListIcon(const LLScrollListCell::Params& p) -: LLScrollListCell(p), - mIcon(LLUI::getUIImage(p.value().asString())), - mColor(p.color), - mAlignment(p.font_halign) +: LLScrollListCell(p), + mIcon(LLUI::getUIImage(p.value().asString())), + mColor(p.color), + mAlignment(p.font_halign) {} LLScrollListIcon::~LLScrollListIcon() @@ -106,82 +106,82 @@ LLScrollListIcon::~LLScrollListIcon() } /*virtual*/ -S32 LLScrollListIcon::getHeight() const +S32 LLScrollListIcon::getHeight() const { return mIcon ? mIcon->getHeight() : 0; } /*virtual*/ -const LLSD LLScrollListIcon::getValue() const +const LLSD LLScrollListIcon::getValue() const { return mIcon.isNull() ? LLStringUtil::null : mIcon->getName(); } void LLScrollListIcon::setValue(const LLSD& value) { - if (value.isUUID()) - { - // don't use default image specified by LLUUID::null, use no image in that case - LLUUID image_id = value.asUUID(); - mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); - } - else - { - std::string value_string = value.asString(); - if (LLUUID::validate(value_string)) - { - setValue(LLUUID(value_string)); - } - else if (!value_string.empty()) - { - mIcon = LLUI::getUIImage(value.asString()); - } - else - { - mIcon = NULL; - } - } + if (value.isUUID()) + { + // don't use default image specified by LLUUID::null, use no image in that case + LLUUID image_id = value.asUUID(); + mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); + } + else + { + std::string value_string = value.asString(); + if (LLUUID::validate(value_string)) + { + setValue(LLUUID(value_string)); + } + else if (!value_string.empty()) + { + mIcon = LLUI::getUIImage(value.asString()); + } + else + { + mIcon = NULL; + } + } } void LLScrollListIcon::setColor(const LLColor4& color) { - mColor = color; + mColor = color; } -S32 LLScrollListIcon::getWidth() const +S32 LLScrollListIcon::getWidth() const { - // if no specified fix width, use width of icon - if (LLScrollListCell::getWidth() == 0 && mIcon.notNull()) - { - return mIcon->getWidth(); - } - return LLScrollListCell::getWidth(); + // if no specified fix width, use width of icon + if (LLScrollListCell::getWidth() == 0 && mIcon.notNull()) + { + return mIcon->getWidth(); + } + return LLScrollListCell::getWidth(); } -void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) const { - if (mIcon) - { - switch(mAlignment) - { - case LLFontGL::LEFT: - mIcon->draw(0, 0, mColor); - break; - case LLFontGL::RIGHT: - mIcon->draw(getWidth() - mIcon->getWidth(), 0, mColor); - break; - case LLFontGL::HCENTER: - mIcon->draw((getWidth() - mIcon->getWidth()) / 2, 0, mColor); - break; - default: - break; - } - } + if (mIcon) + { + switch(mAlignment) + { + case LLFontGL::LEFT: + mIcon->draw(0, 0, mColor); + break; + case LLFontGL::RIGHT: + mIcon->draw(getWidth() - mIcon->getWidth(), 0, mColor); + break; + case LLFontGL::HCENTER: + mIcon->draw((getWidth() - mIcon->getWidth()) / 2, 0, mColor); + break; + default: + break; + } + } } // // LLScrollListBar // LLScrollListBar::LLScrollListBar(const LLScrollListCell::Params& p) - : LLScrollListCell(p), + : LLScrollListCell(p), mRatio(0), mColor(p.color), mBottom(1), @@ -195,14 +195,14 @@ LLScrollListBar::~LLScrollListBar() /*virtual*/ S32 LLScrollListBar::getHeight() const -{ +{ return LLScrollListCell::getHeight(); } /*virtual*/ const LLSD LLScrollListBar::getValue() const -{ - return LLStringUtil::null; +{ + return LLStringUtil::null; } void LLScrollListBar::setValue(const LLSD& value) @@ -230,13 +230,13 @@ void LLScrollListBar::setColor(const LLColor4& color) mColor = color; } -S32 LLScrollListBar::getWidth() const +S32 LLScrollListBar::getWidth() const { return LLScrollListCell::getWidth(); } -void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const { S32 bar_width = getWidth() - mLeftPad - mRightPad; S32 left = bar_width - bar_width * mRatio; @@ -251,267 +251,267 @@ void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_colo U32 LLScrollListText::sCount = 0; LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) -: LLScrollListCell(p), - mText(p.label.isProvided() ? p.label() : p.value().asString()), - mAltText(p.alt_value().asString()), - mFont(p.font), - mColor(p.color), - mUseColor(p.color.isProvided()), - mFontAlignment(p.font_halign), - mVisible(p.visible), - mHighlightCount( 0 ), - mHighlightOffset( 0 ) +: LLScrollListCell(p), + mText(p.label.isProvided() ? p.label() : p.value().asString()), + mAltText(p.alt_value().asString()), + mFont(p.font), + mColor(p.color), + mUseColor(p.color.isProvided()), + mFontAlignment(p.font_halign), + mVisible(p.visible), + mHighlightCount( 0 ), + mHighlightOffset( 0 ) { - sCount++; + sCount++; - mTextWidth = getWidth(); + mTextWidth = getWidth(); - // initialize rounded rect image - if (!mRoundedRectImage) - { - mRoundedRectImage = LLUI::getUIImage("Rounded_Square"); - } + // initialize rounded rect image + if (!mRoundedRectImage) + { + mRoundedRectImage = LLUI::getUIImage("Rounded_Square"); + } } -//virtual +//virtual void LLScrollListText::highlightText(S32 offset, S32 num_chars) { - mHighlightOffset = offset; - mHighlightCount = llmax(0, num_chars); + mHighlightOffset = offset; + mHighlightCount = llmax(0, num_chars); } -//virtual +//virtual BOOL LLScrollListText::isText() const { - return TRUE; + return TRUE; } // virtual const std::string &LLScrollListText::getToolTip() const { - // If base class has a tooltip, return that - if (! LLScrollListCell::getToolTip().empty()) - return LLScrollListCell::getToolTip(); - - // ...otherwise, return the value itself as the tooltip - return mText.getString(); + // If base class has a tooltip, return that + if (! LLScrollListCell::getToolTip().empty()) + return LLScrollListCell::getToolTip(); + + // ...otherwise, return the value itself as the tooltip + return mText.getString(); } // virtual BOOL LLScrollListText::needsToolTip() const { - // If base class has a tooltip, return that - if (LLScrollListCell::needsToolTip()) - return LLScrollListCell::needsToolTip(); - - // ...otherwise, show tooltips for truncated text - return mFont->getWidth(mText.getString()) > getWidth(); + // If base class has a tooltip, return that + if (LLScrollListCell::needsToolTip()) + return LLScrollListCell::needsToolTip(); + + // ...otherwise, show tooltips for truncated text + return mFont->getWidth(mText.getString()) > getWidth(); } -//virtual +//virtual BOOL LLScrollListText::getVisible() const { - return mVisible; + return mVisible; } -//virtual +//virtual S32 LLScrollListText::getHeight() const { - return mFont->getLineHeight(); + return mFont->getLineHeight(); } LLScrollListText::~LLScrollListText() { - sCount--; + sCount--; } -S32 LLScrollListText::getContentWidth() const +S32 LLScrollListText::getContentWidth() const { - return mFont->getWidth(mText.getString()); + return mFont->getWidth(mText.getString()); } void LLScrollListText::setColor(const LLColor4& color) { - mColor = color; - mUseColor = TRUE; + mColor = color; + mUseColor = TRUE; } void LLScrollListText::setText(const LLStringExplicit& text) { - mText = text; + mText = text; } void LLScrollListText::setFontStyle(const U8 font_style) { - LLFontDescriptor new_desc(mFont->getFontDesc()); - new_desc.setStyle(font_style); - mFont = LLFontGL::getFont(new_desc); + LLFontDescriptor new_desc(mFont->getFontDesc()); + new_desc.setStyle(font_style); + mFont = LLFontGL::getFont(new_desc); } //virtual void LLScrollListText::setValue(const LLSD& text) { - setText(text.asString()); + setText(text.asString()); } //virtual void LLScrollListText::setAltValue(const LLSD& text) { - mAltText = text.asString(); + mAltText = text.asString(); } -//virtual -const LLSD LLScrollListText::getValue() const -{ - return LLSD(mText.getString()); +//virtual +const LLSD LLScrollListText::getValue() const +{ + return LLSD(mText.getString()); } -//virtual -const LLSD LLScrollListText::getAltValue() const -{ - return LLSD(mAltText.getString()); +//virtual +const LLSD LLScrollListText::getAltValue() const +{ + return LLSD(mAltText.getString()); } void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const { - LLColor4 display_color; - if (mUseColor) - { - display_color = mColor; - } - else - { - display_color = color; - } - - if (mHighlightCount > 0) - { - // Highlight text - S32 left = 0; - switch(mFontAlignment) - { - case LLFontGL::LEFT: - left = mFont->getWidth(mText.getString(), 1, mHighlightOffset); - break; - case LLFontGL::RIGHT: - left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX); - break; - case LLFontGL::HCENTER: - left = (getWidth() - mFont->getWidth(mText.getString())) / 2; - break; - } - LLRect highlight_rect(left - 2, - mFont->getLineHeight() + 1, - left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, - 1); - mRoundedRectImage->draw(highlight_rect, highlight_color); - } - - // Try to draw the entire string - F32 right_x; - U32 string_chars = mText.length(); - F32 start_x = 0.f; - switch(mFontAlignment) - { - case LLFontGL::LEFT: - start_x = 1.f; - break; - case LLFontGL::RIGHT: - start_x = (F32)getWidth(); - break; - case LLFontGL::HCENTER: - start_x = (F32)getWidth() * 0.5f; - break; - } - mFont->render(mText.getWString(), 0, - start_x, 0.f, - display_color, - mFontAlignment, - LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - string_chars, - getTextWidth(), - &right_x, - TRUE); + LLColor4 display_color; + if (mUseColor) + { + display_color = mColor; + } + else + { + display_color = color; + } + + if (mHighlightCount > 0) + { + // Highlight text + S32 left = 0; + switch(mFontAlignment) + { + case LLFontGL::LEFT: + left = mFont->getWidth(mText.getString(), 1, mHighlightOffset); + break; + case LLFontGL::RIGHT: + left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX); + break; + case LLFontGL::HCENTER: + left = (getWidth() - mFont->getWidth(mText.getString())) / 2; + break; + } + LLRect highlight_rect(left - 2, + mFont->getLineHeight() + 1, + left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, + 1); + mRoundedRectImage->draw(highlight_rect, highlight_color); + } + + // Try to draw the entire string + F32 right_x; + U32 string_chars = mText.length(); + F32 start_x = 0.f; + switch(mFontAlignment) + { + case LLFontGL::LEFT: + start_x = 1.f; + break; + case LLFontGL::RIGHT: + start_x = (F32)getWidth(); + break; + case LLFontGL::HCENTER: + start_x = (F32)getWidth() * 0.5f; + break; + } + mFont->render(mText.getWString(), 0, + start_x, 0.f, + display_color, + mFontAlignment, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + string_chars, + getTextWidth(), + &right_x, + TRUE); } // // LLScrollListCheck // LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p) -: LLScrollListCell(p) +: LLScrollListCell(p) { - LLCheckBoxCtrl::Params checkbox_p; - checkbox_p.name("checkbox"); - checkbox_p.rect = LLRect(0, p.width, p.width, 0); - checkbox_p.enabled(p.enabled); - checkbox_p.initial_value(p.value()); + LLCheckBoxCtrl::Params checkbox_p; + checkbox_p.name("checkbox"); + checkbox_p.rect = LLRect(0, p.width, p.width, 0); + checkbox_p.enabled(p.enabled); + checkbox_p.initial_value(p.value()); + + mCheckBox = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); - mCheckBox = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); - - LLRect rect(mCheckBox->getRect()); - if (p.width) - { - rect.mRight = rect.mLeft + p.width; - mCheckBox->setRect(rect); - setWidth(p.width); - } - else - { - setWidth(rect.getWidth()); //check_box->getWidth(); - } + LLRect rect(mCheckBox->getRect()); + if (p.width) + { + rect.mRight = rect.mLeft + p.width; + mCheckBox->setRect(rect); + setWidth(p.width); + } + else + { + setWidth(rect.getWidth()); //check_box->getWidth(); + } - mCheckBox->setColor(p.color); + mCheckBox->setColor(p.color); } LLScrollListCheck::~LLScrollListCheck() { - delete mCheckBox; - mCheckBox = NULL; + delete mCheckBox; + mCheckBox = NULL; } void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const { - mCheckBox->draw(); + mCheckBox->draw(); } BOOL LLScrollListCheck::handleClick() -{ - if (mCheckBox->getEnabled()) - { - mCheckBox->toggle(); - } - // don't change selection when clicking on embedded checkbox - return TRUE; +{ + if (mCheckBox->getEnabled()) + { + mCheckBox->toggle(); + } + // don't change selection when clicking on embedded checkbox + return TRUE; } /*virtual*/ const LLSD LLScrollListCheck::getValue() const { - return mCheckBox->getValue(); + return mCheckBox->getValue(); } /*virtual*/ void LLScrollListCheck::setValue(const LLSD& value) { - mCheckBox->setValue(value); + mCheckBox->setValue(value); } /*virtual*/ void LLScrollListCheck::onCommit() { - mCheckBox->onCommit(); + mCheckBox->onCommit(); } /*virtual*/ void LLScrollListCheck::setEnabled(BOOL enable) { - mCheckBox->setEnabled(enable); + mCheckBox->setEnabled(enable); } // @@ -519,19 +519,19 @@ void LLScrollListCheck::setEnabled(BOOL enable) // LLScrollListDate::LLScrollListDate( const LLScrollListCell::Params& p) -: LLScrollListText(p), - mDate(p.value().asDate()) +: LLScrollListText(p), + mDate(p.value().asDate()) {} void LLScrollListDate::setValue(const LLSD& value) { - mDate = value.asDate(); - LLScrollListText::setValue(mDate.asRFC1123()); + mDate = value.asDate(); + LLScrollListText::setValue(mDate.asRFC1123()); } const LLSD LLScrollListDate::getValue() const { - return mDate; + return mDate; } // @@ -592,7 +592,7 @@ void LLScrollListIconText::setWidth(S32 width) } -void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const { LLColor4 display_color; if (mUseColor) diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 2588da2331..ea2327961a 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -1,26 +1,26 @@ -/** +/** * @file llscrolllistcell.h - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,8 +28,8 @@ #ifndef LLSCROLLLISTCELL_H #define LLSCROLLLISTCELL_H -#include "llfontgl.h" // HAlign -#include "llpointer.h" // LLPointer<> +#include "llfontgl.h" // HAlign +#include "llpointer.h" // LLPointer<> #include "lluistring.h" #include "v4color.h" #include "llui.h" @@ -42,7 +42,7 @@ class LLUIImage; /* * Represents a cell in a scrollable table. * - * Sub-classes must return height and other properties + * Sub-classes must return height and other properties * though width accessors are implemented by the base class. * It is therefore important for sub-class constructors to call * setWidth() with realistic values. @@ -50,84 +50,84 @@ class LLUIImage; class LLScrollListCell { public: - struct Params : public LLInitParam::Block<Params> - { - Optional<std::string> type, - column; - - Optional<S32> width; - Optional<bool> enabled, - visible; - - Optional<void*> userdata; - Optional<LLSD> value; // state of checkbox, icon id/name, date - Optional<LLSD> alt_value; - Optional<std::string> label; // description or text - Optional<std::string> tool_tip; - - Optional<const LLFontGL*> font; - Optional<LLColor4> font_color; - Optional<LLFontGL::HAlign> font_halign; - - Optional<LLColor4> color; - - Params() - : type("type", "text"), - column("column"), - width("width"), - enabled("enabled", true), - visible("visible", true), - value("value"), - alt_value("alt_value", ""), - label("label"), - tool_tip("tool_tip", ""), - font("font", LLFontGL::getFontSansSerifSmall()), - font_color("font_color", LLColor4::black), - color("color", LLColor4::white), - font_halign("halign", LLFontGL::LEFT) - { - addSynonym(column, "name"); - addSynonym(font_color, "font-color"); - } - }; - - static LLScrollListCell* create(const Params&); - - LLScrollListCell(const LLScrollListCell::Params&); - virtual ~LLScrollListCell() {}; - - virtual void draw(const LLColor4& color, const LLColor4& highlight_color) const {}; // truncate to given width, if possible - virtual S32 getWidth() const {return mWidth;} - virtual S32 getContentWidth() const { return 0; } - virtual S32 getHeight() const { return 0; } - virtual const LLSD getValue() const; - virtual const LLSD getAltValue() const; - virtual void setValue(const LLSD& value) { } - virtual void setAltValue(const LLSD& value) { } - virtual const std::string &getToolTip() const { return mToolTip; } - virtual void setToolTip(const std::string &str) { mToolTip = str; } - virtual BOOL getVisible() const { return TRUE; } - virtual void setWidth(S32 width) { mWidth = width; } - virtual void highlightText(S32 offset, S32 num_chars) {} - virtual BOOL isText() const { return FALSE; } - virtual BOOL needsToolTip() const { return ! mToolTip.empty(); } - virtual void setColor(const LLColor4&) {} - virtual void onCommit() {}; - - virtual BOOL handleClick() { return FALSE; } - virtual void setEnabled(BOOL enable) { } + struct Params : public LLInitParam::Block<Params> + { + Optional<std::string> type, + column; + + Optional<S32> width; + Optional<bool> enabled, + visible; + + Optional<void*> userdata; + Optional<LLSD> value; // state of checkbox, icon id/name, date + Optional<LLSD> alt_value; + Optional<std::string> label; // description or text + Optional<std::string> tool_tip; + + Optional<const LLFontGL*> font; + Optional<LLColor4> font_color; + Optional<LLFontGL::HAlign> font_halign; + + Optional<LLColor4> color; + + Params() + : type("type", "text"), + column("column"), + width("width"), + enabled("enabled", true), + visible("visible", true), + value("value"), + alt_value("alt_value", ""), + label("label"), + tool_tip("tool_tip", ""), + font("font", LLFontGL::getFontEmojiSmall()), + font_color("font_color", LLColor4::black), + color("color", LLColor4::white), + font_halign("halign", LLFontGL::LEFT) + { + addSynonym(column, "name"); + addSynonym(font_color, "font-color"); + } + }; + + static LLScrollListCell* create(const Params&); + + LLScrollListCell(const LLScrollListCell::Params&); + virtual ~LLScrollListCell() {}; + + virtual void draw(const LLColor4& color, const LLColor4& highlight_color) const {}; // truncate to given width, if possible + virtual S32 getWidth() const {return mWidth;} + virtual S32 getContentWidth() const { return 0; } + virtual S32 getHeight() const { return 0; } + virtual const LLSD getValue() const; + virtual const LLSD getAltValue() const; + virtual void setValue(const LLSD& value) { } + virtual void setAltValue(const LLSD& value) { } + virtual const std::string &getToolTip() const { return mToolTip; } + virtual void setToolTip(const std::string &str) { mToolTip = str; } + virtual BOOL getVisible() const { return TRUE; } + virtual void setWidth(S32 width) { mWidth = width; } + virtual void highlightText(S32 offset, S32 num_chars) {} + virtual BOOL isText() const { return FALSE; } + virtual BOOL needsToolTip() const { return ! mToolTip.empty(); } + virtual void setColor(const LLColor4&) {} + virtual void onCommit() {}; + + virtual BOOL handleClick() { return FALSE; } + virtual void setEnabled(BOOL enable) { } private: - S32 mWidth; - std::string mToolTip; + S32 mWidth; + std::string mToolTip; }; class LLScrollListSpacer : public LLScrollListCell { public: - LLScrollListSpacer(const LLScrollListCell::Params& p) : LLScrollListCell(p) {} - /*virtual*/ ~LLScrollListSpacer() {}; - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const {} + LLScrollListSpacer(const LLScrollListCell::Params& p) : LLScrollListCell(p) {} + /*virtual*/ ~LLScrollListSpacer() {}; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const {} }; /* @@ -136,48 +136,48 @@ public: class LLScrollListText : public LLScrollListCell { public: - LLScrollListText(const LLScrollListCell::Params&); - /*virtual*/ ~LLScrollListText(); - - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; - /*virtual*/ S32 getContentWidth() const; - /*virtual*/ S32 getHeight() const; - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ void setAltValue(const LLSD& value); - /*virtual*/ const LLSD getValue() const; - /*virtual*/ const LLSD getAltValue() const; - /*virtual*/ BOOL getVisible() const; - /*virtual*/ void highlightText(S32 offset, S32 num_chars); - - /*virtual*/ void setColor(const LLColor4&); - /*virtual*/ BOOL isText() const; - /*virtual*/ const std::string & getToolTip() const; - /*virtual*/ BOOL needsToolTip() const; - - S32 getTextWidth() const { return mTextWidth;} - void setTextWidth(S32 value) { mTextWidth = value;} - virtual void setWidth(S32 width) { LLScrollListCell::setWidth(width); mTextWidth = width; } - - void setText(const LLStringExplicit& text); - void setFontStyle(const U8 font_style); - void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; } + LLScrollListText(const LLScrollListCell::Params&); + /*virtual*/ ~LLScrollListText(); + + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ S32 getContentWidth() const; + /*virtual*/ S32 getHeight() const; + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void setAltValue(const LLSD& value); + /*virtual*/ const LLSD getValue() const; + /*virtual*/ const LLSD getAltValue() const; + /*virtual*/ BOOL getVisible() const; + /*virtual*/ void highlightText(S32 offset, S32 num_chars); + + /*virtual*/ void setColor(const LLColor4&); + /*virtual*/ BOOL isText() const; + /*virtual*/ const std::string & getToolTip() const; + /*virtual*/ BOOL needsToolTip() const; + + S32 getTextWidth() const { return mTextWidth;} + void setTextWidth(S32 value) { mTextWidth = value;} + virtual void setWidth(S32 width) { LLScrollListCell::setWidth(width); mTextWidth = width; } + + void setText(const LLStringExplicit& text); + void setFontStyle(const U8 font_style); + void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; } protected: - LLUIString mText; - LLUIString mAltText; - S32 mTextWidth; - const LLFontGL* mFont; - LLColor4 mColor; - LLColor4 mHighlightColor; - U8 mUseColor; - LLFontGL::HAlign mFontAlignment; - BOOL mVisible; - S32 mHighlightCount; - S32 mHighlightOffset; - - LLPointer<LLUIImage> mRoundedRectImage; - - static U32 sCount; + LLUIString mText; + LLUIString mAltText; + S32 mTextWidth; + const LLFontGL* mFont; + LLColor4 mColor; + LLColor4 mHighlightColor; + U8 mUseColor; + LLFontGL::HAlign mFontAlignment; + BOOL mVisible; + S32 mHighlightCount; + S32 mHighlightOffset; + + LLPointer<LLUIImage> mRoundedRectImage; + + static U32 sCount; }; /* @@ -186,19 +186,19 @@ protected: class LLScrollListIcon : public LLScrollListCell { public: - LLScrollListIcon(const LLScrollListCell::Params& p); - /*virtual*/ ~LLScrollListIcon(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; - /*virtual*/ S32 getWidth() const; - /*virtual*/ S32 getHeight() const; - /*virtual*/ const LLSD getValue() const; - /*virtual*/ void setColor(const LLColor4&); - /*virtual*/ void setValue(const LLSD& value); + LLScrollListIcon(const LLScrollListCell::Params& p); + /*virtual*/ ~LLScrollListIcon(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ S32 getWidth() const; + /*virtual*/ S32 getHeight() const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setColor(const LLColor4&); + /*virtual*/ void setValue(const LLSD& value); private: - LLPointer<LLUIImage> mIcon; - LLColor4 mColor; - LLFontGL::HAlign mAlignment; + LLPointer<LLUIImage> mIcon; + LLColor4 mColor; + LLFontGL::HAlign mAlignment; }; @@ -207,12 +207,12 @@ class LLScrollListBar : public LLScrollListCell public: LLScrollListBar(const LLScrollListCell::Params& p); /*virtual*/ ~LLScrollListBar(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; - /*virtual*/ S32 getWidth() const; - /*virtual*/ S32 getHeight() const; - /*virtual*/ const LLSD getValue() const; - /*virtual*/ void setColor(const LLColor4&); - /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ S32 getWidth() const; + /*virtual*/ S32 getHeight() const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setColor(const LLColor4&); + /*virtual*/ void setValue(const LLSD& value); private: LLColor4 mColor; @@ -227,32 +227,32 @@ private: class LLScrollListCheck : public LLScrollListCell { public: - LLScrollListCheck( const LLScrollListCell::Params&); - /*virtual*/ ~LLScrollListCheck(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; - /*virtual*/ S32 getHeight() const { return 0; } - /*virtual*/ const LLSD getValue() const; - /*virtual*/ void setValue(const LLSD& value); - /*virtual*/ void onCommit(); + LLScrollListCheck( const LLScrollListCell::Params&); + /*virtual*/ ~LLScrollListCheck(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ S32 getHeight() const { return 0; } + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void onCommit(); - /*virtual*/ BOOL handleClick(); - /*virtual*/ void setEnabled(BOOL enable); + /*virtual*/ BOOL handleClick(); + /*virtual*/ void setEnabled(BOOL enable); - LLCheckBoxCtrl* getCheckBox() { return mCheckBox; } + LLCheckBoxCtrl* getCheckBox() { return mCheckBox; } private: - LLCheckBoxCtrl* mCheckBox; + LLCheckBoxCtrl* mCheckBox; }; class LLScrollListDate : public LLScrollListText { public: - LLScrollListDate( const LLScrollListCell::Params& p ); - virtual void setValue(const LLSD& value); - virtual const LLSD getValue() const; + LLScrollListDate( const LLScrollListCell::Params& p ); + virtual void setValue(const LLSD& value); + virtual const LLSD getValue() const; private: - LLDate mDate; + LLDate mDate; }; /* @@ -264,17 +264,17 @@ class LLScrollListIconText : public LLScrollListText public: LLScrollListIconText(const LLScrollListCell::Params& p); /*virtual*/ ~LLScrollListIconText(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; - /*virtual*/ const LLSD getValue() const; - /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setValue(const LLSD& value); - S32 getIconWidth() const; - /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ + S32 getIconWidth() const; + /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ private: - LLPointer<LLUIImage> mIcon; - S32 mPad; + LLPointer<LLUIImage> mIcon; + S32 mPad; }; #endif diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index 82b0415624..2ef19d1b5a 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llscrollcolumnheader.cpp - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,27 +45,27 @@ static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid // LLScrollColumnHeader //--------------------------------------------------------------------------- LLScrollColumnHeader::Params::Params() -: column("column") +: column("column") {} -LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p) -: LLButton(p), // use combobox params to steal images - mColumn(p.column), - mHasResizableElement(FALSE) +LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p) +: LLButton(p), // use combobox params to steal images + mColumn(p.column), + mHasResizableElement(FALSE) { - setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2)); - - // resize handles on left and right - const S32 RESIZE_BAR_THICKNESS = 3; - LLResizeBar::Params resize_bar_p; - resize_bar_p.resizing_view(this); - resize_bar_p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0)); - resize_bar_p.min_size(MIN_COLUMN_WIDTH); - resize_bar_p.side(LLResizeBar::RIGHT); - resize_bar_p.enabled(false); - mResizeBar = LLUICtrlFactory::create<LLResizeBar>(resize_bar_p); - addChild(mResizeBar); + setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2)); + + // resize handles on left and right + const S32 RESIZE_BAR_THICKNESS = 3; + LLResizeBar::Params resize_bar_p; + resize_bar_p.resizing_view(this); + resize_bar_p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0)); + resize_bar_p.min_size(MIN_COLUMN_WIDTH); + resize_bar_p.side(LLResizeBar::RIGHT); + resize_bar_p.enabled(false); + mResizeBar = LLUICtrlFactory::create<LLResizeBar>(resize_bar_p); + addChild(mResizeBar); } LLScrollColumnHeader::~LLScrollColumnHeader() @@ -73,268 +73,268 @@ LLScrollColumnHeader::~LLScrollColumnHeader() void LLScrollColumnHeader::draw() { - std::string sort_column = mColumn->mParentCtrl->getSortColumnName(); - BOOL draw_arrow = !mColumn->mLabel.empty() - && mColumn->mParentCtrl->isSorted() - // check for indirect sorting column as well as column's sorting name - && (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName); - - BOOL is_ascending = mColumn->mParentCtrl->getSortAscending(); - if (draw_arrow) - { - setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white); - } - else - { - setImageOverlay(LLUUID::null); - } - - // Draw children - LLButton::draw(); + std::string sort_column = mColumn->mParentCtrl->getSortColumnName(); + BOOL draw_arrow = !mColumn->mLabel.empty() + && mColumn->mParentCtrl->isSorted() + // check for indirect sorting column as well as column's sorting name + && (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName); + + BOOL is_ascending = mColumn->mParentCtrl->getSortAscending(); + if (draw_arrow) + { + setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white); + } + else + { + setImageOverlay(LLUUID::null); + } + + // Draw children + LLButton::draw(); } BOOL LLScrollColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask) { - if (canResize() && mResizeBar->getRect().pointInRect(x, y)) - { - // reshape column to max content width - mColumn->mParentCtrl->calcMaxContentWidth(); - LLRect column_rect = getRect(); - column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth; - setShape(column_rect, true); - } - else - { - onClick(LLSD()); - } - return TRUE; + if (canResize() && mResizeBar->getRect().pointInRect(x, y)) + { + // reshape column to max content width + mColumn->mParentCtrl->calcMaxContentWidth(); + LLRect column_rect = getRect(); + column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth; + setShape(column_rect, true); + } + else + { + onClick(LLSD()); + } + return TRUE; } void LLScrollColumnHeader::onClick(const LLSD& data) { - if (mColumn) - { - LLScrollListCtrl::onClickColumn(mColumn); - } + if (mColumn) + { + LLScrollListCtrl::onClickColumn(mColumn); + } } -LLView* LLScrollColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding) +LLView* LLScrollColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding) { - // this logic assumes dragging on right - llassert(snap_edge == SNAP_RIGHT); - - // use higher snap threshold for column headers - threshold = llmin(threshold, 10); - - LLRect snap_rect = getSnapRect(); - - mColumn->mParentCtrl->calcMaxContentWidth(); - - S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth(); - - // x coord growing means column growing, so same signs mean we're going in right direction - if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) - { - new_edge_val = snap_rect.mRight + snap_delta; - } - else - { - LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1); - while (next_column) - { - if (next_column->mHeader) - { - snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight; - if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) - { - new_edge_val = snap_rect.mRight + snap_delta; - } - break; - } - next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1); - } - } - - return this; + // this logic assumes dragging on right + llassert(snap_edge == SNAP_RIGHT); + + // use higher snap threshold for column headers + threshold = llmin(threshold, 10); + + LLRect snap_rect = getSnapRect(); + + mColumn->mParentCtrl->calcMaxContentWidth(); + + S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth(); + + // x coord growing means column growing, so same signs mean we're going in right direction + if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) + { + new_edge_val = snap_rect.mRight + snap_delta; + } + else + { + LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1); + while (next_column) + { + if (next_column->mHeader) + { + snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight; + if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) + { + new_edge_val = snap_rect.mRight + snap_delta; + } + break; + } + next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1); + } + } + + return this; } void LLScrollColumnHeader::handleReshape(const LLRect& new_rect, bool by_user) { - S32 new_width = new_rect.getWidth(); - S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/); - - if (delta_width != 0) - { - S32 remaining_width = -delta_width; - S32 col; - for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++) - { - LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp) continue; - - if (columnp->mHeader && columnp->mHeader->canResize()) - { - // how many pixels in width can this column afford to give up? - S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH); - - // user shrinking column, need to add width to other columns - if (delta_width < 0) - { - if (columnp->getWidth() > 0) - { - // statically sized column, give all remaining width to this column - columnp->setWidth(columnp->getWidth() + remaining_width); - if (columnp->mRelWidth > 0.f) - { - columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); - } - // all padding went to this widget, we're done - break; - } - } - else - { - // user growing column, need to take width from other columns - remaining_width += resize_buffer_amt; - - if (columnp->getWidth() > 0) - { - columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width)); - if (columnp->mRelWidth > 0.f) - { - columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); - } - } - - if (remaining_width >= 0) - { - // width sucked up from neighboring columns, done - break; - } - } - } - } - - // clamp resize amount to maximum that can be absorbed by other columns - if (delta_width > 0) - { - delta_width += llmin(remaining_width, 0); - } - - // propagate constrained delta_width to new width for this column - new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding(); - - // use requested width - mColumn->setWidth(new_width); - - // update proportional spacing - if (mColumn->mRelWidth > 0.f) - { - mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); - } - - // tell scroll list to layout columns again - // do immediate update to get proper feedback to resize handle - // which needs to know how far the resize actually went - const bool force_update = true; - mColumn->mParentCtrl->updateColumns(force_update); - } + S32 new_width = new_rect.getWidth(); + S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/); + + if (delta_width != 0) + { + S32 remaining_width = -delta_width; + S32 col; + for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++) + { + LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); + if (!columnp) continue; + + if (columnp->mHeader && columnp->mHeader->canResize()) + { + // how many pixels in width can this column afford to give up? + S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH); + + // user shrinking column, need to add width to other columns + if (delta_width < 0) + { + if (columnp->getWidth() > 0) + { + // statically sized column, give all remaining width to this column + columnp->setWidth(columnp->getWidth() + remaining_width); + if (columnp->mRelWidth > 0.f) + { + columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); + } + // all padding went to this widget, we're done + break; + } + } + else + { + // user growing column, need to take width from other columns + remaining_width += resize_buffer_amt; + + if (columnp->getWidth() > 0) + { + columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width)); + if (columnp->mRelWidth > 0.f) + { + columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); + } + } + + if (remaining_width >= 0) + { + // width sucked up from neighboring columns, done + break; + } + } + } + } + + // clamp resize amount to maximum that can be absorbed by other columns + if (delta_width > 0) + { + delta_width += llmin(remaining_width, 0); + } + + // propagate constrained delta_width to new width for this column + new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding(); + + // use requested width + mColumn->setWidth(new_width); + + // update proportional spacing + if (mColumn->mRelWidth > 0.f) + { + mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth(); + } + + // tell scroll list to layout columns again + // do immediate update to get proper feedback to resize handle + // which needs to know how far the resize actually went + const bool force_update = true; + mColumn->mParentCtrl->updateColumns(force_update); + } } void LLScrollColumnHeader::setHasResizableElement(BOOL resizable) { - if (mHasResizableElement != resizable) - { - mColumn->mParentCtrl->dirtyColumns(); - mHasResizableElement = resizable; - } + if (mHasResizableElement != resizable) + { + mColumn->mParentCtrl->dirtyColumns(); + mHasResizableElement = resizable; + } } void LLScrollColumnHeader::updateResizeBars() { - S32 num_resizable_columns = 0; - S32 col; - for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) - { - LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (columnp && columnp->mHeader && columnp->mHeader->canResize()) - { - num_resizable_columns++; - } - } - - S32 num_resizers_enabled = 0; - - // now enable/disable resize handles on resizable columns if we have at least two - for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) - { - LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp || !columnp->mHeader) continue; - BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); - columnp->mHeader->enableResizeBar(enable); - if (enable) - { - num_resizers_enabled++; - } - } + S32 num_resizable_columns = 0; + S32 col; + for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) + { + LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); + if (columnp && columnp->mHeader && columnp->mHeader->canResize()) + { + num_resizable_columns++; + } + } + + S32 num_resizers_enabled = 0; + + // now enable/disable resize handles on resizable columns if we have at least two + for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) + { + LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); + if (!columnp || !columnp->mHeader) continue; + BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); + columnp->mHeader->enableResizeBar(enable); + if (enable) + { + num_resizers_enabled++; + } + } } void LLScrollColumnHeader::enableResizeBar(BOOL enable) { - mResizeBar->setEnabled(enable); + mResizeBar->setEnabled(enable); } BOOL LLScrollColumnHeader::canResize() { - return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth); + return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth); } void LLScrollListColumn::SortNames::declareValues() { - declare("ascending", LLScrollListColumn::ASCENDING); - declare("descending", LLScrollListColumn::DESCENDING); + declare("ascending", LLScrollListColumn::ASCENDING); + declare("descending", LLScrollListColumn::DESCENDING); } // // LLScrollListColumn // -//static +//static const LLScrollListColumn::Params& LLScrollListColumn::getDefaultParams() { - return LLUICtrlFactory::getDefaultParams<LLScrollListColumn>(); + return LLUICtrlFactory::getDefaultParams<LLScrollListColumn>(); } LLScrollListColumn::LLScrollListColumn(const Params& p, LLScrollListCtrl* parent) -: mWidth(0), - mIndex (-1), - mParentCtrl(parent), - mName(p.name), - mLabel(p.header.label), - mHeader(NULL), - mMaxContentWidth(0), - mDynamicWidth(p.width.dynamic_width), - mRelWidth(p.width.relative_width), - mFontAlignment(p.halign), - mSortingColumn(p.sort_column) +: mWidth(0), + mIndex (-1), + mParentCtrl(parent), + mName(p.name), + mLabel(p.header.label), + mHeader(NULL), + mMaxContentWidth(0), + mDynamicWidth(p.width.dynamic_width), + mRelWidth(p.width.relative_width), + mFontAlignment(p.halign), + mSortingColumn(p.sort_column) { - if (p.sort_ascending.isProvided()) - { - mSortDirection = p.sort_ascending() ? ASCENDING : DESCENDING; - } - else - { - mSortDirection = p.sort_direction; - } - - setWidth(p.width.pixel_width); + if (p.sort_ascending.isProvided()) + { + mSortDirection = p.sort_ascending() ? ASCENDING : DESCENDING; + } + else + { + mSortDirection = p.sort_direction; + } + + setWidth(p.width.pixel_width); } -void LLScrollListColumn::setWidth(S32 width) -{ - if (!mDynamicWidth && mRelWidth <= 0.f) - { - mParentCtrl->updateStaticColumnWidth(this, width); - } - mWidth = width; +void LLScrollListColumn::setWidth(S32 width) +{ + if (!mDynamicWidth && mRelWidth <= 0.f) + { + mParentCtrl->updateStaticColumnWidth(this, width); + } + mWidth = width; } diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h index b4d4a6d05e..d535d96c76 100644 --- a/indra/llui/llscrolllistcolumn.h +++ b/indra/llui/llscrolllistcolumn.h @@ -1,26 +1,26 @@ -/** +/** * @file llscrollcolumnheader.h - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,33 +40,33 @@ class LLScrollListCtrl; class LLScrollColumnHeader : public LLButton { public: - struct Params : public LLInitParam::Block<Params, LLButton::Params> - { - Mandatory<LLScrollListColumn*> column; + struct Params : public LLInitParam::Block<Params, LLButton::Params> + { + Mandatory<LLScrollListColumn*> column; + + Params(); + }; + LLScrollColumnHeader(const Params&); + ~LLScrollColumnHeader(); - Params(); - }; - LLScrollColumnHeader(const Params&); - ~LLScrollColumnHeader(); + /*virtual*/ void draw(); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ void draw(); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding); + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); - /*virtual*/ LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding); - /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); - - LLScrollListColumn* getColumn() { return mColumn; } - void setHasResizableElement(BOOL resizable); - void updateResizeBars(); - BOOL canResize(); - void enableResizeBar(BOOL enable); + LLScrollListColumn* getColumn() { return mColumn; } + void setHasResizableElement(BOOL resizable); + void updateResizeBars(); + BOOL canResize(); + void enableResizeBar(BOOL enable); - void onClick(const LLSD& data); + void onClick(const LLSD& data); private: - LLScrollListColumn* mColumn; - LLResizeBar* mResizeBar; - BOOL mHasResizableElement; + LLScrollListColumn* mColumn; + LLResizeBar* mResizeBar; + BOOL mHasResizableElement; }; /* @@ -75,98 +75,98 @@ private: class LLScrollListColumn { public: - typedef enum e_sort_direction - { - DESCENDING, - ASCENDING - } ESortDirection; - - struct SortNames - : public LLInitParam::TypeValuesHelper<LLScrollListColumn::ESortDirection, SortNames> - { - static void declareValues(); - }; - - struct Params : public LLInitParam::Block<Params> - { - Optional<std::string> name, - tool_tip; - Optional<std::string> sort_column; - Optional<ESortDirection, SortNames> sort_direction; - Optional<bool> sort_ascending; - - struct Width : public LLInitParam::ChoiceBlock<Width> - { - Alternative<bool> dynamic_width; - Alternative<S32> pixel_width; - Alternative<F32> relative_width; - - Width() - : dynamic_width("dynamic_width", false), - pixel_width("width"), - relative_width("relative_width", -1.f) - { - addSynonym(relative_width, "relwidth"); - } - }; - Optional<Width> width; - - // either an image or label is used in column header - struct Header : public LLInitParam::ChoiceBlock<Header> - { - Alternative<std::string> label; - Alternative<LLUIImage*> image; - - Header() - : label("label"), - image("image") - {} - }; - Optional<Header> header; - - Optional<LLFontGL::HAlign> halign; - - Params() - : name("name"), - tool_tip("tool_tip"), - sort_column("sort_column"), - sort_direction("sort_direction"), - sort_ascending("sort_ascending", true), - halign("halign", LLFontGL::LEFT) - { - // default choice to "dynamic_width" - changeDefault(width.dynamic_width, true); - - addSynonym(sort_column, "sort"); - } - }; - - static const Params& getDefaultParams(); - - //NOTE: this is default constructible so we can store it in a map. - LLScrollListColumn(const Params& p = getDefaultParams(), LLScrollListCtrl* = NULL); - - void setWidth(S32 width); - S32 getWidth() const { return mWidth; } + typedef enum e_sort_direction + { + DESCENDING, + ASCENDING + } ESortDirection; + + struct SortNames + : public LLInitParam::TypeValuesHelper<LLScrollListColumn::ESortDirection, SortNames> + { + static void declareValues(); + }; + + struct Params : public LLInitParam::Block<Params> + { + Optional<std::string> name, + tool_tip; + Optional<std::string> sort_column; + Optional<ESortDirection, SortNames> sort_direction; + Optional<bool> sort_ascending; + + struct Width : public LLInitParam::ChoiceBlock<Width> + { + Alternative<bool> dynamic_width; + Alternative<S32> pixel_width; + Alternative<F32> relative_width; + + Width() + : dynamic_width("dynamic_width", false), + pixel_width("width"), + relative_width("relative_width", -1.f) + { + addSynonym(relative_width, "relwidth"); + } + }; + Optional<Width> width; + + // either an image or label is used in column header + struct Header : public LLInitParam::ChoiceBlock<Header> + { + Alternative<std::string> label; + Alternative<LLUIImage*> image; + + Header() + : label("label"), + image("image") + {} + }; + Optional<Header> header; + + Optional<LLFontGL::HAlign> halign; + + Params() + : name("name"), + tool_tip("tool_tip"), + sort_column("sort_column"), + sort_direction("sort_direction"), + sort_ascending("sort_ascending", true), + halign("halign", LLFontGL::LEFT) + { + // default choice to "dynamic_width" + changeDefault(width.dynamic_width, true); + + addSynonym(sort_column, "sort"); + } + }; + + static const Params& getDefaultParams(); + + //NOTE: this is default constructible so we can store it in a map. + LLScrollListColumn(const Params& p = getDefaultParams(), LLScrollListCtrl* = NULL); + + void setWidth(S32 width); + S32 getWidth() const { return mWidth; } public: - // Public data is fine so long as this remains a simple struct-like data class. - // If it ever gets any smarter than that, these should all become private - // with protected or public accessor methods added as needed. -MG - std::string mName; - std::string mSortingColumn; - ESortDirection mSortDirection; - LLUIString mLabel; - F32 mRelWidth; - BOOL mDynamicWidth; - S32 mMaxContentWidth; - S32 mIndex; - LLScrollListCtrl* mParentCtrl; - LLScrollColumnHeader* mHeader; - LLFontGL::HAlign mFontAlignment; + // Public data is fine so long as this remains a simple struct-like data class. + // If it ever gets any smarter than that, these should all become private + // with protected or public accessor methods added as needed. -MG + std::string mName; + std::string mSortingColumn; + ESortDirection mSortDirection; + LLUIString mLabel; + F32 mRelWidth; + BOOL mDynamicWidth; + S32 mMaxContentWidth; + S32 mIndex; + LLScrollListCtrl* mParentCtrl; + LLScrollColumnHeader* mHeader; + LLFontGL::HAlign mFontAlignment; private: - S32 mWidth; + S32 mWidth; }; #endif diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f982dc99e8..7fb732eca3 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1,26 +1,26 @@ - /** + /** * @file llscrolllistctrl.cpp - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,7 +39,7 @@ #include "llcheckboxctrl.h" #include "llclipboard.h" #include "llfocusmgr.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" //#include "llrender.h" #include "llresmgr.h" @@ -66,58 +66,58 @@ static LLDefaultChildRegistry::Register<LLScrollListCtrl> r("scroll_list"); // local structures & classes. struct SortScrollListItem { - SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal, bool alternate_sort) - : mSortOrders(sort_orders) - , mSortSignal(sort_signal) - , mAltSort(alternate_sort) - {} - - bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2) - { - // sort over all columns in order specified by mSortOrders - S32 sort_result = 0; - for (sort_order_t::const_reverse_iterator it = mSortOrders.rbegin(); - it != mSortOrders.rend(); ++it) - { - S32 col_idx = it->first; - BOOL sort_ascending = it->second; - - S32 order = sort_ascending ? 1 : -1; // ascending or descending sort for this column? - - const LLScrollListCell *cell1 = i1->getColumn(col_idx); - const LLScrollListCell *cell2 = i2->getColumn(col_idx); - if (cell1 && cell2) - { - if(mSortSignal) - { - sort_result = order * (*mSortSignal)(col_idx,i1, i2); - } - else - { - if (mAltSort && !cell1->getAltValue().asString().empty() && !cell2->getAltValue().asString().empty()) - { - sort_result = order * LLStringUtil::compareDict(cell1->getAltValue().asString(), cell2->getAltValue().asString()); - } - else - { - sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString()); - } - } - if (sort_result != 0) - { - break; // we have a sort order! - } - } - } - - return sort_result < 0; - } - - - typedef std::vector<std::pair<S32, BOOL> > sort_order_t; - const LLScrollListCtrl::sort_signal_t* mSortSignal; - const sort_order_t& mSortOrders; - const bool mAltSort; + SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal, bool alternate_sort) + : mSortOrders(sort_orders) + , mSortSignal(sort_signal) + , mAltSort(alternate_sort) + {} + + bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2) + { + // sort over all columns in order specified by mSortOrders + S32 sort_result = 0; + for (sort_order_t::const_reverse_iterator it = mSortOrders.rbegin(); + it != mSortOrders.rend(); ++it) + { + S32 col_idx = it->first; + BOOL sort_ascending = it->second; + + S32 order = sort_ascending ? 1 : -1; // ascending or descending sort for this column? + + const LLScrollListCell *cell1 = i1->getColumn(col_idx); + const LLScrollListCell *cell2 = i2->getColumn(col_idx); + if (cell1 && cell2) + { + if(mSortSignal) + { + sort_result = order * (*mSortSignal)(col_idx,i1, i2); + } + else + { + if (mAltSort && !cell1->getAltValue().asString().empty() && !cell2->getAltValue().asString().empty()) + { + sort_result = order * LLStringUtil::compareDict(cell1->getAltValue().asString(), cell2->getAltValue().asString()); + } + else + { + sort_result = order * LLStringUtil::compareDict(cell1->getValue().asString(), cell2->getValue().asString()); + } + } + if (sort_result != 0) + { + break; // we have a sort order! + } + } + } + + return sort_result < 0; + } + + + typedef std::vector<std::pair<S32, BOOL> > sort_order_t; + const LLScrollListCtrl::sort_signal_t* mSortSignal; + const sort_order_t& mSortOrders; + const bool mAltSort; }; //--------------------------------------------------------------------------- @@ -132,517 +132,517 @@ void LLScrollListCtrl::SelectionTypeNames::declareValues() } LLScrollListCtrl::Contents::Contents() -: columns("column"), - rows("row") +: columns("column"), + rows("row") { - addSynonym(columns, "columns"); - addSynonym(rows, "rows"); + addSynonym(columns, "columns"); + addSynonym(rows, "rows"); } LLScrollListCtrl::Params::Params() -: multi_select("multi_select", false), - has_border("draw_border"), - draw_heading("draw_heading"), - search_column("search_column", 0), - selection_type("selection_type", ROW), - sort_column("sort_column", -1), - sort_ascending("sort_ascending", true), - can_sort("can_sort", true), - mouse_wheel_opaque("mouse_wheel_opaque", false), - commit_on_keyboard_movement("commit_on_keyboard_movement", true), - commit_on_selection_change("commit_on_selection_change", false), - heading_height("heading_height"), - page_lines("page_lines", 0), - background_visible("background_visible"), - draw_stripes("draw_stripes"), - column_padding("column_padding"), - row_padding("row_padding", 2), - fg_unselected_color("fg_unselected_color"), - fg_selected_color("fg_selected_color"), - bg_selected_color("bg_selected_color"), - fg_disable_color("fg_disable_color"), - bg_writeable_color("bg_writeable_color"), - bg_readonly_color("bg_readonly_color"), - bg_stripe_color("bg_stripe_color"), - hovered_color("hovered_color"), - highlighted_color("highlighted_color"), - contents(""), - scroll_bar_bg_visible("scroll_bar_bg_visible"), - scroll_bar_bg_color("scroll_bar_bg_color"), - border("border") +: multi_select("multi_select", false), + has_border("draw_border"), + draw_heading("draw_heading"), + search_column("search_column", 0), + selection_type("selection_type", ROW), + sort_column("sort_column", -1), + sort_ascending("sort_ascending", true), + can_sort("can_sort", true), + mouse_wheel_opaque("mouse_wheel_opaque", false), + commit_on_keyboard_movement("commit_on_keyboard_movement", true), + commit_on_selection_change("commit_on_selection_change", false), + heading_height("heading_height"), + page_lines("page_lines", 0), + background_visible("background_visible"), + draw_stripes("draw_stripes"), + column_padding("column_padding"), + row_padding("row_padding", 2), + fg_unselected_color("fg_unselected_color"), + fg_selected_color("fg_selected_color"), + bg_selected_color("bg_selected_color"), + fg_disable_color("fg_disable_color"), + bg_writeable_color("bg_writeable_color"), + bg_readonly_color("bg_readonly_color"), + bg_stripe_color("bg_stripe_color"), + hovered_color("hovered_color"), + highlighted_color("highlighted_color"), + contents(""), + scroll_bar_bg_visible("scroll_bar_bg_visible"), + scroll_bar_bg_color("scroll_bar_bg_color"), + border("border") {} LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) -: LLUICtrl(p), - mLineHeight(0), - mScrollLines(0), - mMouseWheelOpaque(p.mouse_wheel_opaque), - mPageLines(p.page_lines), - mMaxSelectable(0), - mAllowKeyboardMovement(true), - mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), - mCommitOnSelectionChange(p.commit_on_selection_change), - mSelectionChanged(false), - mSelectionType(p.selection_type), - mNeedsScroll(false), - mCanSelect(true), - mCanSort(p.can_sort), - mColumnsDirty(false), - mMaxItemCount(INT_MAX), - mBorderThickness( 2 ), - mOnDoubleClickCallback( NULL ), - mOnMaximumSelectCallback( NULL ), - mOnSortChangedCallback( NULL ), - mHighlightedItem(-1), - mBorder(NULL), - mSortCallback(NULL), - mCommentTextView(NULL), - mNumDynamicWidthColumns(0), - mTotalStaticColumnWidth(0), - mTotalColumnPadding(0), - mSorted(false), - mDirty(false), - mOriginalSelection(-1), - mLastSelected(NULL), - mHeadingHeight(p.heading_height), - mAllowMultipleSelection(p.multi_select), - mDisplayColumnHeaders(p.draw_heading), - mBackgroundVisible(p.background_visible), - mDrawStripes(p.draw_stripes), - mBgWriteableColor(p.bg_writeable_color()), - mBgReadOnlyColor(p.bg_readonly_color()), - mBgSelectedColor(p.bg_selected_color()), - mBgStripeColor(p.bg_stripe_color()), - mFgSelectedColor(p.fg_selected_color()), - mFgUnselectedColor(p.fg_unselected_color()), - mFgDisabledColor(p.fg_disable_color()), - mHighlightedColor(p.highlighted_color()), - mHoveredColor(p.hovered_color()), - mSearchColumn(p.search_column), - mColumnPadding(p.column_padding), - mRowPadding(p.row_padding), - mAlternateSort(false), - mContextMenuType(MENU_NONE), - mIsFriendSignal(NULL) -{ - mItemListRect.setOriginAndSize( - mBorderThickness, - mBorderThickness, - getRect().getWidth() - 2 * mBorderThickness, - getRect().getHeight() - 2 * mBorderThickness ); - - updateLineHeight(); - - // Init the scrollbar - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - - LLRect scroll_rect; - scroll_rect.setOriginAndSize( - getRect().getWidth() - mBorderThickness - scrollbar_size, - mItemListRect.mBottom, - scrollbar_size, - mItemListRect.getHeight()); - - LLScrollbar::Params sbparams; - sbparams.name("Scrollbar"); - sbparams.rect(scroll_rect); - sbparams.orientation(LLScrollbar::VERTICAL); - sbparams.doc_size(getItemCount()); - sbparams.doc_pos(mScrollLines); - sbparams.page_size( getLinesPerPage() ); - sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); - sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - sbparams.visible(false); - sbparams.bg_visible(p.scroll_bar_bg_visible); - sbparams.bg_color(p.scroll_bar_bg_color); - mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); - addChild(mScrollbar); - - // Border - if (p.has_border) - { - LLRect border_rect = getLocalRect(); - LLViewBorder::Params params = p.border; - params.rect(border_rect); - mBorder = LLUICtrlFactory::create<LLViewBorder> (params); - addChild(mBorder); - } - - // set border *after* rect is fully initialized - if (mBorder) - { - mBorder->setRect(getLocalRect()); - mBorder->reshape(getRect().getWidth(), getRect().getHeight()); - } - - if (p.sort_column >= 0) - { - sortByColumnIndex(p.sort_column, p.sort_ascending); - } - - - for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns.begin(); - row_it != p.contents.columns.end(); - ++row_it) - { - addColumn(*row_it); - } - - for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows.begin(); - row_it != p.contents.rows.end(); - ++row_it) - { - addRow(*row_it); - } - - LLTextBox::Params text_p; - text_p.name("comment_text"); - text_p.border_visible(false); - text_p.rect(mItemListRect); - text_p.follows.flags(FOLLOWS_ALL); - // word wrap was added accroding to the EXT-6841 - text_p.wrap(true); - addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); +: LLUICtrl(p), + mLineHeight(0), + mScrollLines(0), + mMouseWheelOpaque(p.mouse_wheel_opaque), + mPageLines(p.page_lines), + mMaxSelectable(0), + mAllowKeyboardMovement(true), + mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), + mCommitOnSelectionChange(p.commit_on_selection_change), + mSelectionChanged(false), + mSelectionType(p.selection_type), + mNeedsScroll(false), + mCanSelect(true), + mCanSort(p.can_sort), + mColumnsDirty(false), + mMaxItemCount(INT_MAX), + mBorderThickness( 2 ), + mOnDoubleClickCallback( NULL ), + mOnMaximumSelectCallback( NULL ), + mOnSortChangedCallback( NULL ), + mHighlightedItem(-1), + mBorder(NULL), + mSortCallback(NULL), + mCommentTextView(NULL), + mNumDynamicWidthColumns(0), + mTotalStaticColumnWidth(0), + mTotalColumnPadding(0), + mSorted(false), + mDirty(false), + mOriginalSelection(-1), + mLastSelected(NULL), + mHeadingHeight(p.heading_height), + mAllowMultipleSelection(p.multi_select), + mDisplayColumnHeaders(p.draw_heading), + mBackgroundVisible(p.background_visible), + mDrawStripes(p.draw_stripes), + mBgWriteableColor(p.bg_writeable_color()), + mBgReadOnlyColor(p.bg_readonly_color()), + mBgSelectedColor(p.bg_selected_color()), + mBgStripeColor(p.bg_stripe_color()), + mFgSelectedColor(p.fg_selected_color()), + mFgUnselectedColor(p.fg_unselected_color()), + mFgDisabledColor(p.fg_disable_color()), + mHighlightedColor(p.highlighted_color()), + mHoveredColor(p.hovered_color()), + mSearchColumn(p.search_column), + mColumnPadding(p.column_padding), + mRowPadding(p.row_padding), + mAlternateSort(false), + mContextMenuType(MENU_NONE), + mIsFriendSignal(NULL) +{ + mItemListRect.setOriginAndSize( + mBorderThickness, + mBorderThickness, + getRect().getWidth() - 2 * mBorderThickness, + getRect().getHeight() - 2 * mBorderThickness ); + + updateLineHeight(); + + // Init the scrollbar + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - mBorderThickness - scrollbar_size, + mItemListRect.mBottom, + scrollbar_size, + mItemListRect.getHeight()); + + LLScrollbar::Params sbparams; + sbparams.name("Scrollbar"); + sbparams.rect(scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(getItemCount()); + sbparams.doc_pos(mScrollLines); + sbparams.page_size( getLinesPerPage() ); + sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.visible(false); + sbparams.bg_visible(p.scroll_bar_bg_visible); + sbparams.bg_color(p.scroll_bar_bg_color); + mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams); + addChild(mScrollbar); + + // Border + if (p.has_border) + { + LLRect border_rect = getLocalRect(); + LLViewBorder::Params params = p.border; + params.rect(border_rect); + mBorder = LLUICtrlFactory::create<LLViewBorder> (params); + addChild(mBorder); + } + + // set border *after* rect is fully initialized + if (mBorder) + { + mBorder->setRect(getLocalRect()); + mBorder->reshape(getRect().getWidth(), getRect().getHeight()); + } + + if (p.sort_column >= 0) + { + sortByColumnIndex(p.sort_column, p.sort_ascending); + } + + + for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns.begin(); + row_it != p.contents.columns.end(); + ++row_it) + { + addColumn(*row_it); + } + + for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows.begin(); + row_it != p.contents.rows.end(); + ++row_it) + { + addRow(*row_it); + } + + LLTextBox::Params text_p; + text_p.name("comment_text"); + text_p.border_visible(false); + text_p.rect(mItemListRect); + text_p.follows.flags(FOLLOWS_ALL); + // word wrap was added accroding to the EXT-6841 + text_p.wrap(true); + addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); } S32 LLScrollListCtrl::getSearchColumn() { - // search for proper search column - if (mSearchColumn < 0) - { - LLScrollListItem* itemp = getFirstData(); - if (itemp) - { - for(S32 column = 0; column < getNumColumns(); column++) - { - LLScrollListCell* cell = itemp->getColumn(column); - if (cell && cell->isText()) - { - mSearchColumn = column; - break; - } - } - } - } - return llclamp(mSearchColumn, 0, getNumColumns()); + // search for proper search column + if (mSearchColumn < 0) + { + LLScrollListItem* itemp = getFirstData(); + if (itemp) + { + for(S32 column = 0; column < getNumColumns(); column++) + { + LLScrollListCell* cell = itemp->getColumn(column); + if (cell && cell->isText()) + { + mSearchColumn = column; + break; + } + } + } + } + return llclamp(mSearchColumn, 0, getNumColumns()); } /*virtual*/ bool LLScrollListCtrl::preProcessChildNode(LLXMLNodePtr child) { - if (child->hasName("column") || child->hasName("row")) - { - return true; // skip - } - else - { - return false; - } + if (child->hasName("column") || child->hasName("row")) + { + return true; // skip + } + else + { + return false; + } } LLScrollListCtrl::~LLScrollListCtrl() { - delete mSortCallback; + delete mSortCallback; - std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); - mItemList.clear(); + std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); + mItemList.clear(); clearColumns(); //clears columns and deletes headers - delete mIsFriendSignal; + delete mIsFriendSignal; - auto menu = mPopupMenuHandle.get(); - if (menu) - { - menu->die(); - mPopupMenuHandle.markDead(); - } + auto menu = mPopupMenuHandle.get(); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } } BOOL LLScrollListCtrl::setMaxItemCount(S32 max_count) { - if (max_count >= getItemCount()) - { - mMaxItemCount = max_count; - } - return (max_count == mMaxItemCount); + if (max_count >= getItemCount()) + { + mMaxItemCount = max_count; + } + return (max_count == mMaxItemCount); } S32 LLScrollListCtrl::isEmpty() const { - return mItemList.empty(); + return mItemList.empty(); } S32 LLScrollListCtrl::getItemCount() const { - return mItemList.size(); + return mItemList.size(); } BOOL LLScrollListCtrl::hasSelectedItem() const { - item_list::iterator iter; - for (iter = mItemList.begin(); iter < mItemList.end(); ) - { - LLScrollListItem* itemp = *iter; - if (itemp && itemp->getSelected()) - { - return TRUE; - } - iter++; - } - return FALSE; + item_list::iterator iter; + for (iter = mItemList.begin(); iter < mItemList.end(); ) + { + LLScrollListItem* itemp = *iter; + if (itemp && itemp->getSelected()) + { + return TRUE; + } + iter++; + } + return FALSE; } // virtual LLScrolListInterface function (was deleteAllItems) void LLScrollListCtrl::clearRows() { - std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); - mItemList.clear(); - //mItemCount = 0; + std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); + mItemList.clear(); + //mItemCount = 0; - // Scroll the bar back up to the top. - mScrollbar->setDocParams(0, 0); + // Scroll the bar back up to the top. + mScrollbar->setDocParams(0, 0); - mScrollLines = 0; - mLastSelected = NULL; - updateLayout(); - mDirty = false; + mScrollLines = 0; + mLastSelected = NULL; + updateLayout(); + mDirty = false; } LLScrollListItem* LLScrollListCtrl::getFirstSelected() const { - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getSelected()) - { - return item; - } - } - return NULL; + item_list::const_iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + return item; + } + } + return NULL; } std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const { - std::vector<LLScrollListItem*> ret; - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getSelected()) - { - ret.push_back(item); - } - } - return ret; + std::vector<LLScrollListItem*> ret; + item_list::const_iterator iter; + for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + ret.push_back(item); + } + } + return ret; } S32 LLScrollListCtrl::getNumSelected() const { - S32 numSelected = 0; + S32 numSelected = 0; - for(item_list::const_iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) - { - LLScrollListItem* item = *iter; - if (item->getSelected()) - { - ++numSelected; - } - } + for(item_list::const_iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + ++numSelected; + } + } - return numSelected; + return numSelected; } S32 LLScrollListCtrl::getFirstSelectedIndex() const { - S32 CurSelectedIndex = 0; + S32 CurSelectedIndex = 0; - // make sure sort is up to date before returning an index - updateSort(); + // make sure sort is up to date before returning an index + updateSort(); - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getSelected()) - { - return CurSelectedIndex; - } - CurSelectedIndex++; - } + item_list::const_iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + return CurSelectedIndex; + } + CurSelectedIndex++; + } - return -1; + return -1; } LLScrollListItem* LLScrollListCtrl::getFirstData() const { - if (mItemList.size() == 0) - { - return NULL; - } - return mItemList[0]; + if (mItemList.size() == 0) + { + return NULL; + } + return mItemList[0]; } LLScrollListItem* LLScrollListCtrl::getLastData() const { - if (mItemList.size() == 0) - { - return NULL; - } - return mItemList[mItemList.size() - 1]; + if (mItemList.size() == 0) + { + return NULL; + } + return mItemList[mItemList.size() - 1]; } std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const { - std::vector<LLScrollListItem*> ret; - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - ret.push_back(item); - } - return ret; + std::vector<LLScrollListItem*> ret; + item_list::const_iterator iter; + for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + ret.push_back(item); + } + return ret; } // returns first matching item LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const { - std::string string_val = sd.asString(); + std::string string_val = sd.asString(); - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - // assumes string representation is good enough for comparison - if (item->getValue().asString() == string_val) - { - return item; - } - } - return NULL; + item_list::const_iterator iter; + for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + // assumes string representation is good enough for comparison + if (item->getValue().asString() == string_val) + { + return item; + } + } + return NULL; } void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) { - LLUICtrl::reshape( width, height, called_from_parent ); + LLUICtrl::reshape( width, height, called_from_parent ); - updateLayout(); + updateLayout(); } void LLScrollListCtrl::updateLayout() { - static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); - // reserve room for column headers, if needed - S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); - mItemListRect.setOriginAndSize( - mBorderThickness, - mBorderThickness, - getRect().getWidth() - 2 * mBorderThickness, - getRect().getHeight() - (2 * mBorderThickness ) - heading_size ); + static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + // reserve room for column headers, if needed + S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); + mItemListRect.setOriginAndSize( + mBorderThickness, + mBorderThickness, + getRect().getWidth() - 2 * mBorderThickness, + getRect().getHeight() - (2 * mBorderThickness ) - heading_size ); - if (mCommentTextView == NULL) - { - mCommentTextView = getChildView("comment_text"); - } + if (mCommentTextView == NULL) + { + mCommentTextView = getChildView("comment_text"); + } - mCommentTextView->setShape(mItemListRect); + mCommentTextView->setShape(mItemListRect); - // how many lines of content in a single "page" - S32 page_lines = getLinesPerPage(); + // how many lines of content in a single "page" + S32 page_lines = getLinesPerPage(); - BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight(); - if (scrollbar_visible) - { - // provide space on the right for scrollbar - mItemListRect.mRight = getRect().getWidth() - mBorderThickness - scrollbar_size; - } + BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight(); + if (scrollbar_visible) + { + // provide space on the right for scrollbar + mItemListRect.mRight = getRect().getWidth() - mBorderThickness - scrollbar_size; + } - mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom); - mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); - mScrollbar->setPageSize(page_lines); - mScrollbar->setDocSize( getItemCount() ); - mScrollbar->setVisible(scrollbar_visible); + mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom); + mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); + mScrollbar->setPageSize(page_lines); + mScrollbar->setDocSize( getItemCount() ); + mScrollbar->setVisible(scrollbar_visible); - dirtyColumns(); + dirtyColumns(); } // Attempt to size the control to show all items. // Do not make larger than width or height. void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height) { - S32 height = llmin( getRequiredRect().getHeight(), max_height ); - if(mPageLines) - height = llmin( mPageLines * mLineHeight + 2*mBorderThickness + (mDisplayColumnHeaders ? mHeadingHeight : 0), height ); + S32 height = llmin( getRequiredRect().getHeight(), max_height ); + if(mPageLines) + height = llmin( mPageLines * mLineHeight + 2*mBorderThickness + (mDisplayColumnHeaders ? mHeadingHeight : 0), height ); - S32 width = getRect().getWidth(); + S32 width = getRect().getWidth(); - reshape( width, height ); + reshape( width, height ); } LLRect LLScrollListCtrl::getRequiredRect() { - S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); - S32 height = (mLineHeight * getItemCount()) - + (2 * mBorderThickness ) - + heading_size; - S32 width = getRect().getWidth(); + S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); + S32 height = (mLineHeight * getItemCount()) + + (2 * mBorderThickness ) + + heading_size; + S32 width = getRect().getWidth(); - return LLRect(0, height, width, 0); + return LLRect(0, height, width, 0); } BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL requires_column ) { - BOOL not_too_big = getItemCount() < mMaxItemCount; - if (not_too_big) - { - switch( pos ) - { - case ADD_TOP: - mItemList.push_front(item); - setNeedsSort(); - break; - - case ADD_DEFAULT: - case ADD_BOTTOM: - mItemList.push_back(item); - setNeedsSort(); - break; - - default: - llassert(0); - mItemList.push_back(item); - setNeedsSort(); - break; - } - - // create new column on demand - if (mColumns.empty() && requires_column) - { - LLScrollListColumn::Params col_params; - col_params.name = "default_column"; - col_params.header.label = ""; - col_params.width.dynamic_width = true; - addColumn(col_params); - } - - S32 num_cols = item->getNumColumns(); - S32 i = 0; - for (LLScrollListCell* cell = item->getColumn(i); i < num_cols; cell = item->getColumn(++i)) - { - if (i >= (S32)mColumnsIndexed.size()) break; - - cell->setWidth(mColumnsIndexed[i]->getWidth()); - } - - updateLineHeightInsert(item); - - updateLayout(); - } - - return not_too_big; + BOOL not_too_big = getItemCount() < mMaxItemCount; + if (not_too_big) + { + switch( pos ) + { + case ADD_TOP: + mItemList.push_front(item); + setNeedsSort(); + break; + + case ADD_DEFAULT: + case ADD_BOTTOM: + mItemList.push_back(item); + setNeedsSort(); + break; + + default: + llassert(0); + mItemList.push_back(item); + setNeedsSort(); + break; + } + + // create new column on demand + if (mColumns.empty() && requires_column) + { + LLScrollListColumn::Params col_params; + col_params.name = "default_column"; + col_params.header.label = ""; + col_params.width.dynamic_width = true; + addColumn(col_params); + } + + S32 num_cols = item->getNumColumns(); + S32 i = 0; + for (LLScrollListCell* cell = item->getColumn(i); i < num_cols; cell = item->getColumn(++i)) + { + if (i >= (S32)mColumnsIndexed.size()) break; + + cell->setWidth(mColumnsIndexed[i]->getWidth()); + } + + updateLineHeightInsert(item); + + updateLayout(); + } + + return not_too_big; } // NOTE: This is *very* expensive for large lists, especially when we are dirtying the list every frame @@ -650,153 +650,153 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r // *TODO: Use bookkeeping to make this an incramental cost with item additions S32 LLScrollListCtrl::calcMaxContentWidth() { - const S32 HEADING_TEXT_PADDING = 25; - const S32 COLUMN_TEXT_PADDING = 10; + const S32 HEADING_TEXT_PADDING = 25; + const S32 COLUMN_TEXT_PADDING = 10; - S32 max_item_width = 0; + S32 max_item_width = 0; - ordered_columns_t::iterator column_itor; - for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) - { - LLScrollListColumn* column = *column_itor; - if (!column) continue; + ordered_columns_t::iterator column_itor; + for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) + { + LLScrollListColumn* column = *column_itor; + if (!column) continue; - if (mColumnWidthsDirty) - { - // update max content width for this column, by looking at all items - column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); - if (!cellp) continue; + if (mColumnWidthsDirty) + { + // update max content width for this column, by looking at all items + column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0; + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); + if (!cellp) continue; - column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); - } - } - max_item_width += column->mMaxContentWidth; - } - mColumnWidthsDirty = false; + column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); + } + } + max_item_width += column->mMaxContentWidth; + } + mColumnWidthsDirty = false; - return max_item_width; + return max_item_width; } bool LLScrollListCtrl::updateColumnWidths() { - bool width_changed = false; - ordered_columns_t::iterator column_itor; - for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) - { - LLScrollListColumn* column = *column_itor; - if (!column) continue; - - // update column width - S32 new_width = 0; - if (column->mRelWidth >= 0) - { - new_width = (S32)ll_round(column->mRelWidth*mItemListRect.getWidth()); - } - else if (column->mDynamicWidth) - { - new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns; - } - else - { - new_width = column->getWidth(); - } - - if (column->getWidth() != new_width) - { - column->setWidth(new_width); - width_changed = true; - } - } - return width_changed; + bool width_changed = false; + ordered_columns_t::iterator column_itor; + for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) + { + LLScrollListColumn* column = *column_itor; + if (!column) continue; + + // update column width + S32 new_width = 0; + if (column->mRelWidth >= 0) + { + new_width = (S32)ll_round(column->mRelWidth*mItemListRect.getWidth()); + } + else if (column->mDynamicWidth) + { + new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns; + } + else + { + new_width = column->getWidth(); + } + + if (column->getWidth() != new_width) + { + column->setWidth(new_width); + width_changed = true; + } + } + return width_changed; } // Line height is the max height of all the cells in all the items. void LLScrollListCtrl::updateLineHeight() { - mLineHeight = 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - S32 num_cols = itemp->getNumColumns(); - S32 i = 0; - for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) - { - mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); - } - } + mLineHeight = 0; + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + S32 num_cols = itemp->getNumColumns(); + S32 i = 0; + for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) + { + mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); + } + } } // when the only change to line height is from an insert, we needn't scan the entire list void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp) { - S32 num_cols = itemp->getNumColumns(); - S32 i = 0; - for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) - { - mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); - } + S32 num_cols = itemp->getNumColumns(); + S32 i = 0; + for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) + { + mLineHeight = llmax( mLineHeight, cell->getHeight() + mRowPadding ); + } } void LLScrollListCtrl::updateColumns(bool force_update) { - if (!mColumnsDirty && !force_update) - return; - - mColumnsDirty = false; - - bool columns_changed_width = updateColumnWidths(); - - // update column headers - std::vector<LLScrollListColumn*>::iterator column_ordered_it; - S32 left = mItemListRect.mLeft; - LLScrollColumnHeader* last_header = NULL; - for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) - { - LLScrollListColumn* column = *column_ordered_it; - if (!column || column->getWidth() < 0) - { - // skip hidden columns - continue; - } - - if (column->mHeader) - { - column->mHeader->updateResizeBars(); - - last_header = column->mHeader; - S32 top = mItemListRect.mTop; - S32 right = left + column->getWidth(); - - if (column->mIndex != (S32)mColumnsIndexed.size()-1) - { - right += mColumnPadding; - } - right = llmax(left, llmin(mItemListRect.getWidth(), right)); - S32 header_width = right - left; - - last_header->reshape(header_width, mHeadingHeight); - last_header->translate( - left - last_header->getRect().mLeft, - top - last_header->getRect().mBottom); - last_header->setVisible(mDisplayColumnHeaders && header_width > 0); - left = right; - } - } - - bool header_changed_width = false; - // expand last column header we encountered to full list width - if (last_header) - { - S32 old_width = last_header->getColumn()->getWidth(); - S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); - last_header->reshape(new_width, last_header->getRect().getHeight()); - last_header->setVisible(mDisplayColumnHeaders && new_width > 0); + if (!mColumnsDirty && !force_update) + return; + + mColumnsDirty = false; + + bool columns_changed_width = updateColumnWidths(); + + // update column headers + std::vector<LLScrollListColumn*>::iterator column_ordered_it; + S32 left = mItemListRect.mLeft; + LLScrollColumnHeader* last_header = NULL; + for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) + { + LLScrollListColumn* column = *column_ordered_it; + if (!column || column->getWidth() < 0) + { + // skip hidden columns + continue; + } + + if (column->mHeader) + { + column->mHeader->updateResizeBars(); + + last_header = column->mHeader; + S32 top = mItemListRect.mTop; + S32 right = left + column->getWidth(); + + if (column->mIndex != (S32)mColumnsIndexed.size()-1) + { + right += mColumnPadding; + } + right = llmax(left, llmin(mItemListRect.getWidth(), right)); + S32 header_width = right - left; + + last_header->reshape(header_width, mHeadingHeight); + last_header->translate( + left - last_header->getRect().mLeft, + top - last_header->getRect().mBottom); + last_header->setVisible(mDisplayColumnHeaders && header_width > 0); + left = right; + } + } + + bool header_changed_width = false; + // expand last column header we encountered to full list width + if (last_header) + { + S32 old_width = last_header->getColumn()->getWidth(); + S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft); + last_header->reshape(new_width, last_header->getRect().getHeight()); + last_header->setVisible(mDisplayColumnHeaders && new_width > 0); if (old_width != new_width) { last_header->getColumn()->setWidth(new_width); @@ -804,23 +804,23 @@ void LLScrollListCtrl::updateColumns(bool force_update) } } - // propagate column widths to individual cells - if (columns_changed_width || force_update) - { - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - S32 num_cols = itemp->getNumColumns(); - S32 i = 0; - for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) - { - if (i >= (S32)mColumnsIndexed.size()) break; - - cell->setWidth(mColumnsIndexed[i]->getWidth()); - } - } - } + // propagate column widths to individual cells + if (columns_changed_width || force_update) + { + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + S32 num_cols = itemp->getNumColumns(); + S32 i = 0; + for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) + { + if (i >= (S32)mColumnsIndexed.size()) break; + + cell->setWidth(mColumnsIndexed[i]->getWidth()); + } + } + } else if (header_changed_width) { item_list::iterator iter; @@ -839,33 +839,33 @@ void LLScrollListCtrl::updateColumns(bool force_update) void LLScrollListCtrl::setHeadingHeight(S32 heading_height) { - mHeadingHeight = heading_height; + mHeadingHeight = heading_height; - updateLayout(); + updateLayout(); } void LLScrollListCtrl::setPageLines(S32 new_page_lines) { - mPageLines = new_page_lines; - - updateLayout(); + mPageLines = new_page_lines; + + updateLayout(); } BOOL LLScrollListCtrl::selectFirstItem() { - BOOL success = FALSE; + BOOL success = FALSE; - // our $%&@#$()^%#$()*^ iterators don't let us check against the first item inside out iteration - BOOL first_item = TRUE; + // our $%&@#$()^%#$()*^ iterators don't let us check against the first item inside out iteration + BOOL first_item = TRUE; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - if( first_item && itemp->getEnabled() ) - { - if (!itemp->getSelected()) - { + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + if( first_item && itemp->getEnabled() ) + { + if (!itemp->getSelected()) + { switch (mSelectionType) { case CELL: @@ -875,187 +875,187 @@ BOOL LLScrollListCtrl::selectFirstItem() case ROW: selectItem(itemp, -1); } - } - success = TRUE; - mOriginalSelection = 0; - } - else - { - deselectItem(itemp); - } - first_item = false; - } - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } - return success; + } + success = TRUE; + mOriginalSelection = 0; + } + else + { + deselectItem(itemp); + } + first_item = false; + } + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + return success; } // Deselects all other items // virtual BOOL LLScrollListCtrl::selectNthItem( S32 target_index ) { - return selectItemRange(target_index, target_index); + return selectItemRange(target_index, target_index); } // virtual BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) { - if (mItemList.empty()) - { - return FALSE; - } - - // make sure sort is up to date - updateSort(); - - S32 listlen = (S32)mItemList.size(); - first_index = llclamp(first_index, 0, listlen-1); - - if (last_index < 0) - last_index = listlen-1; - else - last_index = llclamp(last_index, first_index, listlen-1); - - BOOL success = FALSE; - S32 index = 0; - for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ) - { - LLScrollListItem *itemp = *iter; - if(!itemp) - { - iter = mItemList.erase(iter); - continue ; - } - - if( index >= first_index && index <= last_index ) - { - if( itemp->getEnabled() ) - { - // TODO: support range selection for cells - selectItem(itemp, -1, FALSE); - success = TRUE; - } - } - else - { - deselectItem(itemp); - } - index++; - iter++ ; - } - - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } - - mSearchString.clear(); - - return success; + if (mItemList.empty()) + { + return FALSE; + } + + // make sure sort is up to date + updateSort(); + + S32 listlen = (S32)mItemList.size(); + first_index = llclamp(first_index, 0, listlen-1); + + if (last_index < 0) + last_index = listlen-1; + else + last_index = llclamp(last_index, first_index, listlen-1); + + BOOL success = FALSE; + S32 index = 0; + for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ) + { + LLScrollListItem *itemp = *iter; + if(!itemp) + { + iter = mItemList.erase(iter); + continue ; + } + + if( index >= first_index && index <= last_index ) + { + if( itemp->getEnabled() ) + { + // TODO: support range selection for cells + selectItem(itemp, -1, FALSE); + success = TRUE; + } + } + else + { + deselectItem(itemp); + } + index++; + iter++ ; + } + + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + + mSearchString.clear(); + + return success; } void LLScrollListCtrl::swapWithNext(S32 index) { - if (index >= ((S32)mItemList.size() - 1)) - { - // At end of list, doesn't do anything - return; - } - updateSort(); - LLScrollListItem *cur_itemp = mItemList[index]; - mItemList[index] = mItemList[index + 1]; - mItemList[index + 1] = cur_itemp; + if (index >= ((S32)mItemList.size() - 1)) + { + // At end of list, doesn't do anything + return; + } + updateSort(); + LLScrollListItem *cur_itemp = mItemList[index]; + mItemList[index] = mItemList[index + 1]; + mItemList[index + 1] = cur_itemp; } void LLScrollListCtrl::swapWithPrevious(S32 index) { - if (index <= 0) - { - // At beginning of list, don't do anything - } + if (index <= 0) + { + // At beginning of list, don't do anything + } - updateSort(); - LLScrollListItem *cur_itemp = mItemList[index]; - mItemList[index] = mItemList[index - 1]; - mItemList[index - 1] = cur_itemp; + updateSort(); + LLScrollListItem *cur_itemp = mItemList[index]; + mItemList[index] = mItemList[index - 1]; + mItemList[index - 1] = cur_itemp; } void LLScrollListCtrl::deleteSingleItem(S32 target_index) { - if (target_index < 0 || target_index >= (S32)mItemList.size()) - { - return; - } + if (target_index < 0 || target_index >= (S32)mItemList.size()) + { + return; + } - updateSort(); + updateSort(); - LLScrollListItem *itemp; - itemp = mItemList[target_index]; - if (itemp == mLastSelected) - { - mLastSelected = NULL; - } - delete itemp; - mItemList.erase(mItemList.begin() + target_index); - dirtyColumns(); + LLScrollListItem *itemp; + itemp = mItemList[target_index]; + if (itemp == mLastSelected) + { + mLastSelected = NULL; + } + delete itemp; + mItemList.erase(mItemList.begin() + target_index); + dirtyColumns(); } //FIXME: refactor item deletion void LLScrollListCtrl::deleteItems(const LLSD& sd) { - item_list::iterator iter; - for (iter = mItemList.begin(); iter < mItemList.end(); ) - { - LLScrollListItem* itemp = *iter; - if (itemp->getValue().asString() == sd.asString()) - { - if (itemp == mLastSelected) - { - mLastSelected = NULL; - } - delete itemp; - iter = mItemList.erase(iter); - } - else - { - iter++; - } - } - - dirtyColumns(); + item_list::iterator iter; + for (iter = mItemList.begin(); iter < mItemList.end(); ) + { + LLScrollListItem* itemp = *iter; + if (itemp->getValue().asString() == sd.asString()) + { + if (itemp == mLastSelected) + { + mLastSelected = NULL; + } + delete itemp; + iter = mItemList.erase(iter); + } + else + { + iter++; + } + } + + dirtyColumns(); } void LLScrollListCtrl::deleteSelectedItems() { - item_list::iterator iter; - for (iter = mItemList.begin(); iter < mItemList.end(); ) - { - LLScrollListItem* itemp = *iter; - if (itemp->getSelected()) - { - delete itemp; - iter = mItemList.erase(iter); - } - else - { - iter++; - } - } - mLastSelected = NULL; - dirtyColumns(); + item_list::iterator iter; + for (iter = mItemList.begin(); iter < mItemList.end(); ) + { + LLScrollListItem* itemp = *iter; + if (itemp->getSelected()) + { + delete itemp; + iter = mItemList.erase(iter); + } + else + { + iter++; + } + } + mLastSelected = NULL; + dirtyColumns(); } void LLScrollListCtrl::clearHighlightedItems() -{ - for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) - { - (*iter)->setHighlighted(false); - } +{ + for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + { + (*iter)->setHighlighted(false); + } } void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index) @@ -1070,173 +1070,173 @@ void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index) } } -S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) +S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) { - item_list::iterator iter; - S32 count = 0; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - uuid_vec_t::iterator iditr; - for(iditr = ids.begin(); iditr != ids.end(); ++iditr) - { - if (item->getEnabled() && (item->getUUID() == (*iditr))) - { - // TODO: support multiple selection for cells - selectItem(item, -1, FALSE); - ++count; - break; - } - } - if(ids.end() != iditr) ids.erase(iditr); - } + item_list::iterator iter; + S32 count = 0; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + uuid_vec_t::iterator iditr; + for(iditr = ids.begin(); iditr != ids.end(); ++iditr) + { + if (item->getEnabled() && (item->getUUID() == (*iditr))) + { + // TODO: support multiple selection for cells + selectItem(item, -1, FALSE); + ++count; + break; + } + } + if(ids.end() != iditr) ids.erase(iditr); + } - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } - return count; + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + return count; } S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const { - updateSort(); + updateSort(); - S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - if (target_item == itemp) - { - return index; - } - index++; - } - return -1; + S32 index = 0; + item_list::const_iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + if (target_item == itemp) + { + return index; + } + index++; + } + return -1; } S32 LLScrollListCtrl::getItemIndex( const LLUUID& target_id ) const { - updateSort(); + updateSort(); - S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - if (target_id == itemp->getUUID()) - { - return index; - } - index++; - } - return -1; + S32 index = 0; + item_list::const_iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + if (target_id == itemp->getUUID()) + { + return index; + } + index++; + } + return -1; } void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) { - LLScrollListItem* prev_item = NULL; - - if (!getFirstSelected()) - { - // select last item - selectNthItem(getItemCount() - 1); - } - else - { - updateSort(); - - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* cur_item = *iter; - - if (cur_item->getSelected()) - { - if (prev_item) - { - selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection); - } - else - { - reportInvalidInput(); - } - break; - } - - // don't allow navigation to disabled elements - prev_item = cur_item->getEnabled() ? cur_item : prev_item; - } - } - - if ((mCommitOnSelectionChange || mCommitOnKeyboardMovement)) - { - commitIfChanged(); - } - - mSearchString.clear(); + LLScrollListItem* prev_item = NULL; + + if (!getFirstSelected()) + { + // select last item + selectNthItem(getItemCount() - 1); + } + else + { + updateSort(); + + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* cur_item = *iter; + + if (cur_item->getSelected()) + { + if (prev_item) + { + selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection); + } + else + { + reportInvalidInput(); + } + break; + } + + // don't allow navigation to disabled elements + prev_item = cur_item->getEnabled() ? cur_item : prev_item; + } + } + + if ((mCommitOnSelectionChange || mCommitOnKeyboardMovement)) + { + commitIfChanged(); + } + + mSearchString.clear(); } void LLScrollListCtrl::selectNextItem( BOOL extend_selection) { - LLScrollListItem* next_item = NULL; + LLScrollListItem* next_item = NULL; - if (!getFirstSelected()) - { - selectFirstItem(); - } - else - { - updateSort(); + if (!getFirstSelected()) + { + selectFirstItem(); + } + else + { + updateSort(); - item_list::reverse_iterator iter; - for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) - { - LLScrollListItem* cur_item = *iter; + item_list::reverse_iterator iter; + for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) + { + LLScrollListItem* cur_item = *iter; - if (cur_item->getSelected()) - { - if (next_item) - { - selectItem(next_item, cur_item->getSelectedCell(), !extend_selection); - } - else - { - reportInvalidInput(); - } - break; - } + if (cur_item->getSelected()) + { + if (next_item) + { + selectItem(next_item, cur_item->getSelectedCell(), !extend_selection); + } + else + { + reportInvalidInput(); + } + break; + } - // don't allow navigation to disabled items - next_item = cur_item->getEnabled() ? cur_item : next_item; - } - } + // don't allow navigation to disabled items + next_item = cur_item->getEnabled() ? cur_item : next_item; + } + } - if (mCommitOnKeyboardMovement) - { - onCommit(); - } + if (mCommitOnKeyboardMovement) + { + onCommit(); + } - mSearchString.clear(); + mSearchString.clear(); } void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change) { - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - deselectItem(item); - } + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + deselectItem(item); + } - if (mCommitOnSelectionChange && !no_commit_on_change) - { - commitIfChanged(); - } + if (mCommitOnSelectionChange && !no_commit_on_change) + { + commitIfChanged(); + } } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1244,20 +1244,20 @@ void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change) void LLScrollListCtrl::setCommentText(const std::string& comment_text) { - getChild<LLTextBox>("comment_text")->setValue(comment_text); + getChild<LLTextBox>("comment_text")->setValue(comment_text); } LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos) { - LLScrollListItem::Params separator_params; - separator_params.enabled(false); - LLScrollListCell::Params column_params; - column_params.type = "icon"; - column_params.value = "menu_separator"; - column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f); - column_params.font_halign = LLFontGL::HCENTER; - separator_params.columns.add(column_params); - return addRow( separator_params, pos ); + LLScrollListItem::Params separator_params; + separator_params.enabled(false); + LLScrollListCell::Params column_params; + column_params.type = "icon"; + column_params.value = "menu_separator"; + column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f); + column_params.font_halign = LLFontGL::HCENTER; + separator_params.columns.add(column_params); + return addRow( separator_params, pos ); } // Selects first enabled item of the given name. @@ -1265,133 +1265,133 @@ LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos) // Calls getItemByLabel in order to combine functionality BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sensitive, S32 column/* = 0*/) { - deselectAllItems(TRUE); // ensure that no stale items are selected, even if we don't find a match - LLScrollListItem* item = getItemByLabel(label, case_sensitive, column); + deselectAllItems(TRUE); // ensure that no stale items are selected, even if we don't find a match + LLScrollListItem* item = getItemByLabel(label, case_sensitive, column); - bool found = NULL != item; - if (found) - { - selectItem(item, -1); - } + bool found = NULL != item; + if (found) + { + selectItem(item, -1); + } - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } - return found; + return found; } LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOOL case_sensitive, S32 column) { - if (label.empty()) //RN: assume no empty items - { - return NULL; - } - - std::string target_text = label; - if (!case_sensitive) - { - LLStringUtil::toLower(target_text); - } - - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names - if (!case_sensitive) - { - LLStringUtil::toLower(item_text); - } - if(item_text == target_text) - { - return item; - } - } - return NULL; + if (label.empty()) //RN: assume no empty items + { + return NULL; + } + + std::string target_text = label; + if (!case_sensitive) + { + LLStringUtil::toLower(target_text); + } + + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names + if (!case_sensitive) + { + LLStringUtil::toLower(item_text); + } + if(item_text == target_text) + { + return item; + } + } + return NULL; } BOOL LLScrollListCtrl::selectItemByPrefix(const std::string& target, BOOL case_sensitive, S32 column) { - return selectItemByPrefix(utf8str_to_wstring(target), case_sensitive, column); + return selectItemByPrefix(utf8str_to_wstring(target), case_sensitive, column); } // Selects first enabled item that has a name where the name's first part matched the target string. // Returns false if item not found. BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sensitive, S32 column) { - BOOL found = FALSE; - - LLWString target_trimmed( target ); - S32 target_len = target_trimmed.size(); - - if( 0 == target_len ) - { - // Is "" a valid choice? - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - // Only select enabled items with matching names - LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column); - BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; - if (select) - { - selectItem(item, -1); - found = TRUE; - break; - } - } - } - else - { - if (!case_sensitive) - { - // do comparisons in lower case - LLWStringUtil::toLower(target_trimmed); - } - - for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - - // Only select enabled items with matching names - LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column); - if (!cellp) - { - continue; - } - LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); - if (!case_sensitive) - { - LLWStringUtil::toLower(item_label); - } - // remove extraneous whitespace from searchable label - LLWString trimmed_label = item_label; - LLWStringUtil::trim(trimmed_label); - - BOOL select = item->getEnabled() && trimmed_label.compare(0, target_trimmed.size(), target_trimmed) == 0; - - if (select) - { - // find offset of matching text (might have leading whitespace) - S32 offset = item_label.find(target_trimmed); - cellp->highlightText(offset, target_trimmed.size()); - selectItem(item, -1); - found = TRUE; - break; - } - } - } - - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } - - return found; + BOOL found = FALSE; + + LLWString target_trimmed( target ); + S32 target_len = target_trimmed.size(); + + if( 0 == target_len ) + { + // Is "" a valid choice? + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + // Only select enabled items with matching names + LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column); + BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; + if (select) + { + selectItem(item, -1); + found = TRUE; + break; + } + } + } + else + { + if (!case_sensitive) + { + // do comparisons in lower case + LLWStringUtil::toLower(target_trimmed); + } + + for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + + // Only select enabled items with matching names + LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column); + if (!cellp) + { + continue; + } + LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); + if (!case_sensitive) + { + LLWStringUtil::toLower(item_label); + } + // remove extraneous whitespace from searchable label + LLWString trimmed_label = item_label; + LLWStringUtil::trim(trimmed_label); + + BOOL select = item->getEnabled() && trimmed_label.compare(0, target_trimmed.size(), target_trimmed) == 0; + + if (select) + { + // find offset of matching text (might have leading whitespace) + S32 offset = item_label.find(target_trimmed); + cellp->highlightText(offset, target_trimmed.size()); + selectItem(item, -1); + found = TRUE; + break; + } + } + } + + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + + return found; } U32 LLScrollListCtrl::searchItems(const std::string& substring, bool case_sensitive, bool focus) @@ -1474,15 +1474,15 @@ U32 LLScrollListCtrl::searchItems(const LLWString& substring, bool case_sensitiv const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const { - LLScrollListItem* item; + LLScrollListItem* item; - item = getFirstSelected(); - if (item) - { - return item->getColumn(column)->getValue().asString(); - } + item = getFirstSelected(); + if (item) + { + return item->getColumn(column)->getValue().asString(); + } - return LLStringUtil::null; + return LLStringUtil::null; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1491,36 +1491,36 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled) { - if (getItemCount() < mMaxItemCount) - { - LLScrollListItem::Params item_p; - item_p.enabled(enabled); - item_p.value(id); - item_p.columns.add().value(item_text).type("text"); + if (getItemCount() < mMaxItemCount) + { + LLScrollListItem::Params item_p; + item_p.enabled(enabled); + item_p.value(id); + item_p.columns.add().value(item_text).type("text"); - return addRow( item_p, pos ); - } - return NULL; + return addRow( item_p, pos ); + } + return NULL; } // Select the line or lines that match this UUID BOOL LLScrollListCtrl::selectByID( const LLUUID& id ) { - return selectByValue( LLSD(id) ); + return selectByValue( LLSD(id) ); } BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) { - BOOL found = FALSE; + BOOL found = FALSE; - if (selected && !mAllowMultipleSelection) deselectAllItems(TRUE); + if (selected && !mAllowMultipleSelection) deselectAllItems(TRUE); - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getEnabled()) - { + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getEnabled()) + { if (value.isBinary()) { if (item->getValue().isBinary()) @@ -1547,523 +1547,523 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) } break; } - } - } + } + } - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } - return found; + return found; } -BOOL LLScrollListCtrl::isSelected(const LLSD& value) const +BOOL LLScrollListCtrl::isSelected(const LLSD& value) const { - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getValue().asString() == value.asString()) - { - return item->getSelected(); - } - } - return FALSE; + item_list::const_iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getValue().asString() == value.asString()) + { + return item->getSelected(); + } + } + return FALSE; } LLUUID LLScrollListCtrl::getStringUUIDSelectedItem() const { - LLScrollListItem* item = getFirstSelected(); + LLScrollListItem* item = getFirstSelected(); - if (item) - { - return item->getUUID(); - } + if (item) + { + return item->getUUID(); + } - return LLUUID::null; + return LLUUID::null; } LLSD LLScrollListCtrl::getSelectedValue() { - LLScrollListItem* item = getFirstSelected(); + LLScrollListItem* item = getFirstSelected(); - if (item) - { - return item->getValue(); - } - else - { - return LLSD(); - } + if (item) + { + return item->getValue(); + } + else + { + return LLSD(); + } } void LLScrollListCtrl::drawItems() { - S32 x = mItemListRect.mLeft; - S32 y = mItemListRect.mTop - mLineHeight; - - // allow for partial line at bottom - S32 num_page_lines = getLinesPerPage(); - - LLRect item_rect; - - LLGLSUIDefault gls_ui; - - F32 alpha = getDrawContext().mAlpha; - - { - LLLocalClipRect clip(mItemListRect); - - S32 cur_y = y; - - S32 max_columns = 0; - - LLColor4 highlight_color = LLColor4::white; // ex: text inside cells - static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); - highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f); - - S32 first_line = mScrollLines; - S32 last_line = llmin((S32)mItemList.size() - 1, mScrollLines + getLinesPerPage()); - - if (first_line >= mItemList.size()) - { - return; - } - item_list::iterator iter; - for (S32 line = first_line; line <= last_line; line++) - { - LLScrollListItem* item = mItemList[line]; - - item_rect.setOriginAndSize( - x, - cur_y, - mItemListRect.getWidth(), - mLineHeight ); - item->setRect(item_rect); - - max_columns = llmax(max_columns, item->getNumColumns()); - - LLColor4 fg_color; - LLColor4 hover_color(LLColor4::transparent); - LLColor4 select_color(LLColor4::transparent); - - if( mScrollLines <= line && line < mScrollLines + num_page_lines ) - { - fg_color = (item->getEnabled() ? mFgUnselectedColor.get() : mFgDisabledColor.get()); - if( item->getSelected() && mCanSelect) - { - if(item->getHighlighted()) // if it's highlighted, average the colors - { - select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); - } - else // otherwise just select-highlight it - { - select_color = mBgSelectedColor.get(); - } - - fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get()); - } - if (mHighlightedItem == line && mCanSelect) - { - if(item->getHighlighted()) // if it's highlighted, average the colors - { - hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); - } - else // otherwise just hover-highlight it - { - hover_color = mHoveredColor.get(); - } - } - else if (item->getHighlighted()) - { - hover_color = mHighlightedColor.get(); - } - else - { - if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) - { - hover_color = mBgStripeColor.get(); - } - } - - if (!item->getEnabled()) - { - hover_color = mBgReadOnlyColor.get(); - } - - item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding); - - cur_y -= mLineHeight; - } - } - } + S32 x = mItemListRect.mLeft; + S32 y = mItemListRect.mTop - mLineHeight; + + // allow for partial line at bottom + S32 num_page_lines = getLinesPerPage(); + + LLRect item_rect; + + LLGLSUIDefault gls_ui; + + F32 alpha = getDrawContext().mAlpha; + + { + LLLocalClipRect clip(mItemListRect); + + S32 cur_y = y; + + S32 max_columns = 0; + + LLColor4 highlight_color = LLColor4::white; // ex: text inside cells + static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); + highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f); + + S32 first_line = mScrollLines; + S32 last_line = llmin((S32)mItemList.size() - 1, mScrollLines + getLinesPerPage()); + + if (first_line >= mItemList.size()) + { + return; + } + item_list::iterator iter; + for (S32 line = first_line; line <= last_line; line++) + { + LLScrollListItem* item = mItemList[line]; + + item_rect.setOriginAndSize( + x, + cur_y, + mItemListRect.getWidth(), + mLineHeight ); + item->setRect(item_rect); + + max_columns = llmax(max_columns, item->getNumColumns()); + + LLColor4 fg_color; + LLColor4 hover_color(LLColor4::transparent); + LLColor4 select_color(LLColor4::transparent); + + if( mScrollLines <= line && line < mScrollLines + num_page_lines ) + { + fg_color = (item->getEnabled() ? mFgUnselectedColor.get() : mFgDisabledColor.get()); + if( item->getSelected() && mCanSelect) + { + if(item->getHighlighted()) // if it's highlighted, average the colors + { + select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f); + } + else // otherwise just select-highlight it + { + select_color = mBgSelectedColor.get(); + } + + fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get()); + } + if (mHighlightedItem == line && mCanSelect) + { + if(item->getHighlighted()) // if it's highlighted, average the colors + { + hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f); + } + else // otherwise just hover-highlight it + { + hover_color = mHoveredColor.get(); + } + } + else if (item->getHighlighted()) + { + hover_color = mHighlightedColor.get(); + } + else + { + if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) + { + hover_color = mBgStripeColor.get(); + } + } + + if (!item->getEnabled()) + { + hover_color = mBgReadOnlyColor.get(); + } + + item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding); + + cur_y -= mLineHeight; + } + } + } } void LLScrollListCtrl::draw() { - LLLocalClipRect clip(getLocalRect()); + LLLocalClipRect clip(getLocalRect()); - // if user specifies sort, make sure it is maintained - updateSort(); + // if user specifies sort, make sure it is maintained + updateSort(); - if (mNeedsScroll) - { - scrollToShowSelected(); - mNeedsScroll = false; - } - LLRect background(0, getRect().getHeight(), getRect().getWidth(), 0); - // Draw background - if (mBackgroundVisible) - { - F32 alpha = getCurrentTransparency(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() % alpha : mBgReadOnlyColor.get() % alpha ); - } + if (mNeedsScroll) + { + scrollToShowSelected(); + mNeedsScroll = false; + } + LLRect background(0, getRect().getHeight(), getRect().getWidth(), 0); + // Draw background + if (mBackgroundVisible) + { + F32 alpha = getCurrentTransparency(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() % alpha : mBgReadOnlyColor.get() % alpha ); + } - updateColumns(); + updateColumns(); - getChildView("comment_text")->setVisible(mItemList.empty()); + getChildView("comment_text")->setVisible(mItemList.empty()); - drawItems(); + drawItems(); - if (mBorder) - { - mBorder->setKeyboardFocusHighlight(hasFocus()); - } + if (mBorder) + { + mBorder->setKeyboardFocusHighlight(hasFocus()); + } - LLUICtrl::draw(); + LLUICtrl::draw(); } void LLScrollListCtrl::setEnabled(BOOL enabled) { - mCanSelect = enabled; - setTabStop(enabled); - mScrollbar->setTabStop(!enabled && mScrollbar->getPageSize() < mScrollbar->getDocSize()); + mCanSelect = enabled; + setTabStop(enabled); + mScrollbar->setTabStop(!enabled && mScrollbar->getPageSize() < mScrollbar->getDocSize()); } BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) { - BOOL handled = FALSE; - // Pretend the mouse is over the scrollbar - handled = mScrollbar->handleScrollWheel( 0, 0, clicks ); + BOOL handled = FALSE; + // Pretend the mouse is over the scrollbar + handled = mScrollbar->handleScrollWheel( 0, 0, clicks ); - if (mMouseWheelOpaque) - { - return TRUE; - } + if (mMouseWheelOpaque) + { + return TRUE; + } - return handled; + return handled; } BOOL LLScrollListCtrl::handleScrollHWheel(S32 x, S32 y, S32 clicks) { - BOOL handled = FALSE; - // Pretend the mouse is over the scrollbar - handled = mScrollbar->handleScrollHWheel( 0, 0, clicks ); + BOOL handled = FALSE; + // Pretend the mouse is over the scrollbar + handled = mScrollbar->handleScrollHWheel( 0, 0, clicks ); - if (mMouseWheelOpaque) - { - return TRUE; - } + if (mMouseWheelOpaque) + { + return TRUE; + } - return handled; + return handled; } // *NOTE: Requires a valid row_index and column_index LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index) { - LLRect cell_rect; - S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft; - S32 rect_bottom = getRowOffsetFromIndex(row_index); - LLScrollListColumn* columnp = getColumn(column_index); - cell_rect.setOriginAndSize(rect_left, rect_bottom, - /*rect_left + */columnp->getWidth(), mLineHeight); - return cell_rect; + LLRect cell_rect; + S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft; + S32 rect_bottom = getRowOffsetFromIndex(row_index); + LLScrollListColumn* columnp = getColumn(column_index); + cell_rect.setOriginAndSize(rect_left, rect_bottom, + /*rect_left + */columnp->getWidth(), mLineHeight); + return cell_rect; } BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask) { - S32 column_index = getColumnIndexFromOffset(x); - LLScrollListColumn* columnp = getColumn(column_index); - - if (columnp == NULL) return FALSE; - - BOOL handled = FALSE; - // show tooltip for full name of hovered item if it has been truncated - LLScrollListItem* hit_item = hitItem(x, y); - if (hit_item) - { - LLScrollListCell* hit_cell = hit_item->getColumn(column_index); - if (!hit_cell) return FALSE; - if (hit_cell - && hit_cell->isText() - && hit_cell->needsToolTip()) - { - S32 row_index = getItemIndex(hit_item); - LLRect cell_rect = getCellRect(row_index, column_index); - // Convert rect local to screen coordinates - LLRect sticky_rect; - localRectToScreen(cell_rect, &sticky_rect); - - // display tooltip exactly over original cell, in same font - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(hit_cell->getToolTip()) - .font(LLFontGL::getFontSansSerifSmall()) - .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6)) - .delay_time(0.2f) - .sticky_rect(sticky_rect)); - } - handled = TRUE; - } - - // otherwise, look for a tooltip associated with this column - LLScrollColumnHeader* headerp = columnp->mHeader; - if (headerp && !handled) - { - handled = headerp->handleToolTip(x, y, mask); - } - - return handled; + S32 column_index = getColumnIndexFromOffset(x); + LLScrollListColumn* columnp = getColumn(column_index); + + if (columnp == NULL) return FALSE; + + BOOL handled = FALSE; + // show tooltip for full name of hovered item if it has been truncated + LLScrollListItem* hit_item = hitItem(x, y); + if (hit_item) + { + LLScrollListCell* hit_cell = hit_item->getColumn(column_index); + if (!hit_cell) return FALSE; + if (hit_cell + && hit_cell->isText() + && hit_cell->needsToolTip()) + { + S32 row_index = getItemIndex(hit_item); + LLRect cell_rect = getCellRect(row_index, column_index); + // Convert rect local to screen coordinates + LLRect sticky_rect; + localRectToScreen(cell_rect, &sticky_rect); + + // display tooltip exactly over original cell, in same font + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(hit_cell->getToolTip()) + .font(LLFontGL::getFontEmojiSmall()) + .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6)) + .delay_time(0.2f) + .sticky_rect(sticky_rect)); + } + handled = TRUE; + } + + // otherwise, look for a tooltip associated with this column + LLScrollColumnHeader* headerp = columnp->mHeader; + if (headerp && !handled) + { + handled = headerp->handleToolTip(x, y, mask); + } + + return handled; } BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { - if (!mCanSelect) return FALSE; - - BOOL selection_changed = FALSE; - - LLScrollListItem* hit_item = hitItem(x, y); - - if( hit_item ) - { - if( mAllowMultipleSelection ) - { - if (mask & MASK_SHIFT) - { - if (mLastSelected == NULL) - { - selectItem(hit_item, getColumnIndexFromOffset(x)); - } - else - { - // Select everthing between mLastSelected and hit_item - bool selecting = false; - item_list::iterator itor; - // If we multiselect backwards, we'll stomp on mLastSelected, - // meaning that we never stop selecting until hitting max or - // the end of the list. - LLScrollListItem* lastSelected = mLastSelected; - for (itor = mItemList.begin(); itor != mItemList.end(); ++itor) - { - if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable) - { - if(mOnMaximumSelectCallback) - { - mOnMaximumSelectCallback(); - } - break; - } - LLScrollListItem *item = *itor; + if (!mCanSelect) return FALSE; + + BOOL selection_changed = FALSE; + + LLScrollListItem* hit_item = hitItem(x, y); + + if( hit_item ) + { + if( mAllowMultipleSelection ) + { + if (mask & MASK_SHIFT) + { + if (mLastSelected == NULL) + { + selectItem(hit_item, getColumnIndexFromOffset(x)); + } + else + { + // Select everthing between mLastSelected and hit_item + bool selecting = false; + item_list::iterator itor; + // If we multiselect backwards, we'll stomp on mLastSelected, + // meaning that we never stop selecting until hitting max or + // the end of the list. + LLScrollListItem* lastSelected = mLastSelected; + for (itor = mItemList.begin(); itor != mItemList.end(); ++itor) + { + if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable) + { + if(mOnMaximumSelectCallback) + { + mOnMaximumSelectCallback(); + } + break; + } + LLScrollListItem *item = *itor; if (item == hit_item || item == lastSelected) - { - selectItem(item, getColumnIndexFromOffset(x), FALSE); - selecting = !selecting; - if (hit_item == lastSelected) - { - // stop selecting now, since we just clicked on our last selected item - selecting = FALSE; - } - } - if (selecting) - { - selectItem(item, getColumnIndexFromOffset(x), FALSE); - } - } - } - } - else if (mask & MASK_CONTROL) - { - if (hit_item->getSelected()) - { - deselectItem(hit_item); - } - else - { - if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)) - { - selectItem(hit_item, getColumnIndexFromOffset(x), FALSE); - } - else - { - if(mOnMaximumSelectCallback) - { - mOnMaximumSelectCallback(); - } - } - } - } - else - { - deselectAllItems(TRUE); - selectItem(hit_item, getColumnIndexFromOffset(x)); - } - } - else - { - selectItem(hit_item, getColumnIndexFromOffset(x)); - } - - selection_changed = mSelectionChanged; - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } - - // clear search string on mouse operations - mSearchString.clear(); - } - else - { - //mLastSelected = NULL; - //deselectAllItems(TRUE); - } - - return selection_changed; + { + selectItem(item, getColumnIndexFromOffset(x), FALSE); + selecting = !selecting; + if (hit_item == lastSelected) + { + // stop selecting now, since we just clicked on our last selected item + selecting = FALSE; + } + } + if (selecting) + { + selectItem(item, getColumnIndexFromOffset(x), FALSE); + } + } + } + } + else if (mask & MASK_CONTROL) + { + if (hit_item->getSelected()) + { + deselectItem(hit_item); + } + else + { + if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)) + { + selectItem(hit_item, getColumnIndexFromOffset(x), FALSE); + } + else + { + if(mOnMaximumSelectCallback) + { + mOnMaximumSelectCallback(); + } + } + } + } + else + { + deselectAllItems(TRUE); + selectItem(hit_item, getColumnIndexFromOffset(x)); + } + } + else + { + selectItem(hit_item, getColumnIndexFromOffset(x)); + } + + selection_changed = mSelectionChanged; + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } + + // clear search string on mouse operations + mSearchString.clear(); + } + else + { + //mLastSelected = NULL; + //deselectAllItems(TRUE); + } + + return selection_changed; } BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = childrenHandleMouseDown(x, y, mask) != NULL; + BOOL handled = childrenHandleMouseDown(x, y, mask) != NULL; - if( !handled ) - { - // set keyboard focus first, in case click action wants to move focus elsewhere - setFocus(TRUE); + if( !handled ) + { + // set keyboard focus first, in case click action wants to move focus elsewhere + setFocus(TRUE); - // clear selection changed flag because user is starting a selection operation - mSelectionChanged = false; + // clear selection changed flag because user is starting a selection operation + mSelectionChanged = false; - handleClick(x, y, mask); - } + handleClick(x, y, mask); + } - return TRUE; + return TRUE; } BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask) -{ - if (hasMouseCapture()) - { - // release mouse capture immediately so - // scroll to show selected logic will work - gFocusMgr.setMouseCapture(NULL); - if(mask == MASK_NONE) - { - selectItemAt(x, y, mask); - mNeedsScroll = true; - } - } - - // always commit when mouse operation is completed inside list - if (mItemListRect.pointInRect(x,y)) - { - mDirty = mDirty || mSelectionChanged; - mSelectionChanged = false; - onCommit(); - } - - return LLUICtrl::handleMouseUp(x, y, mask); +{ + if (hasMouseCapture()) + { + // release mouse capture immediately so + // scroll to show selected logic will work + gFocusMgr.setMouseCapture(NULL); + if(mask == MASK_NONE) + { + selectItemAt(x, y, mask); + mNeedsScroll = true; + } + } + + // always commit when mouse operation is completed inside list + if (mItemListRect.pointInRect(x,y)) + { + mDirty = mDirty || mSelectionChanged; + mSelectionChanged = false; + onCommit(); + } + + return LLUICtrl::handleMouseUp(x, y, mask); } // virtual BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLScrollListItem *item = hitItem(x, y); - if (item) - { - // check to see if we have a UUID for this row - std::string id = item->getValue().asString(); - LLUUID uuid(id); - if (! uuid.isNull() && mContextMenuType != MENU_NONE) - { - // set up the callbacks for all of the avatar/group menu items - // (N.B. callbacks don't take const refs as id is local scope) - bool is_group = (mContextMenuType == MENU_GROUP); - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group)); - registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id)); - registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id)); - registrar.add("Url.RemoveFriend", boost::bind(&LLScrollListCtrl::removeFriend, id)); + LLScrollListItem *item = hitItem(x, y); + if (item) + { + // check to see if we have a UUID for this row + std::string id = item->getValue().asString(); + LLUUID uuid(id); + if (! uuid.isNull() && mContextMenuType != MENU_NONE) + { + // set up the callbacks for all of the avatar/group menu items + // (N.B. callbacks don't take const refs as id is local scope) + bool is_group = (mContextMenuType == MENU_GROUP); + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group)); + registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id)); + registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id)); + registrar.add("Url.RemoveFriend", boost::bind(&LLScrollListCtrl::removeFriend, id)); registrar.add("Url.ReportAbuse", boost::bind(&LLScrollListCtrl::reportAbuse, id, is_group)); - registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group)); - registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group)); - registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group)); - - // create the context menu from the XUI file and display it - std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; - auto menu = mPopupMenuHandle.get(); - if (menu) - { - menu->die(); - mPopupMenuHandle.markDead(); - } - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( - menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); - if (menu) - { - mPopupMenuHandle = menu->getHandle(); - if (mIsFriendSignal) - { - bool isFriend = *(*mIsFriendSignal)(uuid); - LLView* addFriendButton = menu->getChild<LLView>("add_friend"); - LLView* removeFriendButton = menu->getChild<LLView>("remove_friend"); - - if (addFriendButton && removeFriendButton) - { - addFriendButton->setEnabled(!isFriend); - removeFriendButton->setEnabled(isFriend); - } - } - - menu->show(x, y); - LLMenuGL::showPopup(this, menu, x, y); - return TRUE; - } - } - return LLUICtrl::handleRightMouseDown(x, y, mask); - } - return FALSE; + registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group)); + registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group)); + registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group)); + + // create the context menu from the XUI file and display it + std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; + auto menu = mPopupMenuHandle.get(); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( + menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + if (menu) + { + mPopupMenuHandle = menu->getHandle(); + if (mIsFriendSignal) + { + bool isFriend = *(*mIsFriendSignal)(uuid); + LLView* addFriendButton = menu->getChild<LLView>("add_friend"); + LLView* removeFriendButton = menu->getChild<LLView>("remove_friend"); + + if (addFriendButton && removeFriendButton) + { + addFriendButton->setEnabled(!isFriend); + removeFriendButton->setEnabled(isFriend); + } + } + + menu->show(x, y); + LLMenuGL::showPopup(this, menu, x, y); + return TRUE; + } + } + return LLUICtrl::handleRightMouseDown(x, y, mask); + } + return FALSE; } void LLScrollListCtrl::showProfile(std::string id, bool is_group) { - // show the resident's profile or the group profile - std::string sltype = is_group ? "group" : "agent"; - std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; - LLUrlAction::showProfile(slurl); + // show the resident's profile or the group profile + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::showProfile(slurl); } void LLScrollListCtrl::sendIM(std::string id) { - // send im to the resident - std::string slurl = "secondlife:///app/agent/" + id + "/about"; - LLUrlAction::sendIM(slurl); + // send im to the resident + std::string slurl = "secondlife:///app/agent/" + id + "/about"; + LLUrlAction::sendIM(slurl); } void LLScrollListCtrl::addFriend(std::string id) { - // add resident to friends list - std::string slurl = "secondlife:///app/agent/" + id + "/about"; - LLUrlAction::addFriend(slurl); + // add resident to friends list + std::string slurl = "secondlife:///app/agent/" + id + "/about"; + LLUrlAction::addFriend(slurl); } void LLScrollListCtrl::removeFriend(std::string id) { - std::string slurl = "secondlife:///app/agent/" + id + "/about"; - LLUrlAction::removeFriend(slurl); + std::string slurl = "secondlife:///app/agent/" + id + "/about"; + LLUrlAction::removeFriend(slurl); } void LLScrollListCtrl::reportAbuse(std::string id, bool is_group) @@ -2077,225 +2077,225 @@ void LLScrollListCtrl::reportAbuse(std::string id, bool is_group) void LLScrollListCtrl::showNameDetails(std::string id, bool is_group) { - // open the resident's details or the group details - std::string sltype = is_group ? "group" : "agent"; - std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; - LLUrlAction::clickAction(slurl, true); + // open the resident's details or the group details + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::clickAction(slurl, true); } void LLScrollListCtrl::copyNameToClipboard(std::string id, bool is_group) { - // copy the name of the avatar or group to the clipboard - std::string name; - if (is_group) - { - gCacheName->getGroupName(LLUUID(id), name); - } - else - { - LLAvatarName av_name; - LLAvatarNameCache::get(LLUUID(id), &av_name); - name = av_name.getAccountName(); - } - LLUrlAction::copyURLToClipboard(name); + // copy the name of the avatar or group to the clipboard + std::string name; + if (is_group) + { + gCacheName->getGroupName(LLUUID(id), name); + } + else + { + LLAvatarName av_name; + LLAvatarNameCache::get(LLUUID(id), &av_name); + name = av_name.getAccountName(); + } + LLUrlAction::copyURLToClipboard(name); } void LLScrollListCtrl::copySLURLToClipboard(std::string id, bool is_group) { - // copy a SLURL for the avatar or group to the clipboard - std::string sltype = is_group ? "group" : "agent"; - std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; - LLUrlAction::copyURLToClipboard(slurl); + // copy a SLURL for the avatar or group to the clipboard + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::copyURLToClipboard(slurl); } BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { - //BOOL handled = FALSE; - BOOL handled = handleClick(x, y, mask); + //BOOL handled = FALSE; + BOOL handled = handleClick(x, y, mask); - if (!handled) - { - // Offer the click to the children, even if we aren't enabled - // so the scroll bars will work. - if (NULL == LLView::childrenHandleDoubleClick(x, y, mask)) - { - // Run the callback only if an item is being double-clicked. - if( mCanSelect && hitItem(x, y) && mOnDoubleClickCallback ) - { - mOnDoubleClickCallback(); - } - } - } + if (!handled) + { + // Offer the click to the children, even if we aren't enabled + // so the scroll bars will work. + if (NULL == LLView::childrenHandleDoubleClick(x, y, mask)) + { + // Run the callback only if an item is being double-clicked. + if( mCanSelect && hitItem(x, y) && mOnDoubleClickCallback ) + { + mOnDoubleClickCallback(); + } + } + } - return TRUE; + return TRUE; } BOOL LLScrollListCtrl::handleClick(S32 x, S32 y, MASK mask) { - // which row was clicked on? - LLScrollListItem* hit_item = hitItem(x, y); - if (!hit_item) return FALSE; - - // get appropriate cell from that row - S32 column_index = getColumnIndexFromOffset(x); - LLScrollListCell* hit_cell = hit_item->getColumn(column_index); - if (!hit_cell) return FALSE; - - // if cell handled click directly (i.e. clicked on an embedded checkbox) - if (hit_cell->handleClick()) - { - // if item not currently selected, select it - if (!hit_item->getSelected()) - { - selectItemAt(x, y, mask); - gFocusMgr.setMouseCapture(this); - mNeedsScroll = true; - } - - // propagate state of cell to rest of selected column - { - // propagate value of this cell to other selected items - // and commit the respective widgets - LLSD item_value = hit_cell->getValue(); - for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if (item->getSelected()) - { - LLScrollListCell* cellp = item->getColumn(column_index); - cellp->setValue(item_value); - cellp->onCommit(); - if (mLastSelected == NULL) - { - break; - } - } - } - //FIXME: find a better way to signal cell changes - onCommit(); - } - // eat click (e.g. do not trigger double click callback) - return TRUE; - } - else - { - // treat this as a normal single item selection - selectItemAt(x, y, mask); - gFocusMgr.setMouseCapture(this); - mNeedsScroll = true; - // do not eat click (allow double click callback) - return FALSE; - } + // which row was clicked on? + LLScrollListItem* hit_item = hitItem(x, y); + if (!hit_item) return FALSE; + + // get appropriate cell from that row + S32 column_index = getColumnIndexFromOffset(x); + LLScrollListCell* hit_cell = hit_item->getColumn(column_index); + if (!hit_cell) return FALSE; + + // if cell handled click directly (i.e. clicked on an embedded checkbox) + if (hit_cell->handleClick()) + { + // if item not currently selected, select it + if (!hit_item->getSelected()) + { + selectItemAt(x, y, mask); + gFocusMgr.setMouseCapture(this); + mNeedsScroll = true; + } + + // propagate state of cell to rest of selected column + { + // propagate value of this cell to other selected items + // and commit the respective widgets + LLSD item_value = hit_cell->getValue(); + for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + LLScrollListCell* cellp = item->getColumn(column_index); + cellp->setValue(item_value); + cellp->onCommit(); + if (mLastSelected == NULL) + { + break; + } + } + } + //FIXME: find a better way to signal cell changes + onCommit(); + } + // eat click (e.g. do not trigger double click callback) + return TRUE; + } + else + { + // treat this as a normal single item selection + selectItemAt(x, y, mask); + gFocusMgr.setMouseCapture(this); + mNeedsScroll = true; + // do not eat click (allow double click callback) + return FALSE; + } } LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) { - // Excludes disabled items. - LLScrollListItem* hit_item = NULL; + // Excludes disabled items. + LLScrollListItem* hit_item = NULL; - updateSort(); + updateSort(); - LLRect item_rect; - item_rect.setLeftTopAndSize( - mItemListRect.mLeft, - mItemListRect.mTop, - mItemListRect.getWidth(), - mLineHeight ); + LLRect item_rect; + item_rect.setLeftTopAndSize( + mItemListRect.mLeft, + mItemListRect.mTop, + mItemListRect.getWidth(), + mLineHeight ); - // allow for partial line at bottom - S32 num_page_lines = getLinesPerPage(); + // allow for partial line at bottom + S32 num_page_lines = getLinesPerPage(); - S32 line = 0; - item_list::iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem* item = *iter; - if( mScrollLines <= line && line < mScrollLines + num_page_lines ) - { - if( item->getEnabled() && item_rect.pointInRect( x, y ) ) - { - hit_item = item; - break; - } + S32 line = 0; + item_list::iterator iter; + for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem* item = *iter; + if( mScrollLines <= line && line < mScrollLines + num_page_lines ) + { + if( item->getEnabled() && item_rect.pointInRect( x, y ) ) + { + hit_item = item; + break; + } - item_rect.translate(0, -mLineHeight); - } - line++; - } + item_rect.translate(0, -mLineHeight); + } + line++; + } - return hit_item; + return hit_item; } S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x) { - // which column did we hit? - S32 left = 0; - S32 right = 0; - S32 width = 0; - S32 column_index = 0; + // which column did we hit? + S32 left = 0; + S32 right = 0; + S32 width = 0; + S32 column_index = 0; + + ordered_columns_t::const_iterator iter = mColumnsIndexed.begin(); + ordered_columns_t::const_iterator end = mColumnsIndexed.end(); + for ( ; iter != end; ++iter) + { + width = (*iter)->getWidth() + mColumnPadding; + right += width; + if (left <= x && x < right ) + { + break; + } - ordered_columns_t::const_iterator iter = mColumnsIndexed.begin(); - ordered_columns_t::const_iterator end = mColumnsIndexed.end(); - for ( ; iter != end; ++iter) - { - width = (*iter)->getWidth() + mColumnPadding; - right += width; - if (left <= x && x < right ) - { - break; - } - - // set left for next column as right of current column - left = right; - column_index++; - } + // set left for next column as right of current column + left = right; + column_index++; + } - return llclamp(column_index, 0, getNumColumns() - 1); + return llclamp(column_index, 0, getNumColumns() - 1); } S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index) { - S32 column_offset = 0; - ordered_columns_t::const_iterator iter = mColumnsIndexed.begin(); - ordered_columns_t::const_iterator end = mColumnsIndexed.end(); - for ( ; iter != end; ++iter) - { - if (index-- <= 0) - { - return column_offset; - } - column_offset += (*iter)->getWidth() + mColumnPadding; - } + S32 column_offset = 0; + ordered_columns_t::const_iterator iter = mColumnsIndexed.begin(); + ordered_columns_t::const_iterator end = mColumnsIndexed.end(); + for ( ; iter != end; ++iter) + { + if (index-- <= 0) + { + return column_offset; + } + column_offset += (*iter)->getWidth() + mColumnPadding; + } - // when running off the end, return the rightmost pixel - return mItemListRect.mRight; + // when running off the end, return the rightmost pixel + return mItemListRect.mRight; } S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index) { - S32 row_bottom = (mItemListRect.mTop - ((index - mScrollLines + 1) * mLineHeight) ); - return row_bottom; + S32 row_bottom = (mItemListRect.mTop - ((index - mScrollLines + 1) * mLineHeight) ); + return row_bottom; } BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { - BOOL handled = FALSE; - - if (hasMouseCapture()) - { - if(mask == MASK_NONE) - { - selectItemAt(x, y, mask); - mNeedsScroll = true; - } - } - else - if (mCanSelect) - { - LLScrollListItem* item = hitItem(x, y); - if (item) + BOOL handled = FALSE; + + if (hasMouseCapture()) + { + if(mask == MASK_NONE) + { + selectItemAt(x, y, mask); + mNeedsScroll = true; + } + } + else + if (mCanSelect) + { + LLScrollListItem* item = hitItem(x, y); + if (item) { mouseOverHighlightNthItem(getItemIndex(item)); switch (mSelectionType) @@ -2319,53 +2319,53 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) case ROW: break; } - } - else - { - mouseOverHighlightNthItem(-1); - } - } + } + else + { + mouseOverHighlightNthItem(-1); + } + } - handled = LLUICtrl::handleHover( x, y, mask ); + handled = LLUICtrl::handleHover( x, y, mask ); - return handled; + return handled; } void LLScrollListCtrl::onMouseLeave(S32 x, S32 y, MASK mask) { - // clear mouse highlight - mouseOverHighlightNthItem(-1); + // clear mouse highlight + mouseOverHighlightNthItem(-1); } BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask ) { - BOOL handled = FALSE; - - // not called from parent means we have keyboard focus or a child does - if (mCanSelect) - { - if (mask == MASK_NONE) - { - switch(key) - { - case KEY_UP: - if (mAllowKeyboardMovement || hasFocus()) - { - // commit implicit in call - selectPrevItem(FALSE); - mNeedsScroll = true; - handled = TRUE; - } - break; - case KEY_DOWN: - if (mAllowKeyboardMovement || hasFocus()) - { - // commit implicit in call - selectNextItem(FALSE); - mNeedsScroll = true; - handled = TRUE; - } - break; + BOOL handled = FALSE; + + // not called from parent means we have keyboard focus or a child does + if (mCanSelect) + { + if (mask == MASK_NONE) + { + switch(key) + { + case KEY_UP: + if (mAllowKeyboardMovement || hasFocus()) + { + // commit implicit in call + selectPrevItem(FALSE); + mNeedsScroll = true; + handled = TRUE; + } + break; + case KEY_DOWN: + if (mAllowKeyboardMovement || hasFocus()) + { + // commit implicit in call + selectNextItem(FALSE); + mNeedsScroll = true; + handled = TRUE; + } + break; case KEY_LEFT: if (mAllowKeyboardMovement || hasFocus()) { @@ -2418,245 +2418,245 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask ) } } break; - case KEY_PAGE_UP: - if (mAllowKeyboardMovement || hasFocus()) - { - selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1)); - mNeedsScroll = true; - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - handled = TRUE; - } - break; - case KEY_PAGE_DOWN: - if (mAllowKeyboardMovement || hasFocus()) - { - selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1)); - mNeedsScroll = true; - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - handled = TRUE; - } - break; - case KEY_HOME: - if (mAllowKeyboardMovement || hasFocus()) - { - selectFirstItem(); - mNeedsScroll = true; - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - handled = TRUE; - } - break; - case KEY_END: - if (mAllowKeyboardMovement || hasFocus()) - { - selectNthItem(getItemCount() - 1); - mNeedsScroll = true; - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - handled = TRUE; - } - break; - case KEY_RETURN: - // JC - Special case: Only claim to have handled it - // if we're the special non-commit-on-move - // type. AND we are visible - if (!mCommitOnKeyboardMovement && mask == MASK_NONE) - { - onCommit(); - mSearchString.clear(); - handled = TRUE; - } - break; - case KEY_BACKSPACE: - mSearchTimer.reset(); - if (mSearchString.size()) - { - mSearchString.erase(mSearchString.size() - 1, 1); - } - if (mSearchString.empty()) - { - if (getFirstSelected()) - { - LLScrollListCell* cellp = getFirstSelected()->getColumn(getSearchColumn()); - if (cellp) - { - cellp->highlightText(0, 0); - } - } - } - else if (selectItemByPrefix(wstring_to_utf8str(mSearchString), FALSE)) - { - mNeedsScroll = true; - // update search string only on successful match - mSearchTimer.reset(); - - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - } - break; - default: - break; - } - } - // TODO: multiple: shift-up, shift-down, shift-home, shift-end, select all - } - - return handled; + case KEY_PAGE_UP: + if (mAllowKeyboardMovement || hasFocus()) + { + selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1)); + mNeedsScroll = true; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + handled = TRUE; + } + break; + case KEY_PAGE_DOWN: + if (mAllowKeyboardMovement || hasFocus()) + { + selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1)); + mNeedsScroll = true; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + handled = TRUE; + } + break; + case KEY_HOME: + if (mAllowKeyboardMovement || hasFocus()) + { + selectFirstItem(); + mNeedsScroll = true; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + handled = TRUE; + } + break; + case KEY_END: + if (mAllowKeyboardMovement || hasFocus()) + { + selectNthItem(getItemCount() - 1); + mNeedsScroll = true; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + handled = TRUE; + } + break; + case KEY_RETURN: + // JC - Special case: Only claim to have handled it + // if we're the special non-commit-on-move + // type. AND we are visible + if (!mCommitOnKeyboardMovement && mask == MASK_NONE) + { + onCommit(); + mSearchString.clear(); + handled = TRUE; + } + break; + case KEY_BACKSPACE: + mSearchTimer.reset(); + if (mSearchString.size()) + { + mSearchString.erase(mSearchString.size() - 1, 1); + } + if (mSearchString.empty()) + { + if (getFirstSelected()) + { + LLScrollListCell* cellp = getFirstSelected()->getColumn(getSearchColumn()); + if (cellp) + { + cellp->highlightText(0, 0); + } + } + } + else if (selectItemByPrefix(wstring_to_utf8str(mSearchString), FALSE)) + { + mNeedsScroll = true; + // update search string only on successful match + mSearchTimer.reset(); + + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + } + break; + default: + break; + } + } + // TODO: multiple: shift-up, shift-down, shift-home, shift-end, select all + } + + return handled; } BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } - - // perform incremental search based on keyboard input - static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); - if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout) - { - mSearchString.clear(); - } - - // type ahead search is case insensitive - uni_char = LLStringOps::toLower((llwchar)uni_char); - - if (selectItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE)) - { - // update search string only on successful match - mNeedsScroll = true; - mSearchString += uni_char; - mSearchTimer.reset(); - - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - } - // handle iterating over same starting character - else if (isRepeatedChars(mSearchString + (llwchar)uni_char) && !mItemList.empty()) - { - // start from last selected item, in case we previously had a successful match against - // duplicated characters ('AA' matches 'Aaron') - item_list::iterator start_iter = mItemList.begin(); - S32 first_selected = getFirstSelectedIndex(); - - // if we have a selection (> -1) then point iterator at the selected item - if (first_selected > 0) - { - // point iterator to first selected item - start_iter += first_selected; - } - - // start search at first item after current selection - item_list::iterator iter = start_iter; - ++iter; - if (iter == mItemList.end()) - { - iter = mItemList.begin(); - } - - // loop around once, back to previous selection - while(iter != start_iter) - { - LLScrollListItem* item = *iter; - - LLScrollListCell* cellp = item->getColumn(getSearchColumn()); - if (cellp) - { - // Only select enabled items with matching first characters - LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); - if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) - { - selectItem(item, -1); - mNeedsScroll = true; - cellp->highlightText(0, 1); - mSearchTimer.reset(); - - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) - { - onCommit(); - } - - break; - } - } - - ++iter; - if (iter == mItemList.end()) - { - iter = mItemList.begin(); - } - } - } - - return TRUE; + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } + + // perform incremental search based on keyboard input + static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout) + { + mSearchString.clear(); + } + + // type ahead search is case insensitive + uni_char = LLStringOps::toLower((llwchar)uni_char); + + if (selectItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE)) + { + // update search string only on successful match + mNeedsScroll = true; + mSearchString += uni_char; + mSearchTimer.reset(); + + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + } + // handle iterating over same starting character + else if (isRepeatedChars(mSearchString + (llwchar)uni_char) && !mItemList.empty()) + { + // start from last selected item, in case we previously had a successful match against + // duplicated characters ('AA' matches 'Aaron') + item_list::iterator start_iter = mItemList.begin(); + S32 first_selected = getFirstSelectedIndex(); + + // if we have a selection (> -1) then point iterator at the selected item + if (first_selected > 0) + { + // point iterator to first selected item + start_iter += first_selected; + } + + // start search at first item after current selection + item_list::iterator iter = start_iter; + ++iter; + if (iter == mItemList.end()) + { + iter = mItemList.begin(); + } + + // loop around once, back to previous selection + while(iter != start_iter) + { + LLScrollListItem* item = *iter; + + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); + if (cellp) + { + // Only select enabled items with matching first characters + LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); + if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) + { + selectItem(item, -1); + mNeedsScroll = true; + cellp->highlightText(0, 1); + mSearchTimer.reset(); + + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + + break; + } + } + + ++iter; + if (iter == mItemList.end()) + { + iter = mItemList.begin(); + } + } + } + + return TRUE; } void LLScrollListCtrl::reportInvalidInput() { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const { - if (string.empty()) - { - return FALSE; - } + if (string.empty()) + { + return FALSE; + } - llwchar first_char = string[0]; + llwchar first_char = string[0]; - for (U32 i = 0; i < string.size(); i++) - { - if (string[i] != first_char) - { - return FALSE; - } - } + for (U32 i = 0; i < string.size(); i++) + { + if (string[i] != first_char) + { + return FALSE; + } + } - return TRUE; + return TRUE; } void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item) { - if (!itemp) return; - - if (!itemp->getSelected()) - { - if (mLastSelected) - { - LLScrollListCell* cellp = mLastSelected->getColumn(getSearchColumn()); - if (cellp) - { - cellp->highlightText(0, 0); - } - } - if (select_single_item) - { - deselectAllItems(TRUE); - } - itemp->setSelected(TRUE); + if (!itemp) return; + + if (!itemp->getSelected()) + { + if (mLastSelected) + { + LLScrollListCell* cellp = mLastSelected->getColumn(getSearchColumn()); + if (cellp) + { + cellp->highlightText(0, 0); + } + } + if (select_single_item) + { + deselectAllItems(TRUE); + } + itemp->setSelected(TRUE); switch (mSelectionType) { case CELL: @@ -2669,743 +2669,743 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select itemp->setSelectedCell(-1); break; } - mLastSelected = itemp; - mSelectionChanged = true; - } + mLastSelected = itemp; + mSelectionChanged = true; + } } void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp) { - if (!itemp) return; + if (!itemp) return; - if (itemp->getSelected()) - { - if (mLastSelected == itemp) - { - mLastSelected = NULL; - } + if (itemp->getSelected()) + { + if (mLastSelected == itemp) + { + mLastSelected = NULL; + } - itemp->setSelected(FALSE); - LLScrollListCell* cellp = itemp->getColumn(getSearchColumn()); - if (cellp) - { - cellp->highlightText(0, 0); - } - mSelectionChanged = true; - } + itemp->setSelected(FALSE); + LLScrollListCell* cellp = itemp->getColumn(getSearchColumn()); + if (cellp) + { + cellp->highlightText(0, 0); + } + mSelectionChanged = true; + } } void LLScrollListCtrl::commitIfChanged() { - if (mSelectionChanged) - { - mDirty = true; - mSelectionChanged = FALSE; - onCommit(); - } + if (mSelectionChanged) + { + mDirty = true; + mSelectionChanged = FALSE; + onCommit(); + } } struct SameSortColumn { - SameSortColumn(S32 column) : mColumn(column) {} - S32 mColumn; + SameSortColumn(S32 column) : mColumn(column) {} + S32 mColumn; - bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; } + bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; } }; BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) { - LLScrollListColumn* sort_column = getColumn(column_idx); - if (!sort_column) return FALSE; + LLScrollListColumn* sort_column = getColumn(column_idx); + if (!sort_column) return FALSE; - sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING; + sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING; - sort_column_t new_sort_column(column_idx, ascending); - - setNeedsSort(); + sort_column_t new_sort_column(column_idx, ascending); - if (mSortColumns.empty()) - { - mSortColumns.push_back(new_sort_column); - return TRUE; - } - else - { - // grab current sort column - sort_column_t cur_sort_column = mSortColumns.back(); - - // remove any existing sort criterion referencing this column - // and add the new one - mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column_idx)), mSortColumns.end()); - mSortColumns.push_back(new_sort_column); + setNeedsSort(); - // did the sort criteria change? - return (cur_sort_column != new_sort_column); - } + if (mSortColumns.empty()) + { + mSortColumns.push_back(new_sort_column); + return TRUE; + } + else + { + // grab current sort column + sort_column_t cur_sort_column = mSortColumns.back(); + + // remove any existing sort criterion referencing this column + // and add the new one + mSortColumns.erase(remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column_idx)), mSortColumns.end()); + mSortColumns.push_back(new_sort_column); + + // did the sort criteria change? + return (cur_sort_column != new_sort_column); + } } -S32 LLScrollListCtrl::getLinesPerPage() +S32 LLScrollListCtrl::getLinesPerPage() { - //if mPageLines is NOT provided display all item - if (mPageLines) - { - return mPageLines; - } - else - { - return mLineHeight ? mItemListRect.getHeight() / mLineHeight : getItemCount(); - } + //if mPageLines is NOT provided display all item + if (mPageLines) + { + return mPageLines; + } + else + { + return mLineHeight ? mItemListRect.getHeight() / mLineHeight : getItemCount(); + } } // Called by scrollbar void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar ) { - mScrollLines = new_pos; + mScrollLines = new_pos; } void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending) { - column_map_t::iterator itor = mColumns.find(name); - if (itor != mColumns.end()) - { - sortByColumnIndex((*itor).second->mIndex, ascending); - } + column_map_t::iterator itor = mColumns.find(name); + if (itor != mColumns.end()) + { + sortByColumnIndex((*itor).second->mIndex, ascending); + } } // First column is column 0 void LLScrollListCtrl::sortByColumnIndex(U32 column, BOOL ascending) { - setSort(column, ascending); - updateSort(); + setSort(column, ascending); + updateSort(); } void LLScrollListCtrl::updateSort() const { - if (hasSortOrder() && !isSorted()) - { - // do stable sort to preserve any previous sorts - std::stable_sort( - mItemList.begin(), - mItemList.end(), - SortScrollListItem(mSortColumns,mSortCallback, mAlternateSort)); + if (hasSortOrder() && !isSorted()) + { + // do stable sort to preserve any previous sorts + std::stable_sort( + mItemList.begin(), + mItemList.end(), + SortScrollListItem(mSortColumns,mSortCallback, mAlternateSort)); - mSorted = true; - } + mSorted = true; + } } // for one-shot sorts, does not save sort column/order void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending) { - std::vector<std::pair<S32, BOOL> > sort_column; - sort_column.push_back(std::make_pair(column, ascending)); + std::vector<std::pair<S32, BOOL> > sort_column; + sort_column.push_back(std::make_pair(column, ascending)); - // do stable sort to preserve any previous sorts - std::stable_sort( - mItemList.begin(), - mItemList.end(), - SortScrollListItem(sort_column,mSortCallback,mAlternateSort)); + // do stable sort to preserve any previous sorts + std::stable_sort( + mItemList.begin(), + mItemList.end(), + SortScrollListItem(sort_column,mSortCallback,mAlternateSort)); } -void LLScrollListCtrl::dirtyColumns() -{ - mColumnsDirty = true; - mColumnWidthsDirty = true; +void LLScrollListCtrl::dirtyColumns() +{ + mColumnsDirty = true; + mColumnWidthsDirty = true; - // need to keep mColumnsIndexed up to date - // just in case someone indexes into it immediately - mColumnsIndexed.resize(mColumns.size()); + // need to keep mColumnsIndexed up to date + // just in case someone indexes into it immediately + mColumnsIndexed.resize(mColumns.size()); - column_map_t::iterator column_itor; - for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor) - { - LLScrollListColumn *column = column_itor->second; - mColumnsIndexed[column_itor->second->mIndex] = column; - } + column_map_t::iterator column_itor; + for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor) + { + LLScrollListColumn *column = column_itor->second; + mColumnsIndexed[column_itor->second->mIndex] = column; + } } S32 LLScrollListCtrl::getScrollPos() const { - return mScrollbar->getDocPos(); + return mScrollbar->getDocPos(); } void LLScrollListCtrl::setScrollPos( S32 pos ) { - mScrollbar->setDocPos( pos ); + mScrollbar->setDocPos( pos ); - onScrollChange(mScrollbar->getDocPos(), mScrollbar); + onScrollChange(mScrollbar->getDocPos(), mScrollbar); } void LLScrollListCtrl::scrollToShowSelected() { - // don't scroll automatically when capturing mouse input - // as that will change what is currently under the mouse cursor - if (hasMouseCapture()) - { - return; - } - - updateSort(); - - S32 index = getFirstSelectedIndex(); - if (index < 0) - { - return; - } - - LLScrollListItem* item = mItemList[index]; - if (!item) - { - // I don't THINK this should ever happen. - return; - } - - S32 lowest = mScrollLines; - S32 page_lines = getLinesPerPage(); - S32 highest = mScrollLines + page_lines; - - if (index < lowest) - { - // need to scroll to show item - setScrollPos(index); - } - else if (highest <= index) - { - setScrollPos(index - page_lines + 1); - } + // don't scroll automatically when capturing mouse input + // as that will change what is currently under the mouse cursor + if (hasMouseCapture()) + { + return; + } + + updateSort(); + + S32 index = getFirstSelectedIndex(); + if (index < 0) + { + return; + } + + LLScrollListItem* item = mItemList[index]; + if (!item) + { + // I don't THINK this should ever happen. + return; + } + + S32 lowest = mScrollLines; + S32 page_lines = getLinesPerPage(); + S32 highest = mScrollLines + page_lines; + + if (index < lowest) + { + // need to scroll to show item + setScrollPos(index); + } + else if (highest <= index) + { + setScrollPos(index - page_lines + 1); + } } void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width) { - mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth()); + mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth()); } // LLEditMenuHandler functions // virtual -void LLScrollListCtrl::copy() +void LLScrollListCtrl::copy() { - std::string buffer; + std::string buffer; - std::vector<LLScrollListItem*> items = getAllSelected(); - std::vector<LLScrollListItem*>::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) - { - buffer += (*itor)->getContentsCSV() + "\n"; - } - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length()); + std::vector<LLScrollListItem*> items = getAllSelected(); + std::vector<LLScrollListItem*>::iterator itor; + for (itor = items.begin(); itor != items.end(); ++itor) + { + buffer += (*itor)->getContentsCSV() + "\n"; + } + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(buffer), 0, buffer.length()); } // virtual -BOOL LLScrollListCtrl::canCopy() const +BOOL LLScrollListCtrl::canCopy() const { - return (getFirstSelected() != NULL); + return (getFirstSelected() != NULL); } // virtual -void LLScrollListCtrl::cut() +void LLScrollListCtrl::cut() { - copy(); - doDelete(); + copy(); + doDelete(); } // virtual -BOOL LLScrollListCtrl::canCut() const +BOOL LLScrollListCtrl::canCut() const { - return canCopy() && canDoDelete(); + return canCopy() && canDoDelete(); } // virtual -void LLScrollListCtrl::selectAll() +void LLScrollListCtrl::selectAll() { - // Deselects all other items - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) - { - LLScrollListItem *itemp = *iter; - if( itemp->getEnabled() ) - { - selectItem(itemp, -1, FALSE); - } - } + // Deselects all other items + item_list::iterator iter; + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + { + LLScrollListItem *itemp = *iter; + if( itemp->getEnabled() ) + { + selectItem(itemp, -1, FALSE); + } + } - if (mCommitOnSelectionChange) - { - commitIfChanged(); - } + if (mCommitOnSelectionChange) + { + commitIfChanged(); + } } // virtual -BOOL LLScrollListCtrl::canSelectAll() const +BOOL LLScrollListCtrl::canSelectAll() const { - return getCanSelect() && mAllowMultipleSelection && !(mMaxSelectable > 0 && mItemList.size() > mMaxSelectable); + return getCanSelect() && mAllowMultipleSelection && !(mMaxSelectable > 0 && mItemList.size() > mMaxSelectable); } // virtual -void LLScrollListCtrl::deselect() +void LLScrollListCtrl::deselect() { - deselectAllItems(); + deselectAllItems(); } // virtual -BOOL LLScrollListCtrl::canDeselect() const +BOOL LLScrollListCtrl::canDeselect() const { - return getCanSelect(); + return getCanSelect(); } void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos) { - LLScrollListColumn::Params p; - LLParamSDParser parser; - parser.readSD(column, p); - addColumn(p, pos); + LLScrollListColumn::Params p; + LLParamSDParser parser; + parser.readSD(column, p); + addColumn(p, pos); } void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params, EAddPosition pos) { - if (!column_params.validateBlock()) return; - - std::string name = column_params.name; - // if no column name provided, just use ordinal as name - if (name.empty()) - { - name = llformat("%d", mColumnsIndexed.size()); - } - - if (mColumns.find(name) == mColumns.end()) - { - // Add column - mColumns[name] = new LLScrollListColumn(column_params, this); - LLScrollListColumn* new_column = mColumns[name]; - new_column->mIndex = mColumns.size()-1; - - // Add button - if (new_column->getWidth() > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth) - { - if (getNumColumns() > 0) - { - mTotalColumnPadding += mColumnPadding; - } - if (new_column->mRelWidth >= 0) - { - new_column->setWidth((S32)ll_round(new_column->mRelWidth*mItemListRect.getWidth())); - } - else if(new_column->mDynamicWidth) - { - mNumDynamicWidthColumns++; - new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns); - } - S32 top = mItemListRect.mTop; - - S32 left = mItemListRect.mLeft; - for (column_map_t::iterator itor = mColumns.begin(); - itor != mColumns.end(); - ++itor) - { - if (itor->second->mIndex < new_column->mIndex && - itor->second->getWidth() > 0) - { - left += itor->second->getWidth() + mColumnPadding; - } - } - - S32 right = left+new_column->getWidth(); - if (new_column->mIndex != (S32)mColumns.size()-1) - { - right += mColumnPadding; - } - - LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top); - - LLScrollColumnHeader::Params params(LLUICtrlFactory::getDefaultParams<LLScrollColumnHeader>()); - params.name = "btn_" + name; - params.rect = temp_rect; - params.column = new_column; - params.tool_tip = column_params.tool_tip; - params.tab_stop = false; - params.visible = mDisplayColumnHeaders; - - if(column_params.header.image.isProvided()) - { - params.image_selected = column_params.header.image; - params.image_unselected = column_params.header.image; - } - else - { - params.label = column_params.header.label; - } - - new_column->mHeader = LLUICtrlFactory::create<LLScrollColumnHeader>(params); - addChild(new_column->mHeader); - - sendChildToFront(mScrollbar); - } - } - - dirtyColumns(); + if (!column_params.validateBlock()) return; + + std::string name = column_params.name; + // if no column name provided, just use ordinal as name + if (name.empty()) + { + name = llformat("%d", mColumnsIndexed.size()); + } + + if (mColumns.find(name) == mColumns.end()) + { + // Add column + mColumns[name] = new LLScrollListColumn(column_params, this); + LLScrollListColumn* new_column = mColumns[name]; + new_column->mIndex = mColumns.size()-1; + + // Add button + if (new_column->getWidth() > 0 || new_column->mRelWidth > 0 || new_column->mDynamicWidth) + { + if (getNumColumns() > 0) + { + mTotalColumnPadding += mColumnPadding; + } + if (new_column->mRelWidth >= 0) + { + new_column->setWidth((S32)ll_round(new_column->mRelWidth*mItemListRect.getWidth())); + } + else if(new_column->mDynamicWidth) + { + mNumDynamicWidthColumns++; + new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns); + } + S32 top = mItemListRect.mTop; + + S32 left = mItemListRect.mLeft; + for (column_map_t::iterator itor = mColumns.begin(); + itor != mColumns.end(); + ++itor) + { + if (itor->second->mIndex < new_column->mIndex && + itor->second->getWidth() > 0) + { + left += itor->second->getWidth() + mColumnPadding; + } + } + + S32 right = left+new_column->getWidth(); + if (new_column->mIndex != (S32)mColumns.size()-1) + { + right += mColumnPadding; + } + + LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top); + + LLScrollColumnHeader::Params params(LLUICtrlFactory::getDefaultParams<LLScrollColumnHeader>()); + params.name = "btn_" + name; + params.rect = temp_rect; + params.column = new_column; + params.tool_tip = column_params.tool_tip; + params.tab_stop = false; + params.visible = mDisplayColumnHeaders; + + if(column_params.header.image.isProvided()) + { + params.image_selected = column_params.header.image; + params.image_unselected = column_params.header.image; + } + else + { + params.label = column_params.header.label; + } + + new_column->mHeader = LLUICtrlFactory::create<LLScrollColumnHeader>(params); + addChild(new_column->mHeader); + + sendChildToFront(mScrollbar); + } + } + + dirtyColumns(); } // static void LLScrollListCtrl::onClickColumn(void *userdata) { - LLScrollListColumn *info = (LLScrollListColumn*)userdata; - if (!info) return; + LLScrollListColumn *info = (LLScrollListColumn*)userdata; + if (!info) return; - LLScrollListCtrl *parent = info->mParentCtrl; - if (!parent) return; + LLScrollListCtrl *parent = info->mParentCtrl; + if (!parent) return; - if (!parent->mCanSort) return; + if (!parent->mCanSort) return; - S32 column_index = info->mIndex; + S32 column_index = info->mIndex; - LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex]; - bool ascending = column->mSortDirection == LLScrollListColumn::ASCENDING; - if (column->mSortingColumn != column->mName - && parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end()) - { - LLScrollListColumn* info_redir = parent->mColumns[column->mSortingColumn]; - column_index = info_redir->mIndex; - } + LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex]; + bool ascending = column->mSortDirection == LLScrollListColumn::ASCENDING; + if (column->mSortingColumn != column->mName + && parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end()) + { + LLScrollListColumn* info_redir = parent->mColumns[column->mSortingColumn]; + column_index = info_redir->mIndex; + } - // if this column is the primary sort key, reverse the direction - if (!parent->mSortColumns.empty() && parent->mSortColumns.back().first == column_index) - { - ascending = !parent->mSortColumns.back().second; - } + // if this column is the primary sort key, reverse the direction + if (!parent->mSortColumns.empty() && parent->mSortColumns.back().first == column_index) + { + ascending = !parent->mSortColumns.back().second; + } - parent->sortByColumnIndex(column_index, ascending); + parent->sortByColumnIndex(column_index, ascending); - if (parent->mOnSortChangedCallback) - { - parent->mOnSortChangedCallback(); - } + if (parent->mOnSortChangedCallback) + { + parent->mOnSortChangedCallback(); + } } std::string LLScrollListCtrl::getSortColumnName() { - LLScrollListColumn* column = mSortColumns.empty() ? NULL : mColumnsIndexed[mSortColumns.back().first]; + LLScrollListColumn* column = mSortColumns.empty() ? NULL : mColumnsIndexed[mSortColumns.back().first]; - if (column) return column->mName; - else return ""; + if (column) return column->mName; + else return ""; } BOOL LLScrollListCtrl::hasSortOrder() const { - return !mSortColumns.empty(); + return !mSortColumns.empty(); } void LLScrollListCtrl::clearSortOrder() { - mSortColumns.clear(); + mSortColumns.clear(); } void LLScrollListCtrl::clearColumns() { - column_map_t::iterator itor; - for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) - { - LLScrollColumnHeader *header = itor->second->mHeader; - if (header) - { - removeChild(header); - delete header; - } - } - std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer()); - mColumns.clear(); - mSortColumns.clear(); - mTotalStaticColumnWidth = 0; - mTotalColumnPadding = 0; + column_map_t::iterator itor; + for (itor = mColumns.begin(); itor != mColumns.end(); ++itor) + { + LLScrollColumnHeader *header = itor->second->mHeader; + if (header) + { + removeChild(header); + delete header; + } + } + std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer()); + mColumns.clear(); + mSortColumns.clear(); + mTotalStaticColumnWidth = 0; + mTotalColumnPadding = 0; dirtyColumns(); // Clears mColumnsIndexed } void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label) { - LLScrollListColumn* columnp = getColumn(column); - if (columnp) - { - columnp->mLabel = label; - if (columnp->mHeader) - { - columnp->mHeader->setLabel(label); - } - } + LLScrollListColumn* columnp = getColumn(column); + if (columnp) + { + columnp->mLabel = label; + if (columnp->mHeader) + { + columnp->mHeader->setLabel(label); + } + } } LLScrollListColumn* LLScrollListCtrl::getColumn(S32 index) { - if (index < 0 || index >= (S32)mColumnsIndexed.size()) - { - return NULL; - } - return mColumnsIndexed[index]; + if (index < 0 || index >= (S32)mColumnsIndexed.size()) + { + return NULL; + } + return mColumnsIndexed[index]; } LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name) { - column_map_t::iterator column_itor = mColumns.find(name); - if (column_itor != mColumns.end()) - { - return column_itor->second; - } - return NULL; + column_map_t::iterator column_itor = mColumns.find(name); + if (column_itor != mColumns.end()) + { + return column_itor->second; + } + return NULL; } LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - LLScrollListItem::Params item_params; - LLParamSDParser parser; - parser.readSD(element, item_params); - item_params.userdata = userdata; - return addRow(item_params, pos); + LLScrollListItem::Params item_params; + LLParamSDParser parser; + parser.readSD(element, item_params); + item_params.userdata = userdata; + return addRow(item_params, pos); } LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - LLScrollListItem *new_item = new LLScrollListItem(item_p); - return addRow(new_item, item_p, pos); + LLScrollListItem *new_item = new LLScrollListItem(item_p); + return addRow(new_item, item_p, pos); } LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if (!item_p.validateBlock() || !new_item) return NULL; - new_item->setNumColumns(mColumns.size()); - - // Add any columns we don't already have - S32 col_index = 0; - - for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns.begin(); - itor != item_p.columns.end(); - ++itor) - { - LLScrollListCell::Params cell_p = *itor; - std::string column = cell_p.column; - - // empty columns strings index by ordinal - if (column.empty()) - { - column = llformat("%d", col_index); - } - - LLScrollListColumn* columnp = getColumn(column); - - // create new column on demand - if (!columnp) - { - LLScrollListColumn::Params new_column; - new_column.name = column; - new_column.header.label = column; - - // if width supplied for column, use it, otherwise - // use adaptive width - if (cell_p.width.isProvided()) - { - new_column.width.pixel_width = cell_p.width; - } - addColumn(new_column); - columnp = mColumns[column]; - new_item->setNumColumns(mColumns.size()); - } - - S32 index = columnp->mIndex; - if (!cell_p.width.isProvided()) - { - cell_p.width = columnp->getWidth(); - } - - LLScrollListCell* cell = LLScrollListCell::create(cell_p); - - if (cell) - { - new_item->setColumn(index, cell); - if (columnp->mHeader - && cell->isText() - && !cell->getValue().asString().empty()) - { - columnp->mHeader->setHasResizableElement(TRUE); - } - } - - col_index++; - } - - if (item_p.columns.empty()) - { - if (mColumns.empty()) - { - LLScrollListColumn::Params new_column; - new_column.name = "0"; - - addColumn(new_column); - new_item->setNumColumns(mColumns.size()); - } - - LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value)); - if (cell) - { - LLScrollListColumn* columnp = mColumns.begin()->second; - - new_item->setColumn(0, cell); - if (columnp->mHeader - && cell->isText() - && !cell->getValue().asString().empty()) - { - columnp->mHeader->setHasResizableElement(TRUE); - } - } - } - - // add dummy cells for missing columns - for (column_map_t::iterator column_it = mColumns.begin(); column_it != mColumns.end(); ++column_it) - { - S32 column_idx = column_it->second->mIndex; - if (new_item->getColumn(column_idx) == NULL) - { - LLScrollListColumn* column_ptr = column_it->second; - LLScrollListCell::Params cell_p; - cell_p.width = column_ptr->getWidth(); - - new_item->setColumn(column_idx, new LLScrollListSpacer(cell_p)); - } - } - - addItem(new_item, pos); - return new_item; + if (!item_p.validateBlock() || !new_item) return NULL; + new_item->setNumColumns(mColumns.size()); + + // Add any columns we don't already have + S32 col_index = 0; + + for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns.begin(); + itor != item_p.columns.end(); + ++itor) + { + LLScrollListCell::Params cell_p = *itor; + std::string column = cell_p.column; + + // empty columns strings index by ordinal + if (column.empty()) + { + column = llformat("%d", col_index); + } + + LLScrollListColumn* columnp = getColumn(column); + + // create new column on demand + if (!columnp) + { + LLScrollListColumn::Params new_column; + new_column.name = column; + new_column.header.label = column; + + // if width supplied for column, use it, otherwise + // use adaptive width + if (cell_p.width.isProvided()) + { + new_column.width.pixel_width = cell_p.width; + } + addColumn(new_column); + columnp = mColumns[column]; + new_item->setNumColumns(mColumns.size()); + } + + S32 index = columnp->mIndex; + if (!cell_p.width.isProvided()) + { + cell_p.width = columnp->getWidth(); + } + + LLScrollListCell* cell = LLScrollListCell::create(cell_p); + + if (cell) + { + new_item->setColumn(index, cell); + if (columnp->mHeader + && cell->isText() + && !cell->getValue().asString().empty()) + { + columnp->mHeader->setHasResizableElement(TRUE); + } + } + + col_index++; + } + + if (item_p.columns.empty()) + { + if (mColumns.empty()) + { + LLScrollListColumn::Params new_column; + new_column.name = "0"; + + addColumn(new_column); + new_item->setNumColumns(mColumns.size()); + } + + LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value)); + if (cell) + { + LLScrollListColumn* columnp = mColumns.begin()->second; + + new_item->setColumn(0, cell); + if (columnp->mHeader + && cell->isText() + && !cell->getValue().asString().empty()) + { + columnp->mHeader->setHasResizableElement(TRUE); + } + } + } + + // add dummy cells for missing columns + for (column_map_t::iterator column_it = mColumns.begin(); column_it != mColumns.end(); ++column_it) + { + S32 column_idx = column_it->second->mIndex; + if (new_item->getColumn(column_idx) == NULL) + { + LLScrollListColumn* column_ptr = column_it->second; + LLScrollListCell::Params cell_p; + cell_p.width = column_ptr->getWidth(); + + new_item->setColumn(column_idx, new LLScrollListSpacer(cell_p)); + } + } + + addItem(new_item, pos); + return new_item; } LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) { - LLSD entry_id = id; + LLSD entry_id = id; - if (id.isUndefined()) - { - entry_id = value; - } + if (id.isUndefined()) + { + entry_id = value; + } + + LLScrollListItem::Params item_params; + item_params.value(entry_id); + item_params.columns.add() + .value(value) + .font(LLFontGL::getFontEmojiSmall()); - LLScrollListItem::Params item_params; - item_params.value(entry_id); - item_params.columns.add() - .value(value) - .font(LLFontGL::getFontSansSerifSmall()); - - return addRow(item_params, pos); + return addRow(item_params, pos); } void LLScrollListCtrl::setValue(const LLSD& value ) { - LLSD::array_const_iterator itor; - for (itor = value.beginArray(); itor != value.endArray(); ++itor) - { - addElement(*itor); - } + LLSD::array_const_iterator itor; + for (itor = value.beginArray(); itor != value.endArray(); ++itor) + { + addElement(*itor); + } } LLSD LLScrollListCtrl::getValue() const { - LLScrollListItem *item = getFirstSelected(); - if (!item) return LLSD(); - return item->getValue(); + LLScrollListItem *item = getFirstSelected(); + if (!item) return LLSD(); + return item->getValue(); } BOOL LLScrollListCtrl::operateOnSelection(EOperation op) { - if (op == OP_DELETE) - { - deleteSelectedItems(); - return TRUE; - } - else if (op == OP_DESELECT) - { - deselectAllItems(); - } - return FALSE; + if (op == OP_DELETE) + { + deleteSelectedItems(); + return TRUE; + } + else if (op == OP_DESELECT) + { + deselectAllItems(); + } + return FALSE; } BOOL LLScrollListCtrl::operateOnAll(EOperation op) { - if (op == OP_DELETE) - { - clearRows(); - return TRUE; - } - else if (op == OP_DESELECT) - { - deselectAllItems(); - } - else if (op == OP_SELECT) - { - selectAll(); - } - return FALSE; -} -//virtual + if (op == OP_DELETE) + { + clearRows(); + return TRUE; + } + else if (op == OP_DESELECT) + { + deselectAllItems(); + } + else if (op == OP_SELECT) + { + selectAll(); + } + return FALSE; +} +//virtual void LLScrollListCtrl::setFocus(BOOL b) { - // for tabbing into pristine scroll lists (Finder) - if (!getFirstSelected()) - { - selectFirstItem(); - //onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate - } - LLUICtrl::setFocus(b); + // for tabbing into pristine scroll lists (Finder) + if (!getFirstSelected()) + { + selectFirstItem(); + //onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate + } + LLUICtrl::setFocus(b); } -// virtual -BOOL LLScrollListCtrl::isDirty() const +// virtual +BOOL LLScrollListCtrl::isDirty() const { - BOOL grubby = mDirty; - if ( !mAllowMultipleSelection ) - { - grubby = (mOriginalSelection != getFirstSelectedIndex()); - } - return grubby; + BOOL grubby = mDirty; + if ( !mAllowMultipleSelection ) + { + grubby = (mOriginalSelection != getFirstSelectedIndex()); + } + return grubby; } // Clear dirty state void LLScrollListCtrl::resetDirty() { - mDirty = FALSE; - mOriginalSelection = getFirstSelectedIndex(); + mDirty = FALSE; + mOriginalSelection = getFirstSelectedIndex(); } //virtual void LLScrollListCtrl::onFocusReceived() { - // forget latent selection changes when getting focus - mSelectionChanged = false; - LLUICtrl::onFocusReceived(); + // forget latent selection changes when getting focus + mSelectionChanged = false; + LLUICtrl::onFocusReceived(); } -//virtual +//virtual void LLScrollListCtrl::onFocusLost() { - if (hasMouseCapture()) - { - gFocusMgr.setMouseCapture(NULL); - } + if (hasMouseCapture()) + { + gFocusMgr.setMouseCapture(NULL); + } - mSearchString.clear(); + mSearchString.clear(); - LLUICtrl::onFocusLost(); + LLUICtrl::onFocusLost(); } boost::signals2::connection LLScrollListCtrl::setIsFriendCallback(const is_friend_signal_t::slot_type& cb) { - if (!mIsFriendSignal) - { - mIsFriendSignal = new is_friend_signal_t(); - } - return mIsFriendSignal->connect(cb); + if (!mIsFriendSignal) + { + mIsFriendSignal = new is_friend_signal_t(); + } + return mIsFriendSignal->connect(cb); } bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str) @@ -3415,7 +3415,7 @@ bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str) clearHighlightedItems(); return false; } - + bool res = false; setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red)); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 326589a329..c525fd72a8 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -1,4 +1,4 @@ -/** +/** * @file llscrolllistctrl.h * @brief A scrolling list of items. This is the one you want to use * in UI code. LLScrollListCell, LLScrollListItem, etc. are utility @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,7 +36,7 @@ #include "llctrlselectioninterface.h" #include "llfontgl.h" #include "llui.h" -#include "llstring.h" // LLWString +#include "llstring.h" // LLWString #include "lleditmenuhandler.h" #include "llframetimer.h" @@ -50,8 +50,8 @@ class LLScrollListCell; class LLTextBox; class LLContextMenu; -class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, - public LLCtrlListInterface, public LLCtrlScrollInterface +class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, + public LLCtrlListInterface, public LLCtrlScrollInterface { public: typedef enum e_selection_type @@ -66,499 +66,499 @@ public: static void declareValues(); }; - struct Contents : public LLInitParam::Block<Contents> - { - Multiple<LLScrollListColumn::Params> columns; - Multiple<LLScrollListItem::Params> rows; - - //Multiple<Contents> groups; - - Contents(); - }; - - // *TODO: Add callbacks to Params - typedef boost::function<void (void)> callback_t; - - template<typename T> struct maximum - { - typedef T result_type; - - template<typename InputIterator> - T operator()(InputIterator first, InputIterator last) const - { - // If there are no slots to call, just return the - // default-constructed value - if(first == last ) return T(); - T max_value = *first++; - while (first != last) { - if (max_value < *first) - max_value = *first; - ++first; - } - - return max_value; - } - }; - - - typedef boost::signals2::signal<S32 (S32,const LLScrollListItem*,const LLScrollListItem*),maximum<S32> > sort_signal_t; - typedef boost::signals2::signal<bool(const LLUUID& user_id)> is_friend_signal_t; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - // behavioral flags - Optional<bool> multi_select, - commit_on_keyboard_movement, - commit_on_selection_change, - mouse_wheel_opaque; - - Optional<ESelectionType, SelectionTypeNames> selection_type; - - // display flags - Optional<bool> has_border, - draw_heading, - draw_stripes, - background_visible, - scroll_bar_bg_visible; - - // layout - Optional<S32> column_padding, - row_padding, - page_lines, - heading_height; - - // sort and search behavior - Optional<S32> search_column, - sort_column; - Optional<bool> sort_ascending, - can_sort; // whether user is allowed to sort - - // colors - Optional<LLUIColor> fg_unselected_color, - fg_selected_color, - bg_selected_color, - fg_disable_color, - bg_writeable_color, - bg_readonly_color, - bg_stripe_color, - hovered_color, - highlighted_color, - scroll_bar_bg_color; - - Optional<Contents> contents; - - Optional<LLViewBorder::Params> border; - - Params(); - }; + struct Contents : public LLInitParam::Block<Contents> + { + Multiple<LLScrollListColumn::Params> columns; + Multiple<LLScrollListItem::Params> rows; + + //Multiple<Contents> groups; + + Contents(); + }; + + // *TODO: Add callbacks to Params + typedef boost::function<void (void)> callback_t; + + template<typename T> struct maximum + { + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + // If there are no slots to call, just return the + // default-constructed value + if(first == last ) return T(); + T max_value = *first++; + while (first != last) { + if (max_value < *first) + max_value = *first; + ++first; + } + + return max_value; + } + }; + + + typedef boost::signals2::signal<S32 (S32,const LLScrollListItem*,const LLScrollListItem*),maximum<S32> > sort_signal_t; + typedef boost::signals2::signal<bool(const LLUUID& user_id)> is_friend_signal_t; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + // behavioral flags + Optional<bool> multi_select, + commit_on_keyboard_movement, + commit_on_selection_change, + mouse_wheel_opaque; + + Optional<ESelectionType, SelectionTypeNames> selection_type; + + // display flags + Optional<bool> has_border, + draw_heading, + draw_stripes, + background_visible, + scroll_bar_bg_visible; + + // layout + Optional<S32> column_padding, + row_padding, + page_lines, + heading_height; + + // sort and search behavior + Optional<S32> search_column, + sort_column; + Optional<bool> sort_ascending, + can_sort; // whether user is allowed to sort + + // colors + Optional<LLUIColor> fg_unselected_color, + fg_selected_color, + bg_selected_color, + fg_disable_color, + bg_writeable_color, + bg_readonly_color, + bg_stripe_color, + hovered_color, + highlighted_color, + scroll_bar_bg_color; + + Optional<Contents> contents; + + Optional<LLViewBorder::Params> border; + + Params(); + }; protected: - friend class LLUICtrlFactory; + friend class LLUICtrlFactory; - LLScrollListCtrl(const Params&); + LLScrollListCtrl(const Params&); public: - virtual ~LLScrollListCtrl(); - - S32 isEmpty() const; - - void deleteAllItems() { clearRows(); } - - // Sets an array of column descriptors - void setColumnHeadings(const LLSD& headings); - void sortByColumnIndex(U32 column, BOOL ascending); - - // LLCtrlListInterface functions - virtual S32 getItemCount() const; - // Adds a single column descriptor: ["name" : string, "label" : string, "width" : integer, "relwidth" : integer ] - virtual void addColumn(const LLScrollListColumn::Params& column, EAddPosition pos = ADD_BOTTOM); - virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM); - virtual void clearColumns(); - virtual void setColumnLabel(const std::string& column, const std::string& label); - virtual bool preProcessChildNode(LLXMLNodePtr child); - virtual LLScrollListColumn* getColumn(S32 index); - virtual LLScrollListColumn* getColumn(const std::string& name); - virtual S32 getNumColumns() const { return mColumnsIndexed.size(); } - - // Adds a single element, from an array of: - // "columns" => [ "column" => column name, "value" => value, "type" => type, "font" => font, "font-style" => style ], "id" => uuid - // Creates missing columns automatically. - virtual LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); - virtual LLScrollListItem* addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM); - virtual LLScrollListItem* addRow(const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM); - // Simple add element. Takes a single array of: - // [ "value" => value, "font" => font, "font-style" => style ] - virtual void clearRows(); // clears all elements - virtual void sortByColumn(const std::string& name, BOOL ascending); - - // These functions take and return an array of arrays of elements, as above - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - - LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; } - LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; } - LLCtrlScrollInterface* getScrollInterface() { return (LLCtrlScrollInterface*)this; } - - // DEPRECATED: Use setSelectedByValue() below. - BOOL setCurrentByID( const LLUUID& id ) { return selectByID(id); } - virtual LLUUID getCurrentID() const { return getStringUUIDSelectedItem(); } - - BOOL operateOnSelection(EOperation op); - BOOL operateOnAll(EOperation op); - - // returns FALSE if unable to set the max count so low - BOOL setMaxItemCount(S32 max_count); - - BOOL selectByID( const LLUUID& id ); // FALSE if item not found - - // Match item by value.asString(), which should work for string, integer, uuid. - // Returns FALSE if not found. - BOOL setSelectedByValue(const LLSD& value, BOOL selected); - - BOOL isSorted() const { return mSorted; } - - virtual BOOL isSelected(const LLSD& value) const; - - BOOL hasSelectedItem() const; - - BOOL handleClick(S32 x, S32 y, MASK mask); - BOOL selectFirstItem(); - BOOL selectNthItem( S32 index ); - BOOL selectItemRange( S32 first, S32 last ); - BOOL selectItemAt(S32 x, S32 y, MASK mask); - - void deleteSingleItem( S32 index ); - void deleteItems(const LLSD& sd); - void deleteSelectedItems(); - void deselectAllItems(BOOL no_commit_on_change = FALSE); // by default, go ahead and commit on selection change - - void clearHighlightedItems(); - - virtual void mouseOverHighlightNthItem( S32 index ); - - S32 getHighlightedItemInx() const { return mHighlightedItem; } - - void setDoubleClickCallback( callback_t cb ) { mOnDoubleClickCallback = cb; } - void setMaximumSelectCallback( callback_t cb) { mOnMaximumSelectCallback = cb; } - void setSortChangedCallback( callback_t cb) { mOnSortChangedCallback = cb; } - // Convenience function; *TODO: replace with setter above + boost::bind() in calling code - void setDoubleClickCallback( boost::function<void (void* userdata)> cb, void* userdata) { mOnDoubleClickCallback = boost::bind(cb, userdata); } - - void swapWithNext(S32 index); - void swapWithPrevious(S32 index); - - void setCanSelect(BOOL can_select) { mCanSelect = can_select; } - virtual BOOL getCanSelect() const { return mCanSelect; } - - S32 getItemIndex( LLScrollListItem* item ) const; - S32 getItemIndex( const LLUUID& item_id ) const; - - void setCommentText( const std::string& comment_text); - LLScrollListItem* addSeparator(EAddPosition pos); - - // "Simple" interface: use this when you're creating a list that contains only unique strings, only - // one of which can be selected at a time. - virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); - - BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found - BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1); - BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1); - LLScrollListItem* getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0); - const std::string getSelectedItemLabel(S32 column = 0) const; - LLSD getSelectedValue(); + virtual ~LLScrollListCtrl(); + + S32 isEmpty() const; + + void deleteAllItems() { clearRows(); } + + // Sets an array of column descriptors + void setColumnHeadings(const LLSD& headings); + void sortByColumnIndex(U32 column, BOOL ascending); + + // LLCtrlListInterface functions + virtual S32 getItemCount() const; + // Adds a single column descriptor: ["name" : string, "label" : string, "width" : integer, "relwidth" : integer ] + virtual void addColumn(const LLScrollListColumn::Params& column, EAddPosition pos = ADD_BOTTOM); + virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM); + virtual void clearColumns(); + virtual void setColumnLabel(const std::string& column, const std::string& label); + virtual bool preProcessChildNode(LLXMLNodePtr child); + virtual LLScrollListColumn* getColumn(S32 index); + virtual LLScrollListColumn* getColumn(const std::string& name); + virtual S32 getNumColumns() const { return mColumnsIndexed.size(); } + + // Adds a single element, from an array of: + // "columns" => [ "column" => column name, "value" => value, "type" => type, "font" => font, "font-style" => style ], "id" => uuid + // Creates missing columns automatically. + virtual LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); + virtual LLScrollListItem* addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM); + virtual LLScrollListItem* addRow(const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM); + // Simple add element. Takes a single array of: + // [ "value" => value, "font" => font, "font-style" => style ] + virtual void clearRows(); // clears all elements + virtual void sortByColumn(const std::string& name, BOOL ascending); + + // These functions take and return an array of arrays of elements, as above + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const; + + LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; } + LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; } + LLCtrlScrollInterface* getScrollInterface() { return (LLCtrlScrollInterface*)this; } + + // DEPRECATED: Use setSelectedByValue() below. + BOOL setCurrentByID( const LLUUID& id ) { return selectByID(id); } + virtual LLUUID getCurrentID() const { return getStringUUIDSelectedItem(); } + + BOOL operateOnSelection(EOperation op); + BOOL operateOnAll(EOperation op); + + // returns FALSE if unable to set the max count so low + BOOL setMaxItemCount(S32 max_count); + + BOOL selectByID( const LLUUID& id ); // FALSE if item not found + + // Match item by value.asString(), which should work for string, integer, uuid. + // Returns FALSE if not found. + BOOL setSelectedByValue(const LLSD& value, BOOL selected); + + BOOL isSorted() const { return mSorted; } + + virtual BOOL isSelected(const LLSD& value) const; + + BOOL hasSelectedItem() const; + + BOOL handleClick(S32 x, S32 y, MASK mask); + BOOL selectFirstItem(); + BOOL selectNthItem( S32 index ); + BOOL selectItemRange( S32 first, S32 last ); + BOOL selectItemAt(S32 x, S32 y, MASK mask); + + void deleteSingleItem( S32 index ); + void deleteItems(const LLSD& sd); + void deleteSelectedItems(); + void deselectAllItems(BOOL no_commit_on_change = FALSE); // by default, go ahead and commit on selection change + + void clearHighlightedItems(); + + virtual void mouseOverHighlightNthItem( S32 index ); + + S32 getHighlightedItemInx() const { return mHighlightedItem; } + + void setDoubleClickCallback( callback_t cb ) { mOnDoubleClickCallback = cb; } + void setMaximumSelectCallback( callback_t cb) { mOnMaximumSelectCallback = cb; } + void setSortChangedCallback( callback_t cb) { mOnSortChangedCallback = cb; } + // Convenience function; *TODO: replace with setter above + boost::bind() in calling code + void setDoubleClickCallback( boost::function<void (void* userdata)> cb, void* userdata) { mOnDoubleClickCallback = boost::bind(cb, userdata); } + + void swapWithNext(S32 index); + void swapWithPrevious(S32 index); + + void setCanSelect(BOOL can_select) { mCanSelect = can_select; } + virtual BOOL getCanSelect() const { return mCanSelect; } + + S32 getItemIndex( LLScrollListItem* item ) const; + S32 getItemIndex( const LLUUID& item_id ) const; + + void setCommentText( const std::string& comment_text); + LLScrollListItem* addSeparator(EAddPosition pos); + + // "Simple" interface: use this when you're creating a list that contains only unique strings, only + // one of which can be selected at a time. + virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); + + BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found + BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1); + BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1); + LLScrollListItem* getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0); + const std::string getSelectedItemLabel(S32 column = 0) const; + LLSD getSelectedValue(); // If multi select is on, select all element that include substring, // otherwise select first match only. // If focus is true will scroll to selection. // Returns number of results. // Note: at the moment search happens in one go and is expensive - U32 searchItems(const std::string& substring, bool case_sensitive = false, bool focus = true); - U32 searchItems(const LLWString& substring, bool case_sensitive = false, bool focus = true); - - // DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue(). - // "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which - // has an associated, unique UUID, and only one of which can be selected at a time. - LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - LLUUID getStringUUIDSelectedItem() const; - - LLScrollListItem* getFirstSelected() const; - virtual S32 getFirstSelectedIndex() const; - std::vector<LLScrollListItem*> getAllSelected() const; - S32 getNumSelected() const; - LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } - - // iterate over all items - LLScrollListItem* getFirstData() const; - LLScrollListItem* getLastData() const; - std::vector<LLScrollListItem*> getAllData() const; - - LLScrollListItem* getItem(const LLSD& sd) const; - - void setAllowMultipleSelection(BOOL mult ) { mAllowMultipleSelection = mult; } - - void setBgWriteableColor(const LLColor4 &c) { mBgWriteableColor = c; } - void setReadOnlyBgColor(const LLColor4 &c) { mBgReadOnlyColor = c; } - void setBgSelectedColor(const LLColor4 &c) { mBgSelectedColor = c; } - void setBgStripeColor(const LLColor4& c) { mBgStripeColor = c; } - void setFgSelectedColor(const LLColor4 &c) { mFgSelectedColor = c; } - void setFgUnselectedColor(const LLColor4 &c){ mFgUnselectedColor = c; } - void setHoveredColor(const LLColor4 &c) { mHoveredColor = c; } - void setHighlightedColor(const LLColor4 &c) { mHighlightedColor = c; } - void setFgDisableColor(const LLColor4 &c) { mFgDisabledColor = c; } - - void setBackgroundVisible(BOOL b) { mBackgroundVisible = b; } - void setDrawStripes(BOOL b) { mDrawStripes = b; } - void setColumnPadding(const S32 c) { mColumnPadding = c; } - S32 getColumnPadding() const { return mColumnPadding; } - void setRowPadding(const S32 c) { mColumnPadding = c; } - S32 getRowPadding() const { return mColumnPadding; } - void setCommitOnKeyboardMovement(BOOL b) { mCommitOnKeyboardMovement = b; } - void setCommitOnSelectionChange(BOOL b) { mCommitOnSelectionChange = b; } - void setAllowKeyboardMovement(BOOL b) { mAllowKeyboardMovement = b; } - - void setMaxSelectable(U32 max_selected) { mMaxSelectable = max_selected; } - S32 getMaxSelectable() { return mMaxSelectable; } - - - virtual S32 getScrollPos() const; - virtual void setScrollPos( S32 pos ); - S32 getSearchColumn(); - void setSearchColumn(S32 column) { mSearchColumn = column; } - S32 getColumnIndexFromOffset(S32 x); - S32 getColumnOffsetFromIndex(S32 index); - S32 getRowOffsetFromIndex(S32 index); - - void clearSearchString() { mSearchString.clear(); } - - // support right-click context menus for avatar/group lists - enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP }; - void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; } + U32 searchItems(const std::string& substring, bool case_sensitive = false, bool focus = true); + U32 searchItems(const LLWString& substring, bool case_sensitive = false, bool focus = true); + + // DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue(). + // "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which + // has an associated, unique UUID, and only one of which can be selected at a time. + LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); + LLUUID getStringUUIDSelectedItem() const; + + LLScrollListItem* getFirstSelected() const; + virtual S32 getFirstSelectedIndex() const; + std::vector<LLScrollListItem*> getAllSelected() const; + S32 getNumSelected() const; + LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } + + // iterate over all items + LLScrollListItem* getFirstData() const; + LLScrollListItem* getLastData() const; + std::vector<LLScrollListItem*> getAllData() const; + + LLScrollListItem* getItem(const LLSD& sd) const; + + void setAllowMultipleSelection(BOOL mult ) { mAllowMultipleSelection = mult; } + + void setBgWriteableColor(const LLColor4 &c) { mBgWriteableColor = c; } + void setReadOnlyBgColor(const LLColor4 &c) { mBgReadOnlyColor = c; } + void setBgSelectedColor(const LLColor4 &c) { mBgSelectedColor = c; } + void setBgStripeColor(const LLColor4& c) { mBgStripeColor = c; } + void setFgSelectedColor(const LLColor4 &c) { mFgSelectedColor = c; } + void setFgUnselectedColor(const LLColor4 &c){ mFgUnselectedColor = c; } + void setHoveredColor(const LLColor4 &c) { mHoveredColor = c; } + void setHighlightedColor(const LLColor4 &c) { mHighlightedColor = c; } + void setFgDisableColor(const LLColor4 &c) { mFgDisabledColor = c; } + + void setBackgroundVisible(BOOL b) { mBackgroundVisible = b; } + void setDrawStripes(BOOL b) { mDrawStripes = b; } + void setColumnPadding(const S32 c) { mColumnPadding = c; } + S32 getColumnPadding() const { return mColumnPadding; } + void setRowPadding(const S32 c) { mColumnPadding = c; } + S32 getRowPadding() const { return mColumnPadding; } + void setCommitOnKeyboardMovement(BOOL b) { mCommitOnKeyboardMovement = b; } + void setCommitOnSelectionChange(BOOL b) { mCommitOnSelectionChange = b; } + void setAllowKeyboardMovement(BOOL b) { mAllowKeyboardMovement = b; } + + void setMaxSelectable(U32 max_selected) { mMaxSelectable = max_selected; } + S32 getMaxSelectable() { return mMaxSelectable; } + + + virtual S32 getScrollPos() const; + virtual void setScrollPos( S32 pos ); + S32 getSearchColumn(); + void setSearchColumn(S32 column) { mSearchColumn = column; } + S32 getColumnIndexFromOffset(S32 x); + S32 getColumnOffsetFromIndex(S32 index); + S32 getRowOffsetFromIndex(S32 index); + + void clearSearchString() { mSearchString.clear(); } + + // support right-click context menus for avatar/group lists + enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP }; + void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; } ContextMenuType getContextMenuType() { return mContextMenuType; } - // Overridden from LLView - /*virtual*/ void draw(); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); - /*virtual*/ void setEnabled(BOOL enabled); - /*virtual*/ void setFocus( BOOL b ); - /*virtual*/ void onFocusReceived(); - /*virtual*/ void onFocusLost(); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - virtual BOOL isDirty() const; - virtual void resetDirty(); // Clear dirty state - - virtual void updateLayout(); - virtual void fitContents(S32 max_width, S32 max_height); - - virtual LLRect getRequiredRect(); - static BOOL rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row); - - LLRect getItemListRect() { return mItemListRect; } - - /// Returns rect, in local coords, of a given row/column - LLRect getCellRect(S32 row_index, S32 column_index); - - // Used "internally" by the scroll bar. - void onScrollChange( S32 new_pos, LLScrollbar* src ); - - static void onClickColumn(void *userdata); - - virtual void updateColumns(bool force_update = false); - S32 calcMaxContentWidth(); - bool updateColumnWidths(); - - void setHeadingHeight(S32 heading_height); - /** - * Sets max visible lines without scroolbar, if this value equals to 0, - * then display all items. - */ - void setPageLines(S32 page_lines ); - void setCollapseEmptyColumns(BOOL collapse); - - LLScrollListItem* hitItem(S32 x,S32 y); - virtual void scrollToShowSelected(); - - // LLEditMenuHandler functions - virtual void copy(); - virtual BOOL canCopy() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; - virtual void deselect(); - virtual BOOL canDeselect() const; - - void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } - void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); - S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } - - std::string getSortColumnName(); - BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } - BOOL hasSortOrder() const; - void clearSortOrder(); - - void setAlternateSort() { mAlternateSort = TRUE; } - - void selectPrevItem(BOOL extend_selection = FALSE); - void selectNextItem(BOOL extend_selection = FALSE); - S32 selectMultiple(uuid_vec_t ids); - // conceptually const, but mutates mItemList - void updateSort() const; - // sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example) - void sortOnce(S32 column, BOOL ascending); - - // manually call this whenever editing list items in place to flag need for resorting - void setNeedsSort(bool val = true) { mSorted = !val; } - void dirtyColumns(); // some operation has potentially affected column layout or ordering + // Overridden from LLView + /*virtual*/ void draw(); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ void setEnabled(BOOL enabled); + /*virtual*/ void setFocus( BOOL b ); + /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusLost(); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + virtual BOOL isDirty() const; + virtual void resetDirty(); // Clear dirty state + + virtual void updateLayout(); + virtual void fitContents(S32 max_width, S32 max_height); + + virtual LLRect getRequiredRect(); + static BOOL rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row); + + LLRect getItemListRect() { return mItemListRect; } + + /// Returns rect, in local coords, of a given row/column + LLRect getCellRect(S32 row_index, S32 column_index); + + // Used "internally" by the scroll bar. + void onScrollChange( S32 new_pos, LLScrollbar* src ); + + static void onClickColumn(void *userdata); + + virtual void updateColumns(bool force_update = false); + S32 calcMaxContentWidth(); + bool updateColumnWidths(); + + void setHeadingHeight(S32 heading_height); + /** + * Sets max visible lines without scroolbar, if this value equals to 0, + * then display all items. + */ + void setPageLines(S32 page_lines ); + void setCollapseEmptyColumns(BOOL collapse); + + LLScrollListItem* hitItem(S32 x,S32 y); + virtual void scrollToShowSelected(); + + // LLEditMenuHandler functions + virtual void copy(); + virtual BOOL canCopy() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; + virtual void deselect(); + virtual BOOL canDeselect() const; + + void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } + void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); + S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } + + std::string getSortColumnName(); + BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } + BOOL hasSortOrder() const; + void clearSortOrder(); + + void setAlternateSort() { mAlternateSort = TRUE; } + + void selectPrevItem(BOOL extend_selection = FALSE); + void selectNextItem(BOOL extend_selection = FALSE); + S32 selectMultiple(uuid_vec_t ids); + // conceptually const, but mutates mItemList + void updateSort() const; + // sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example) + void sortOnce(S32 column, BOOL ascending); + + // manually call this whenever editing list items in place to flag need for resorting + void setNeedsSort(bool val = true) { mSorted = !val; } + void dirtyColumns(); // some operation has potentially affected column layout or ordering bool highlightMatchingItems(const std::string& filter_str); - boost::signals2::connection setSortCallback(sort_signal_t::slot_type cb ) - { - if (!mSortCallback) mSortCallback = new sort_signal_t(); - return mSortCallback->connect(cb); - } + boost::signals2::connection setSortCallback(sort_signal_t::slot_type cb ) + { + if (!mSortCallback) mSortCallback = new sort_signal_t(); + return mSortCallback->connect(cb); + } - boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); + boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); protected: - // "Full" interface: use this when you're creating a list that has one or more of the following: - // * contains icons - // * contains multiple columns - // * allows multiple selection - // * has items that are not guarenteed to have unique names - // * has additional per-item data (e.g. a UUID or void* userdata) - // - // To add items using this approach, create new LLScrollListItems and LLScrollListCells. Add the - // cells (column entries) to each item, and add the item to the LLScrollListCtrl. - // - // The LLScrollListCtrl owns its items and is responsible for deleting them - // (except in the case that the addItem() call fails, in which case it is up - // to the caller to delete the item) - // - // returns FALSE if item faile to be added to list, does NOT delete 'item' - BOOL addItem( LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM, BOOL requires_column = TRUE ); - - typedef std::deque<LLScrollListItem *> item_list; - item_list& getItemList() { return mItemList; } - - void updateLineHeight(); + // "Full" interface: use this when you're creating a list that has one or more of the following: + // * contains icons + // * contains multiple columns + // * allows multiple selection + // * has items that are not guarenteed to have unique names + // * has additional per-item data (e.g. a UUID or void* userdata) + // + // To add items using this approach, create new LLScrollListItems and LLScrollListCells. Add the + // cells (column entries) to each item, and add the item to the LLScrollListCtrl. + // + // The LLScrollListCtrl owns its items and is responsible for deleting them + // (except in the case that the addItem() call fails, in which case it is up + // to the caller to delete the item) + // + // returns FALSE if item faile to be added to list, does NOT delete 'item' + BOOL addItem( LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM, BOOL requires_column = TRUE ); + + typedef std::deque<LLScrollListItem *> item_list; + item_list& getItemList() { return mItemList; } + + void updateLineHeight(); private: - void drawItems(); - - void updateLineHeightInsert(LLScrollListItem* item); - void reportInvalidInput(); - BOOL isRepeatedChars(const LLWString& string) const; - void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE); - void deselectItem(LLScrollListItem* itemp); - void commitIfChanged(); - BOOL setSort(S32 column, BOOL ascending); - S32 getLinesPerPage(); - - static void showProfile(std::string id, bool is_group); - static void sendIM(std::string id); - static void addFriend(std::string id); - static void removeFriend(std::string id); - static void reportAbuse(std::string id, bool is_group); - static void showNameDetails(std::string id, bool is_group); - static void copyNameToClipboard(std::string id, bool is_group); - static void copySLURLToClipboard(std::string id, bool is_group); - - S32 mLineHeight; // the max height of a single line - S32 mScrollLines; // how many lines we've scrolled down - S32 mPageLines; // max number of lines is it possible to see on the screen given mRect and mLineHeight - S32 mHeadingHeight; // the height of the column header buttons, if visible - U32 mMaxSelectable; - LLScrollbar* mScrollbar; - bool mAllowMultipleSelection; - bool mAllowKeyboardMovement; - bool mCommitOnKeyboardMovement; - bool mCommitOnSelectionChange; - bool mSelectionChanged; - ESelectionType mSelectionType; - bool mNeedsScroll; - bool mMouseWheelOpaque; - bool mCanSelect; - bool mCanSort; // Whether user is allowed to sort - bool mDisplayColumnHeaders; - bool mColumnsDirty; - bool mColumnWidthsDirty; - - bool mAlternateSort; - - mutable item_list mItemList; - - LLScrollListItem *mLastSelected; - - S32 mMaxItemCount; - - LLRect mItemListRect; - S32 mColumnPadding; - S32 mRowPadding; - - BOOL mBackgroundVisible; - BOOL mDrawStripes; - - LLUIColor mBgWriteableColor; - LLUIColor mBgReadOnlyColor; - LLUIColor mBgSelectedColor; - LLUIColor mBgStripeColor; - LLUIColor mFgSelectedColor; - LLUIColor mFgUnselectedColor; - LLUIColor mFgDisabledColor; - LLUIColor mHoveredColor; - LLUIColor mHighlightedColor; - - S32 mBorderThickness; - callback_t mOnDoubleClickCallback; - callback_t mOnMaximumSelectCallback; - callback_t mOnSortChangedCallback; - - S32 mHighlightedItem; - class LLViewBorder* mBorder; - LLHandle<LLContextMenu> mPopupMenuHandle; - - LLView *mCommentTextView; - - LLWString mSearchString; - LLFrameTimer mSearchTimer; - - S32 mSearchColumn; - S32 mNumDynamicWidthColumns; - S32 mTotalStaticColumnWidth; - S32 mTotalColumnPadding; - - mutable bool mSorted; - - typedef std::map<std::string, LLScrollListColumn*> column_map_t; - column_map_t mColumns; - - bool mDirty; - S32 mOriginalSelection; - - ContextMenuType mContextMenuType; - - typedef std::vector<LLScrollListColumn*> ordered_columns_t; - ordered_columns_t mColumnsIndexed; - - typedef std::pair<S32, BOOL> sort_column_t; - std::vector<sort_column_t> mSortColumns; - - sort_signal_t* mSortCallback; - - is_friend_signal_t* mIsFriendSignal; + void drawItems(); + + void updateLineHeightInsert(LLScrollListItem* item); + void reportInvalidInput(); + BOOL isRepeatedChars(const LLWString& string) const; + void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE); + void deselectItem(LLScrollListItem* itemp); + void commitIfChanged(); + BOOL setSort(S32 column, BOOL ascending); + S32 getLinesPerPage(); + + static void showProfile(std::string id, bool is_group); + static void sendIM(std::string id); + static void addFriend(std::string id); + static void removeFriend(std::string id); + static void reportAbuse(std::string id, bool is_group); + static void showNameDetails(std::string id, bool is_group); + static void copyNameToClipboard(std::string id, bool is_group); + static void copySLURLToClipboard(std::string id, bool is_group); + + S32 mLineHeight; // the max height of a single line + S32 mScrollLines; // how many lines we've scrolled down + S32 mPageLines; // max number of lines is it possible to see on the screen given mRect and mLineHeight + S32 mHeadingHeight; // the height of the column header buttons, if visible + U32 mMaxSelectable; + LLScrollbar* mScrollbar; + bool mAllowMultipleSelection; + bool mAllowKeyboardMovement; + bool mCommitOnKeyboardMovement; + bool mCommitOnSelectionChange; + bool mSelectionChanged; + ESelectionType mSelectionType; + bool mNeedsScroll; + bool mMouseWheelOpaque; + bool mCanSelect; + bool mCanSort; // Whether user is allowed to sort + bool mDisplayColumnHeaders; + bool mColumnsDirty; + bool mColumnWidthsDirty; + + bool mAlternateSort; + + mutable item_list mItemList; + + LLScrollListItem *mLastSelected; + + S32 mMaxItemCount; + + LLRect mItemListRect; + S32 mColumnPadding; + S32 mRowPadding; + + BOOL mBackgroundVisible; + BOOL mDrawStripes; + + LLUIColor mBgWriteableColor; + LLUIColor mBgReadOnlyColor; + LLUIColor mBgSelectedColor; + LLUIColor mBgStripeColor; + LLUIColor mFgSelectedColor; + LLUIColor mFgUnselectedColor; + LLUIColor mFgDisabledColor; + LLUIColor mHoveredColor; + LLUIColor mHighlightedColor; + + S32 mBorderThickness; + callback_t mOnDoubleClickCallback; + callback_t mOnMaximumSelectCallback; + callback_t mOnSortChangedCallback; + + S32 mHighlightedItem; + class LLViewBorder* mBorder; + LLHandle<LLContextMenu> mPopupMenuHandle; + + LLView *mCommentTextView; + + LLWString mSearchString; + LLFrameTimer mSearchTimer; + + S32 mSearchColumn; + S32 mNumDynamicWidthColumns; + S32 mTotalStaticColumnWidth; + S32 mTotalColumnPadding; + + mutable bool mSorted; + + typedef std::map<std::string, LLScrollListColumn*> column_map_t; + column_map_t mColumns; + + bool mDirty; + S32 mOriginalSelection; + + ContextMenuType mContextMenuType; + + typedef std::vector<LLScrollListColumn*> ordered_columns_t; + ordered_columns_t mColumnsIndexed; + + typedef std::pair<S32, BOOL> sort_column_t; + std::vector<sort_column_t> mSortColumns; + + sort_signal_t* mSortCallback; + + is_friend_signal_t* mIsFriendSignal; }; // end class LLScrollListCtrl #endif // LL_SCROLLLISTCTRL_H diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index e1360f80cd..a928a57465 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llscrolllistitem.cpp - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,22 +38,22 @@ //--------------------------------------------------------------------------- LLScrollListItem::LLScrollListItem( const Params& p ) -: mSelected(FALSE), - mHighlighted(FALSE), - mHoverIndex(-1), - mSelectedIndex(-1), - mEnabled(p.enabled), - mUserdata(p.userdata), - mItemValue(p.value), - mItemAltValue(p.alt_value) +: mSelected(FALSE), + mHighlighted(FALSE), + mHoverIndex(-1), + mSelectedIndex(-1), + mEnabled(p.enabled), + mUserdata(p.userdata), + mItemValue(p.value), + mItemAltValue(p.alt_value) { } LLScrollListItem::~LLScrollListItem() { - std::for_each(mColumns.begin(), mColumns.end(), DeletePointer()); - mColumns.clear(); + std::for_each(mColumns.begin(), mColumns.end(), DeletePointer()); + mColumns.clear(); } void LLScrollListItem::setSelected(BOOL b) @@ -80,76 +80,76 @@ void LLScrollListItem::setSelectedCell(S32 cell) void LLScrollListItem::addColumn(const LLScrollListCell::Params& p) { - mColumns.push_back(LLScrollListCell::create(p)); + mColumns.push_back(LLScrollListCell::create(p)); } void LLScrollListItem::setNumColumns(S32 columns) { - S32 prev_columns = mColumns.size(); - if (columns < prev_columns) - { - std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer()); - } - - mColumns.resize(columns); - - for (S32 col = prev_columns; col < columns; ++col) - { - mColumns[col] = NULL; - } + S32 prev_columns = mColumns.size(); + if (columns < prev_columns) + { + std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer()); + } + + mColumns.resize(columns); + + for (S32 col = prev_columns; col < columns; ++col) + { + mColumns[col] = NULL; + } } void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell ) { - if (column < (S32)mColumns.size()) - { - delete mColumns[column]; - mColumns[column] = cell; - } - else - { - LL_ERRS() << "LLScrollListItem::setColumn: bad column: " << column << LL_ENDL; - } + if (column < (S32)mColumns.size()) + { + delete mColumns[column]; + mColumns[column] = cell; + } + else + { + LL_ERRS() << "LLScrollListItem::setColumn: bad column: " << column << LL_ENDL; + } } S32 LLScrollListItem::getNumColumns() const { - return mColumns.size(); + return mColumns.size(); } LLScrollListCell* LLScrollListItem::getColumn(const S32 i) const { - if (0 <= i && i < (S32)mColumns.size()) - { - return mColumns[i]; - } - return NULL; + if (0 <= i && i < (S32)mColumns.size()) + { + return mColumns[i]; + } + return NULL; } std::string LLScrollListItem::getContentsCSV() const { - std::string ret; - - S32 count = getNumColumns(); - for (S32 i=0; i<count; ++i) - { - ret += getColumn(i)->getValue().asString(); - if (i < count-1) - { - ret += ", "; - } - } - - return ret; + std::string ret; + + S32 count = getNumColumns(); + for (S32 i=0; i<count; ++i) + { + ret += getColumn(i)->getValue().asString(); + if (i < count-1) + { + ret += ", "; + } + } + + return ret; } void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding) { - // draw background rect - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLRect bg_rect = rect; + // draw background rect + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLRect bg_rect = rect; if (mSelectedIndex < 0 && getSelected()) { // Whole item is highlighted/selected @@ -161,19 +161,19 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const gl_rect_2d(bg_rect, hover_color); } - S32 cur_x = rect.mLeft; - S32 num_cols = getNumColumns(); - S32 cur_col = 0; + S32 cur_x = rect.mLeft; + S32 num_cols = getNumColumns(); + S32 cur_col = 0; - for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col)) - { - // Two ways a cell could be hidden - if (cell->getWidth() < 0 - || !cell->getVisible()) continue; + for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col)) + { + // Two ways a cell could be hidden + if (cell->getWidth() < 0 + || !cell->getVisible()) continue; - LLUI::pushMatrix(); - { - LLUI::translate((F32) cur_x, (F32) rect.mBottom); + LLUI::pushMatrix(); + { + LLUI::translate((F32) cur_x, (F32) rect.mBottom); if (mSelectedIndex == cur_col) { @@ -194,11 +194,11 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const gl_rect_2d(highlight_rect, hover_color); } - cell->draw( fg_color, highlight_color ); - } - LLUI::popMatrix(); - - cur_x += cell->getWidth() + column_padding; - } + cell->draw( fg_color, highlight_color ); + } + LLUI::popMatrix(); + + cur_x += cell->getWidth() + column_padding; + } } diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index a3398305b1..8a78efbd7c 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -1,26 +1,26 @@ -/** +/** * @file llscrolllistitem.h - * @brief Scroll lists are composed of rows (items), each of which + * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #ifndef LLSCROLLLISTITEM_H #define LLSCROLLLISTITEM_H -#include "llpointer.h" // LLPointer<> +#include "llpointer.h" // LLPointer<> #include "llsd.h" #include "v4color.h" #include "llinitparam.h" @@ -48,95 +48,95 @@ class LLUIImage; //--------------------------------------------------------------------------- class LLScrollListItem { - friend class LLScrollListCtrl; + friend class LLScrollListCtrl; public: - struct Params : public LLInitParam::Block<Params> - { - Optional<bool> enabled; - Optional<void*> userdata; - Optional<LLSD> value; - Optional<LLSD> alt_value; - - Ignored name; // use for localization tools - Ignored type; - Ignored length; - - Multiple<LLScrollListCell::Params> columns; - - Params() - : enabled("enabled", true), - value("value"), - alt_value("alt_value"), - name("name"), - type("type"), - length("length"), - columns("columns") - { - addSynonym(columns, "column"); - addSynonym(value, "id"); - } - }; - - virtual ~LLScrollListItem(); - - void setSelected( BOOL b ); - BOOL getSelected() const { return mSelected; } - - void setEnabled( BOOL b ) { mEnabled = b; } - BOOL getEnabled() const { return mEnabled; } - - void setHighlighted( BOOL b ); - BOOL getHighlighted() const { return mHighlighted; } - - void setSelectedCell( S32 cell ); - S32 getSelectedCell() const { return mSelectedIndex; } - - void setHoverCell( S32 cell ); - S32 getHoverCell() const { return mHoverIndex; } - - void setUserdata( void* userdata ) { mUserdata = userdata; } - void* getUserdata() const { return mUserdata; } - - virtual LLUUID getUUID() const { return mItemValue.asUUID(); } - LLSD getValue() const { return mItemValue; } - LLSD getAltValue() const { return mItemAltValue; } - - void setRect(LLRect rect) { mRectangle = rect; } - LLRect getRect() const { return mRectangle; } - - void addColumn( const LLScrollListCell::Params& p ); - - void setNumColumns(S32 columns); - - void setColumn( S32 column, LLScrollListCell *cell ); - - S32 getNumColumns() const; - - LLScrollListCell *getColumn(const S32 i) const; - - std::string getContentsCSV() const; - - virtual void draw(const LLRect& rect, - const LLColor4& fg_color, - const LLColor4& hover_color, // highlight/hover selection of whole item or cell - const LLColor4& select_color, // highlight/hover selection of whole item or cell - const LLColor4& highlight_color, // highlights contents of cells (ex: text) - S32 column_padding); + struct Params : public LLInitParam::Block<Params> + { + Optional<bool> enabled; + Optional<void*> userdata; + Optional<LLSD> value; + Optional<LLSD> alt_value; + + Ignored name; // use for localization tools + Ignored type; + Ignored length; + + Multiple<LLScrollListCell::Params> columns; + + Params() + : enabled("enabled", true), + value("value"), + alt_value("alt_value"), + name("name"), + type("type"), + length("length"), + columns("columns") + { + addSynonym(columns, "column"); + addSynonym(value, "id"); + } + }; + + virtual ~LLScrollListItem(); + + void setSelected( BOOL b ); + BOOL getSelected() const { return mSelected; } + + void setEnabled( BOOL b ) { mEnabled = b; } + BOOL getEnabled() const { return mEnabled; } + + void setHighlighted( BOOL b ); + BOOL getHighlighted() const { return mHighlighted; } + + void setSelectedCell( S32 cell ); + S32 getSelectedCell() const { return mSelectedIndex; } + + void setHoverCell( S32 cell ); + S32 getHoverCell() const { return mHoverIndex; } + + void setUserdata( void* userdata ) { mUserdata = userdata; } + void* getUserdata() const { return mUserdata; } + + virtual LLUUID getUUID() const { return mItemValue.asUUID(); } + LLSD getValue() const { return mItemValue; } + LLSD getAltValue() const { return mItemAltValue; } + + void setRect(LLRect rect) { mRectangle = rect; } + LLRect getRect() const { return mRectangle; } + + void addColumn( const LLScrollListCell::Params& p ); + + void setNumColumns(S32 columns); + + void setColumn( S32 column, LLScrollListCell *cell ); + + S32 getNumColumns() const; + + LLScrollListCell *getColumn(const S32 i) const; + + std::string getContentsCSV() const; + + virtual void draw(const LLRect& rect, + const LLColor4& fg_color, + const LLColor4& hover_color, // highlight/hover selection of whole item or cell + const LLColor4& select_color, // highlight/hover selection of whole item or cell + const LLColor4& highlight_color, // highlights contents of cells (ex: text) + S32 column_padding); protected: - LLScrollListItem( const Params& ); + LLScrollListItem( const Params& ); private: - BOOL mSelected; - BOOL mHighlighted; - S32 mHoverIndex; - S32 mSelectedIndex; - BOOL mEnabled; - void* mUserdata; - LLSD mItemValue; - LLSD mItemAltValue; - std::vector<LLScrollListCell *> mColumns; - LLRect mRectangle; + BOOL mSelected; + BOOL mHighlighted; + S32 mHoverIndex; + S32 mSelectedIndex; + BOOL mEnabled; + void* mUserdata; + LLSD mItemValue; + LLSD mItemAltValue; + std::vector<LLScrollListCell *> mColumns; + LLRect mRectangle; }; #endif diff --git a/indra/llui/llsearchablecontrol.h b/indra/llui/llsearchablecontrol.h index f7f1ffa0a5..bccb4858e1 100644 --- a/indra/llui/llsearchablecontrol.h +++ b/indra/llui/llsearchablecontrol.h @@ -31,40 +31,40 @@ namespace ll { - namespace ui - { - class SearchableControl - { - mutable bool mIsHighlighed; - public: - SearchableControl() - : mIsHighlighed( false ) - { } - virtual ~SearchableControl() - { } + namespace ui + { + class SearchableControl + { + mutable bool mIsHighlighed; + public: + SearchableControl() + : mIsHighlighed( false ) + { } + virtual ~SearchableControl() + { } - LLColor4 getHighlightColor( ) const - { - static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red); - return highlight_color.get(); - } + LLColor4 getHighlightColor( ) const + { + static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red); + return highlight_color.get(); + } - void setHighlighted( bool aVal ) const - { - mIsHighlighed = aVal; - onSetHighlight( ); - } - bool getHighlighted( ) const - { return mIsHighlighed; } + void setHighlighted( bool aVal ) const + { + mIsHighlighed = aVal; + onSetHighlight( ); + } + bool getHighlighted( ) const + { return mIsHighlighed; } - std::string getSearchText() const - { return _getSearchText(); } - protected: - virtual std::string _getSearchText() const = 0; - virtual void onSetHighlight( ) const - { } - }; - } + std::string getSearchText() const + { return _getSearchText(); } + protected: + virtual std::string _getSearchText() const = 0; + virtual void onSetHighlight( ) const + { } + }; + } } diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index 8bf135f10c..9a35c628af 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsearcheditor.cpp * @brief LLSearchEditor implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,81 +27,81 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #include "llsearcheditor.h" #include "llkeyboard.h" LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) -: LLUICtrl(p), - mSearchButton(NULL), - mClearButton(NULL), - mEditorImage(p.background_image), - mEditorImageFocused(p.background_image_focused), - mEditorSearchImage(p.background_image_highlight), - mHighlightTextField(p.highlight_text_field) +: LLUICtrl(p), + mSearchButton(NULL), + mClearButton(NULL), + mEditorImage(p.background_image), + mEditorImageFocused(p.background_image_focused), + mEditorSearchImage(p.background_image_highlight), + mHighlightTextField(p.highlight_text_field) { - S32 srch_btn_top = p.search_button.top_pad + p.search_button.rect.height; - S32 srch_btn_right = p.search_button.rect.width + p.search_button.left_pad; - LLRect srch_btn_rect(p.search_button.left_pad, srch_btn_top, srch_btn_right, p.search_button.top_pad); - - S32 clr_btn_top = p.clear_button.rect.bottom + p.clear_button.rect.height; - S32 clr_btn_right = getRect().getWidth() - p.clear_button.pad_right; - S32 clr_btn_left = clr_btn_right - p.clear_button.rect.width; - LLRect clear_btn_rect(clr_btn_left, clr_btn_top, clr_btn_right, p.clear_button.rect.bottom); - - S32 text_pad_left = p.text_pad_left; - S32 text_pad_right = p.text_pad_right; - - if (p.search_button_visible) - text_pad_left += srch_btn_rect.getWidth(); - - if (p.clear_button_visible) - text_pad_right = getRect().getWidth() - clr_btn_left + p.clear_button.pad_left; - - // Set up line editor. - LLLineEditor::Params line_editor_params(p); - line_editor_params.name("filter edit box"); - line_editor_params.background_image(p.background_image); - line_editor_params.background_image_focused(p.background_image_focused); - line_editor_params.rect(getLocalRect()); - line_editor_params.follows.flags(FOLLOWS_ALL); - line_editor_params.text_pad_left(text_pad_left); - line_editor_params.text_pad_right(text_pad_right); - line_editor_params.revert_on_esc(false); - line_editor_params.commit_callback.function(boost::bind(&LLUICtrl::onCommit, this)); - line_editor_params.keystroke_callback(boost::bind(&LLSearchEditor::handleKeystroke, this)); - - mSearchEditor = LLUICtrlFactory::create<LLLineEditor>(line_editor_params); - mSearchEditor->setPassDelete(TRUE); - addChild(mSearchEditor); - - if (p.search_button_visible) - { - // Set up search button. - LLButton::Params srch_btn_params(p.search_button); - srch_btn_params.name(std::string("search button")); - srch_btn_params.rect(srch_btn_rect) ; - srch_btn_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); - srch_btn_params.tab_stop(false); - srch_btn_params.click_callback.function(boost::bind(&LLUICtrl::onCommit, this)); - - mSearchButton = LLUICtrlFactory::create<LLButton>(srch_btn_params); - mSearchEditor->addChild(mSearchButton); - } - - if (p.clear_button_visible) - { - // Set up clear button. - LLButton::Params clr_btn_params(p.clear_button); - clr_btn_params.name(std::string("clear button")); - clr_btn_params.rect(clear_btn_rect) ; - clr_btn_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); - clr_btn_params.tab_stop(false); - clr_btn_params.click_callback.function(boost::bind(&LLSearchEditor::onClearButtonClick, this, _2)); - - mClearButton = LLUICtrlFactory::create<LLButton>(clr_btn_params); - mSearchEditor->addChild(mClearButton); - } + S32 srch_btn_top = p.search_button.top_pad + p.search_button.rect.height; + S32 srch_btn_right = p.search_button.rect.width + p.search_button.left_pad; + LLRect srch_btn_rect(p.search_button.left_pad, srch_btn_top, srch_btn_right, p.search_button.top_pad); + + S32 clr_btn_top = p.clear_button.rect.bottom + p.clear_button.rect.height; + S32 clr_btn_right = getRect().getWidth() - p.clear_button.pad_right; + S32 clr_btn_left = clr_btn_right - p.clear_button.rect.width; + LLRect clear_btn_rect(clr_btn_left, clr_btn_top, clr_btn_right, p.clear_button.rect.bottom); + + S32 text_pad_left = p.text_pad_left; + S32 text_pad_right = p.text_pad_right; + + if (p.search_button_visible) + text_pad_left += srch_btn_rect.getWidth(); + + if (p.clear_button_visible) + text_pad_right = getRect().getWidth() - clr_btn_left + p.clear_button.pad_left; + + // Set up line editor. + LLLineEditor::Params line_editor_params(p); + line_editor_params.name("filter edit box"); + line_editor_params.background_image(p.background_image); + line_editor_params.background_image_focused(p.background_image_focused); + line_editor_params.rect(getLocalRect()); + line_editor_params.follows.flags(FOLLOWS_ALL); + line_editor_params.text_pad_left(text_pad_left); + line_editor_params.text_pad_right(text_pad_right); + line_editor_params.revert_on_esc(false); + line_editor_params.commit_callback.function(boost::bind(&LLUICtrl::onCommit, this)); + line_editor_params.keystroke_callback(boost::bind(&LLSearchEditor::handleKeystroke, this)); + + mSearchEditor = LLUICtrlFactory::create<LLLineEditor>(line_editor_params); + mSearchEditor->setPassDelete(TRUE); + addChild(mSearchEditor); + + if (p.search_button_visible) + { + // Set up search button. + LLButton::Params srch_btn_params(p.search_button); + srch_btn_params.name(std::string("search button")); + srch_btn_params.rect(srch_btn_rect) ; + srch_btn_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); + srch_btn_params.tab_stop(false); + srch_btn_params.click_callback.function(boost::bind(&LLUICtrl::onCommit, this)); + + mSearchButton = LLUICtrlFactory::create<LLButton>(srch_btn_params); + mSearchEditor->addChild(mSearchButton); + } + + if (p.clear_button_visible) + { + // Set up clear button. + LLButton::Params clr_btn_params(p.clear_button); + clr_btn_params.name(std::string("clear button")); + clr_btn_params.rect(clear_btn_rect) ; + clr_btn_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); + clr_btn_params.tab_stop(false); + clr_btn_params.click_callback.function(boost::bind(&LLSearchEditor::onClearButtonClick, this, _2)); + + mClearButton = LLUICtrlFactory::create<LLButton>(clr_btn_params); + mSearchEditor->addChild(mClearButton); + } } LLSearchEditor::~LLSearchEditor() @@ -115,100 +115,100 @@ LLSearchEditor::~LLSearchEditor() //virtual void LLSearchEditor::draw() { - if (mClearButton) - mClearButton->setVisible(!mSearchEditor->getWText().empty()); - - if (mHighlightTextField) - { - if (!mSearchEditor->getWText().empty()) - { - mSearchEditor->setBgImage(mEditorSearchImage); - mSearchEditor->setBgImageFocused(mEditorSearchImage); - } - else - { - mSearchEditor->setBgImage(mEditorImage); - mSearchEditor->setBgImageFocused(mEditorImageFocused); - } - } - - LLUICtrl::draw(); + if (mClearButton) + mClearButton->setVisible(!mSearchEditor->getWText().empty()); + + if (mHighlightTextField) + { + if (!mSearchEditor->getWText().empty()) + { + mSearchEditor->setBgImage(mEditorSearchImage); + mSearchEditor->setBgImageFocused(mEditorSearchImage); + } + else + { + mSearchEditor->setBgImage(mEditorImage); + mSearchEditor->setBgImageFocused(mEditorImageFocused); + } + } + + LLUICtrl::draw(); } //virtual void LLSearchEditor::setValue(const LLSD& value ) { - mSearchEditor->setValue(value); + mSearchEditor->setValue(value); } //virtual LLSD LLSearchEditor::getValue() const { - return mSearchEditor->getValue(); + return mSearchEditor->getValue(); } //virtual BOOL LLSearchEditor::setTextArg( const std::string& key, const LLStringExplicit& text ) { - return mSearchEditor->setTextArg(key, text); + return mSearchEditor->setTextArg(key, text); } //virtual BOOL LLSearchEditor::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - return mSearchEditor->setLabelArg(key, text); + return mSearchEditor->setLabelArg(key, text); } //virtual void LLSearchEditor::setLabel( const LLStringExplicit &new_label ) { - mSearchEditor->setLabel(new_label); + mSearchEditor->setLabel(new_label); } //virtual void LLSearchEditor::clear() { - if (mSearchEditor) - { - mSearchEditor->clear(); - } + if (mSearchEditor) + { + mSearchEditor->clear(); + } } //virtual void LLSearchEditor::setFocus( BOOL b ) { - if (mSearchEditor) - { - mSearchEditor->setFocus(b); - } + if (mSearchEditor) + { + mSearchEditor->setFocus(b); + } } void LLSearchEditor::onClearButtonClick(const LLSD& data) { - setText(LLStringUtil::null); - if (mTextChangedCallback) - { - mTextChangedCallback(this, getValue()); - } - mSearchEditor->onCommit(); // force keystroke callback + setText(LLStringUtil::null); + if (mTextChangedCallback) + { + mTextChangedCallback(this, getValue()); + } + mSearchEditor->onCommit(); // force keystroke callback } void LLSearchEditor::handleKeystroke() { - if (mKeystrokeCallback) - { - mKeystrokeCallback(this, getValue()); - } - - KEY key = gKeyboard->currentKey(); - if (key == KEY_LEFT || - key == KEY_RIGHT) - { - return; - } - - if (mTextChangedCallback) - { - mTextChangedCallback(this, getValue()); - } + if (mKeystrokeCallback) + { + mKeystrokeCallback(this, getValue()); + } + + KEY key = gKeyboard->currentKey(); + if (key == KEY_LEFT || + key == KEY_RIGHT) + { + return; + } + + if (mTextChangedCallback) + { + mTextChangedCallback(this, getValue()); + } } diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index bd51988d07..26f6b72aa3 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -1,34 +1,34 @@ -/** +/** * @file llsearcheditor.h * @brief Text editor widget that represents a search operation * - * Features: - * Text entry of a single line (text, delete, left and right arrow, insert, return). - * Callbacks either on every keystroke or just on the return key. - * Focus (allow multiple text entry widgets) - * Clipboard (cut, copy, and paste) - * Horizontal scrolling to allow strings longer than widget size allows - * Pre-validation (limit which keys can be used) - * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * Features: + * Text entry of a single line (text, delete, left and right arrow, insert, return). + * Callbacks either on every keystroke or just on the return key. + * Focus (allow multiple text entry widgets) + * Clipboard (cut, copy, and paste) + * Horizontal scrolling to allow strings longer than widget size allows + * Pre-validation (limit which keys can be used) + * Optional line history so previous entries can be recalled by CTRL UP/DOWN * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,73 +42,73 @@ class LLSearchEditor : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> - { - Optional<LLButton::Params> search_button, - clear_button; - Optional<bool> search_button_visible, - clear_button_visible, - highlight_text_field; - Optional<commit_callback_t> keystroke_callback; - - Optional<LLUIImage*> background_image, - background_image_focused, - background_image_highlight; - - Params() - : search_button("search_button"), - search_button_visible("search_button_visible"), - clear_button("clear_button"), - clear_button_visible("clear_button_visible"), - highlight_text_field("highlight_text_field"), - background_image("background_image"), - background_image_focused("background_image_focused"), - background_image_highlight("background_image_highlight") - {} - }; - - void setCommitOnFocusLost(BOOL b) { if (mSearchEditor) mSearchEditor->setCommitOnFocusLost(b); } + struct Params : public LLInitParam::Block<Params, LLLineEditor::Params> + { + Optional<LLButton::Params> search_button, + clear_button; + Optional<bool> search_button_visible, + clear_button_visible, + highlight_text_field; + Optional<commit_callback_t> keystroke_callback; + + Optional<LLUIImage*> background_image, + background_image_focused, + background_image_highlight; + + Params() + : search_button("search_button"), + search_button_visible("search_button_visible"), + clear_button("clear_button"), + clear_button_visible("clear_button_visible"), + highlight_text_field("highlight_text_field"), + background_image("background_image"), + background_image_focused("background_image_focused"), + background_image_highlight("background_image_highlight") + {} + }; + + void setCommitOnFocusLost(BOOL b) { if (mSearchEditor) mSearchEditor->setCommitOnFocusLost(b); } protected: - LLSearchEditor(const Params&); - friend class LLUICtrlFactory; + LLSearchEditor(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLSearchEditor(); + virtual ~LLSearchEditor(); - /*virtual*/ void draw(); + /*virtual*/ void draw(); - void setText(const LLStringExplicit &new_text) { mSearchEditor->setText(new_text); } - const std::string& getText() const { return mSearchEditor->getText(); } + void setText(const LLStringExplicit &new_text) { mSearchEditor->setText(new_text); } + const std::string& getText() const { return mSearchEditor->getText(); } - // LLUICtrl interface - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - virtual void setLabel( const LLStringExplicit &new_label ); - virtual void clear(); - virtual void setFocus( BOOL b ); + // LLUICtrl interface + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const; + virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual void setLabel( const LLStringExplicit &new_label ); + virtual void clear(); + virtual void setFocus( BOOL b ); - void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } - void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } + void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } + void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; } protected: - void onClearButtonClick(const LLSD& data); - virtual void handleKeystroke(); + void onClearButtonClick(const LLSD& data); + virtual void handleKeystroke(); - commit_callback_t mKeystrokeCallback; - commit_callback_t mTextChangedCallback; - LLLineEditor* mSearchEditor; - LLButton* mSearchButton; - LLButton* mClearButton; + commit_callback_t mKeystrokeCallback; + commit_callback_t mTextChangedCallback; + LLLineEditor* mSearchEditor; + LLButton* mSearchButton; + LLButton* mClearButton; - LLPointer<LLUIImage> mEditorImage; - LLPointer<LLUIImage> mEditorImageFocused; - LLPointer<LLUIImage> mEditorSearchImage; - LLPointer<LLUIImage> mEditorSearchImageFocused; + LLPointer<LLUIImage> mEditorImage; + LLPointer<LLUIImage> mEditorImageFocused; + LLPointer<LLUIImage> mEditorSearchImage; + LLPointer<LLUIImage> mEditorSearchImageFocused; - bool mHighlightTextField; + bool mHighlightTextField; }; #endif // LL_SEARCHEDITOR_H diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index 62df5a2c38..ed8d508ba3 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llslider.cpp * @brief LLSlider base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "llgl.h" #include "llwindow.h" #include "llfocusmgr.h" -#include "llkeyboard.h" // for the MASK constants +#include "llkeyboard.h" // for the MASK constants #include "llcontrol.h" #include "lluictrlfactory.h" @@ -41,343 +41,343 @@ static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar"); // have ambigious template lookup problem LLSlider::Params::Params() -: orientation ("orientation", std::string ("horizontal")), - thumb_outline_color("thumb_outline_color"), - thumb_center_color("thumb_center_color"), - thumb_image("thumb_image"), - thumb_image_pressed("thumb_image_pressed"), - thumb_image_disabled("thumb_image_disabled"), - track_image_horizontal("track_image_horizontal"), - track_image_vertical("track_image_vertical"), - track_highlight_horizontal_image("track_highlight_horizontal_image"), - track_highlight_vertical_image("track_highlight_vertical_image"), - mouse_down_callback("mouse_down_callback"), - mouse_up_callback("mouse_up_callback") +: orientation ("orientation", std::string ("horizontal")), + thumb_outline_color("thumb_outline_color"), + thumb_center_color("thumb_center_color"), + thumb_image("thumb_image"), + thumb_image_pressed("thumb_image_pressed"), + thumb_image_disabled("thumb_image_disabled"), + track_image_horizontal("track_image_horizontal"), + track_image_vertical("track_image_vertical"), + track_highlight_horizontal_image("track_highlight_horizontal_image"), + track_highlight_vertical_image("track_highlight_vertical_image"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback") {} LLSlider::LLSlider(const LLSlider::Params& p) -: LLF32UICtrl(p), - mMouseOffset( 0 ), - mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL), - mThumbOutlineColor(p.thumb_outline_color()), - mThumbCenterColor(p.thumb_center_color()), - mThumbImage(p.thumb_image), - mThumbImagePressed(p.thumb_image_pressed), - mThumbImageDisabled(p.thumb_image_disabled), - mTrackImageHorizontal(p.track_image_horizontal), - mTrackImageVertical(p.track_image_vertical), - mTrackHighlightHorizontalImage(p.track_highlight_horizontal_image), - mTrackHighlightVerticalImage(p.track_highlight_vertical_image), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL) +: LLF32UICtrl(p), + mMouseOffset( 0 ), + mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL), + mThumbOutlineColor(p.thumb_outline_color()), + mThumbCenterColor(p.thumb_center_color()), + mThumbImage(p.thumb_image), + mThumbImagePressed(p.thumb_image_pressed), + mThumbImageDisabled(p.thumb_image_disabled), + mTrackImageHorizontal(p.track_image_horizontal), + mTrackImageVertical(p.track_image_vertical), + mTrackHighlightHorizontalImage(p.track_highlight_horizontal_image), + mTrackHighlightVerticalImage(p.track_highlight_vertical_image), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL) { mViewModel->setValue(p.initial_value); - updateThumbRect(); - mDragStartThumbRect = mThumbRect; - setControlName(p.control_name, NULL); - setValue(getValueF32()); - - if (p.mouse_down_callback.isProvided()) - { - setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); - } - if (p.mouse_up_callback.isProvided()) - { - setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); - } + updateThumbRect(); + mDragStartThumbRect = mThumbRect; + setControlName(p.control_name, NULL); + setValue(getValueF32()); + + if (p.mouse_down_callback.isProvided()) + { + setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); + } + if (p.mouse_up_callback.isProvided()) + { + setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); + } } LLSlider::~LLSlider() { - delete mMouseDownSignal; - delete mMouseUpSignal; + delete mMouseDownSignal; + delete mMouseUpSignal; } void LLSlider::setValue(F32 value, BOOL from_event) { - value = llclamp( value, mMinValue, mMaxValue ); + value = llclamp( value, mMinValue, mMaxValue ); - // Round to nearest increment (bias towards rounding down) - value -= mMinValue; - value += mIncrement/2.0001f; - value -= fmod(value, mIncrement); - value += mMinValue; + // Round to nearest increment (bias towards rounding down) + value -= mMinValue; + value += mIncrement/2.0001f; + value -= fmod(value, mIncrement); + value += mMinValue; - if (!from_event && getValueF32() != value) - { - setControlValue(value); - } + if (!from_event && getValueF32() != value) + { + setControlValue(value); + } LLF32UICtrl::setValue(value); - updateThumbRect(); + updateThumbRect(); } void LLSlider::updateThumbRect() { - const S32 DEFAULT_THUMB_SIZE = 16; - F32 t = (getValueF32() - mMinValue) / (mMaxValue - mMinValue); - - S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE; - S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE; - - if ( mOrientation == HORIZONTAL ) - { - S32 left_edge = (thumb_width / 2); - S32 right_edge = getRect().getWidth() - (thumb_width / 2); - - S32 x = left_edge + S32( t * (right_edge - left_edge) ); - mThumbRect.mLeft = x - (thumb_width / 2); - mThumbRect.mRight = mThumbRect.mLeft + thumb_width; - mThumbRect.mBottom = getLocalRect().getCenterY() - (thumb_height / 2); - mThumbRect.mTop = mThumbRect.mBottom + thumb_height; - } - else - { - S32 top_edge = (thumb_height / 2); - S32 bottom_edge = getRect().getHeight() - (thumb_height / 2); - - S32 y = top_edge + S32( t * (bottom_edge - top_edge) ); - mThumbRect.mLeft = getLocalRect().getCenterX() - (thumb_width / 2); - mThumbRect.mRight = mThumbRect.mLeft + thumb_width; - mThumbRect.mBottom = y - (thumb_height / 2); - mThumbRect.mTop = mThumbRect.mBottom + thumb_height; - } + const S32 DEFAULT_THUMB_SIZE = 16; + F32 t = (getValueF32() - mMinValue) / (mMaxValue - mMinValue); + + S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE; + S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE; + + if ( mOrientation == HORIZONTAL ) + { + S32 left_edge = (thumb_width / 2); + S32 right_edge = getRect().getWidth() - (thumb_width / 2); + + S32 x = left_edge + S32( t * (right_edge - left_edge) ); + mThumbRect.mLeft = x - (thumb_width / 2); + mThumbRect.mRight = mThumbRect.mLeft + thumb_width; + mThumbRect.mBottom = getLocalRect().getCenterY() - (thumb_height / 2); + mThumbRect.mTop = mThumbRect.mBottom + thumb_height; + } + else + { + S32 top_edge = (thumb_height / 2); + S32 bottom_edge = getRect().getHeight() - (thumb_height / 2); + + S32 y = top_edge + S32( t * (bottom_edge - top_edge) ); + mThumbRect.mLeft = getLocalRect().getCenterX() - (thumb_width / 2); + mThumbRect.mRight = mThumbRect.mLeft + thumb_width; + mThumbRect.mBottom = y - (thumb_height / 2); + mThumbRect.mTop = mThumbRect.mBottom + thumb_height; + } } void LLSlider::setValueAndCommit(F32 value) { - F32 old_value = getValueF32(); - setValue(value); + F32 old_value = getValueF32(); + setValue(value); - if (getValueF32() != old_value) - { - onCommit(); - } + if (getValueF32() != old_value) + { + onCommit(); + } } BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask) { - if( hasMouseCapture() ) - { - if ( mOrientation == HORIZONTAL ) - { - S32 thumb_half_width = mThumbImage->getWidth()/2; - S32 left_edge = thumb_half_width; - S32 right_edge = getRect().getWidth() - (thumb_half_width); - - x += mMouseOffset; - x = llclamp( x, left_edge, right_edge ); - - F32 t = F32(x - left_edge) / (right_edge - left_edge); - setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); - } - else // mOrientation == VERTICAL - { - S32 thumb_half_height = mThumbImage->getHeight()/2; - S32 top_edge = thumb_half_height; - S32 bottom_edge = getRect().getHeight() - (thumb_half_height); - - y += mMouseOffset; - y = llclamp(y, top_edge, bottom_edge); - - F32 t = F32(y - top_edge) / (bottom_edge - top_edge); - setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); - } - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; - } - return TRUE; + if( hasMouseCapture() ) + { + if ( mOrientation == HORIZONTAL ) + { + S32 thumb_half_width = mThumbImage->getWidth()/2; + S32 left_edge = thumb_half_width; + S32 right_edge = getRect().getWidth() - (thumb_half_width); + + x += mMouseOffset; + x = llclamp( x, left_edge, right_edge ); + + F32 t = F32(x - left_edge) / (right_edge - left_edge); + setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); + } + else // mOrientation == VERTICAL + { + S32 thumb_half_height = mThumbImage->getHeight()/2; + S32 top_edge = thumb_half_height; + S32 bottom_edge = getRect().getHeight() - (thumb_half_height); + + y += mMouseOffset; + y = llclamp(y, top_edge, bottom_edge); + + F32 t = F32(y - top_edge) / (bottom_edge - top_edge); + setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); + } + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + } + else + { + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + } + return TRUE; } BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); - if (mMouseUpSignal) - (*mMouseUpSignal)( this, getValueF32() ); + if (mMouseUpSignal) + (*mMouseUpSignal)( this, getValueF32() ); - handled = TRUE; - make_ui_sound("UISndClickRelease"); - } - else - { - handled = TRUE; - } + handled = TRUE; + make_ui_sound("UISndClickRelease"); + } + else + { + handled = TRUE; + } - return handled; + return handled; } BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask) { - // only do sticky-focus on non-chrome widgets - if (!getIsChrome()) - { - setFocus(TRUE); - } - if (mMouseDownSignal) - (*mMouseDownSignal)( this, getValueF32() ); - - if (MASK_CONTROL & mask) // if CTRL is modifying - { - setValueAndCommit(mInitialValue); - } - else - { - // Find the offset of the actual mouse location from the center of the thumb. - if (mThumbRect.pointInRect(x,y)) - { - mMouseOffset = (mOrientation == HORIZONTAL) - ? (mThumbRect.mLeft + mThumbImage->getWidth()/2) - x - : (mThumbRect.mBottom + mThumbImage->getHeight()/2) - y; - } - else - { - mMouseOffset = 0; - } - - // Start dragging the thumb - // No handler needed for focus lost since this class has no state that depends on it. - gFocusMgr.setMouseCapture( this ); - mDragStartThumbRect = mThumbRect; - } - make_ui_sound("UISndClick"); - - return TRUE; + // only do sticky-focus on non-chrome widgets + if (!getIsChrome()) + { + setFocus(TRUE); + } + if (mMouseDownSignal) + (*mMouseDownSignal)( this, getValueF32() ); + + if (MASK_CONTROL & mask) // if CTRL is modifying + { + setValueAndCommit(mInitialValue); + } + else + { + // Find the offset of the actual mouse location from the center of the thumb. + if (mThumbRect.pointInRect(x,y)) + { + mMouseOffset = (mOrientation == HORIZONTAL) + ? (mThumbRect.mLeft + mThumbImage->getWidth()/2) - x + : (mThumbRect.mBottom + mThumbImage->getHeight()/2) - y; + } + else + { + mMouseOffset = 0; + } + + // Start dragging the thumb + // No handler needed for focus lost since this class has no state that depends on it. + gFocusMgr.setMouseCapture( this ); + mDragStartThumbRect = mThumbRect; + } + make_ui_sound("UISndClick"); + + return TRUE; } BOOL LLSlider::handleKeyHere(KEY key, MASK mask) { - BOOL handled = FALSE; - switch(key) - { - case KEY_DOWN: - case KEY_LEFT: - setValueAndCommit(getValueF32() - getIncrement()); - handled = TRUE; - break; - case KEY_UP: - case KEY_RIGHT: - setValueAndCommit(getValueF32() + getIncrement()); - handled = TRUE; - break; - default: - break; - } - return handled; + BOOL handled = FALSE; + switch(key) + { + case KEY_DOWN: + case KEY_LEFT: + setValueAndCommit(getValueF32() - getIncrement()); + handled = TRUE; + break; + case KEY_UP: + case KEY_RIGHT: + setValueAndCommit(getValueF32() + getIncrement()); + handled = TRUE; + break; + default: + break; + } + return handled; } BOOL LLSlider::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if ( mOrientation == VERTICAL ) - { - F32 new_val = getValueF32() - clicks * getIncrement(); - setValueAndCommit(new_val); - return TRUE; - } - return LLF32UICtrl::handleScrollWheel(x,y,clicks); + if ( mOrientation == VERTICAL ) + { + F32 new_val = getValueF32() - clicks * getIncrement(); + setValueAndCommit(new_val); + return TRUE; + } + return LLF32UICtrl::handleScrollWheel(x,y,clicks); } void LLSlider::draw() { - F32 alpha = getDrawContext().mAlpha; - - // since thumb image might still be decoding, need thumb to accomodate image size - updateThumbRect(); - - // Draw background and thumb. - - // drawing solids requires texturing be disabled - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // Track - LLPointer<LLUIImage>& trackImage = ( mOrientation == HORIZONTAL ) - ? mTrackImageHorizontal - : mTrackImageVertical; - - LLPointer<LLUIImage>& trackHighlightImage = ( mOrientation == HORIZONTAL ) - ? mTrackHighlightHorizontalImage - : mTrackHighlightVerticalImage; - - LLRect track_rect; - LLRect highlight_rect; - - if ( mOrientation == HORIZONTAL ) - { - track_rect.set(mThumbImage->getWidth() / 2, - getLocalRect().getCenterY() + (trackImage->getHeight() / 2), - getRect().getWidth() - mThumbImage->getWidth() / 2, - getLocalRect().getCenterY() - (trackImage->getHeight() / 2) ); - highlight_rect.set(track_rect.mLeft, track_rect.mTop, mThumbRect.getCenterX(), track_rect.mBottom); - } - else - { - track_rect.set(getLocalRect().getCenterX() - (trackImage->getWidth() / 2), - getRect().getHeight(), - getLocalRect().getCenterX() + (trackImage->getWidth() / 2), - 0); - highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom); - } - - LLColor4 color = isInEnabledChain() ? LLColor4::white % alpha : LLColor4::white % (0.6f * alpha); - trackImage->draw(track_rect, color); - trackHighlightImage->draw(highlight_rect, color); - - // Thumb - if (hasFocus()) - { - // Draw focus highlighting. - mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor() % alpha, gFocusMgr.getFocusFlashWidth()); - } - - if( hasMouseCapture() ) // currently clicking on slider - { - // Show ghost where thumb was before dragging began. - if (mThumbImage.notNull()) - { - mThumbImage->draw(mDragStartThumbRect, mThumbCenterColor.get() % (0.3f * alpha)); - } - if (mThumbImagePressed.notNull()) - { - mThumbImagePressed->draw(mThumbRect, mThumbOutlineColor % alpha); - } - } - else if (!isInEnabledChain()) - { - if (mThumbImageDisabled.notNull()) - { - mThumbImageDisabled->draw(mThumbRect, mThumbCenterColor % alpha); - } - } - else - { - if (mThumbImage.notNull()) - { - mThumbImage->draw(mThumbRect, mThumbCenterColor % alpha); - } - } - - LLUICtrl::draw(); + F32 alpha = getDrawContext().mAlpha; + + // since thumb image might still be decoding, need thumb to accomodate image size + updateThumbRect(); + + // Draw background and thumb. + + // drawing solids requires texturing be disabled + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // Track + LLPointer<LLUIImage>& trackImage = ( mOrientation == HORIZONTAL ) + ? mTrackImageHorizontal + : mTrackImageVertical; + + LLPointer<LLUIImage>& trackHighlightImage = ( mOrientation == HORIZONTAL ) + ? mTrackHighlightHorizontalImage + : mTrackHighlightVerticalImage; + + LLRect track_rect; + LLRect highlight_rect; + + if ( mOrientation == HORIZONTAL ) + { + track_rect.set(mThumbImage->getWidth() / 2, + getLocalRect().getCenterY() + (trackImage->getHeight() / 2), + getRect().getWidth() - mThumbImage->getWidth() / 2, + getLocalRect().getCenterY() - (trackImage->getHeight() / 2) ); + highlight_rect.set(track_rect.mLeft, track_rect.mTop, mThumbRect.getCenterX(), track_rect.mBottom); + } + else + { + track_rect.set(getLocalRect().getCenterX() - (trackImage->getWidth() / 2), + getRect().getHeight(), + getLocalRect().getCenterX() + (trackImage->getWidth() / 2), + 0); + highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom); + } + + LLColor4 color = isInEnabledChain() ? LLColor4::white % alpha : LLColor4::white % (0.6f * alpha); + trackImage->draw(track_rect, color); + trackHighlightImage->draw(highlight_rect, color); + + // Thumb + if (hasFocus()) + { + // Draw focus highlighting. + mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor() % alpha, gFocusMgr.getFocusFlashWidth()); + } + + if( hasMouseCapture() ) // currently clicking on slider + { + // Show ghost where thumb was before dragging began. + if (mThumbImage.notNull()) + { + mThumbImage->draw(mDragStartThumbRect, mThumbCenterColor.get() % (0.3f * alpha)); + } + if (mThumbImagePressed.notNull()) + { + mThumbImagePressed->draw(mThumbRect, mThumbOutlineColor % alpha); + } + } + else if (!isInEnabledChain()) + { + if (mThumbImageDisabled.notNull()) + { + mThumbImageDisabled->draw(mThumbRect, mThumbCenterColor % alpha); + } + } + else + { + if (mThumbImage.notNull()) + { + mThumbImage->draw(mThumbRect, mThumbCenterColor % alpha); + } + } + + LLUICtrl::draw(); } -boost::signals2::connection LLSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); - return mMouseDownSignal->connect(cb); +boost::signals2::connection LLSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); + return mMouseDownSignal->connect(cb); } -boost::signals2::connection LLSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); - return mMouseUpSignal->connect(cb); +boost::signals2::connection LLSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); + return mMouseUpSignal->connect(cb); } diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index 484a5373b3..4f4acdc50c 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -1,25 +1,25 @@ -/** +/** * @file llslider.h * @brief A simple slider with no label. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,75 +34,75 @@ class LLSlider : public LLF32UICtrl { public: - struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> - { - Optional<std::string> orientation; + struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> + { + Optional<std::string> orientation; - Optional<LLUIColor> thumb_outline_color, - thumb_center_color; + Optional<LLUIColor> thumb_outline_color, + thumb_center_color; - Optional<LLUIImage*> thumb_image, - thumb_image_pressed, - thumb_image_disabled, - track_image_horizontal, - track_image_vertical, - track_highlight_horizontal_image, - track_highlight_vertical_image; + Optional<LLUIImage*> thumb_image, + thumb_image_pressed, + thumb_image_disabled, + track_image_horizontal, + track_image_vertical, + track_highlight_horizontal_image, + track_highlight_vertical_image; - Optional<CommitCallbackParam> mouse_down_callback, - mouse_up_callback; + Optional<CommitCallbackParam> mouse_down_callback, + mouse_up_callback; - Params(); - }; + Params(); + }; protected: - LLSlider(const Params&); - friend class LLUICtrlFactory; + LLSlider(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLSlider(); - void setValue( F32 value, BOOL from_event = FALSE ); + virtual ~LLSlider(); + void setValue( F32 value, BOOL from_event = FALSE ); // overrides for LLF32UICtrl methods - virtual void setValue(const LLSD& value ) { setValue((F32)value.asReal(), TRUE); } - - virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } - virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } - virtual void setMinValue(F32 min_value) { LLF32UICtrl::setMinValue(min_value); updateThumbRect(); } - virtual void setMaxValue(F32 max_value) { LLF32UICtrl::setMaxValue(max_value); updateThumbRect(); } - - boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); - - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - virtual void draw(); + virtual void setValue(const LLSD& value ) { setValue((F32)value.asReal(), TRUE); } + + virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + virtual void setMinValue(F32 min_value) { LLF32UICtrl::setMinValue(min_value); updateThumbRect(); } + virtual void setMaxValue(F32 max_value) { LLF32UICtrl::setMaxValue(max_value); updateThumbRect(); } + + boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); + + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + virtual void draw(); private: - void setValueAndCommit(F32 value); - void updateThumbRect(); - - BOOL mVolumeSlider; - S32 mMouseOffset; - LLRect mDragStartThumbRect; - - LLPointer<LLUIImage> mThumbImage; - LLPointer<LLUIImage> mThumbImagePressed; - LLPointer<LLUIImage> mThumbImageDisabled; - LLPointer<LLUIImage> mTrackImageHorizontal; - LLPointer<LLUIImage> mTrackImageVertical; - LLPointer<LLUIImage> mTrackHighlightHorizontalImage; - LLPointer<LLUIImage> mTrackHighlightVerticalImage; - - const EOrientation mOrientation; - - LLRect mThumbRect; - LLUIColor mThumbOutlineColor; - LLUIColor mThumbCenterColor; - - commit_signal_t* mMouseDownSignal; - commit_signal_t* mMouseUpSignal; + void setValueAndCommit(F32 value); + void updateThumbRect(); + + BOOL mVolumeSlider; + S32 mMouseOffset; + LLRect mDragStartThumbRect; + + LLPointer<LLUIImage> mThumbImage; + LLPointer<LLUIImage> mThumbImagePressed; + LLPointer<LLUIImage> mThumbImageDisabled; + LLPointer<LLUIImage> mTrackImageHorizontal; + LLPointer<LLUIImage> mTrackImageVertical; + LLPointer<LLUIImage> mTrackHighlightHorizontalImage; + LLPointer<LLUIImage> mTrackHighlightVerticalImage; + + const EOrientation mOrientation; + + LLRect mThumbRect; + LLUIColor mThumbOutlineColor; + LLUIColor mThumbCenterColor; + + commit_signal_t* mMouseDownSignal; + commit_signal_t* mMouseUpSignal; }; #endif // LL_LLSLIDER_H diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index d80a434f22..e16ba9408e 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsliderctrl.cpp * @brief LLSliderCtrl base class * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,241 +46,241 @@ static LLDefaultChildRegistry::Register<LLSliderCtrl> r("slider"); LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) -: LLF32UICtrl(p), - mLabelBox( NULL ), - mEditor( NULL ), - mTextBox( NULL ), - mFont(p.font), - mShowText(p.show_text), - mCanEditText(p.can_edit_text), - mPrecision(p.decimal_digits), - mTextEnabledColor(p.text_color()), - mTextDisabledColor(p.text_disabled_color()), - mLabelWidth(p.label_width), - mEditorCommitSignal(NULL) +: LLF32UICtrl(p), + mLabelBox( NULL ), + mEditor( NULL ), + mTextBox( NULL ), + mFont(p.font), + mShowText(p.show_text), + mCanEditText(p.can_edit_text), + mPrecision(p.decimal_digits), + mTextEnabledColor(p.text_color()), + mTextDisabledColor(p.text_disabled_color()), + mLabelWidth(p.label_width), + mEditorCommitSignal(NULL) { - S32 top = getRect().getHeight(); - S32 bottom = 0; - S32 left = 0; - - S32 label_width = p.label_width; - S32 text_width = p.text_width; - - // Label - if( !p.label().empty() ) - { - if (!p.label_width.isProvided()) - { - label_width = p.font()->getWidth(p.label); - } - LLRect label_rect( left, top, label_width, bottom ); - LLTextBox::Params params(p.slider_label); - if (!params.rect.isProvided()) - { - params.rect = label_rect; - } - if (!params.font.isProvided()) - { - params.font = p.font; - } - params.initial_value(p.label()); - mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mLabelBox); - mLabelFont = params.font(); - } - - if (p.show_text && !p.text_width.isProvided()) - { - // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) - if ( p.max_value ) - text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 ); - - if ( p.increment < 1.0f ) - text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value - - if ( p.min_value < 0.0f || p.max_value < 0.0f ) - text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign - - // padding to make things look nicer - text_width += 8; - } - - - S32 text_left = getRect().getWidth() - text_width; - static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0); - - S32 slider_right = getRect().getWidth(); - if( p.show_text ) - { - slider_right = text_left - sliderctrl_spacing; - } - - S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0; - LLSlider::Params slider_p(p.slider_bar); - slider_p.name("slider_bar"); - if (!slider_p.rect.isProvided()) - { - slider_p.rect = LLRect(slider_left,top,slider_right,bottom); - } - if (!slider_p.initial_value.isProvided()) - { - slider_p.initial_value = p.initial_value().asReal(); - } - if (!slider_p.min_value.isProvided()) - { - slider_p.min_value = p.min_value; - } - if (!slider_p.max_value.isProvided()) - { - slider_p.max_value = p.max_value; - } - if (!slider_p.increment.isProvided()) - { - slider_p.increment = p.increment; - } - if (!slider_p.orientation.isProvided()) - { - slider_p.orientation = p.orientation; - } - - slider_p.commit_callback.function = &LLSliderCtrl::onSliderCommit; - slider_p.control_name = p.control_name; - slider_p.mouse_down_callback( p.mouse_down_callback ); - slider_p.mouse_up_callback( p.mouse_up_callback ); - mSlider = LLUICtrlFactory::create<LLSlider> (slider_p); - - addChild( mSlider ); - - if( p.show_text() ) - { - LLRect text_rect( text_left, top, getRect().getWidth(), bottom ); - if( p.can_edit_text() ) - { - LLLineEditor::Params line_p(p.value_editor); - if (!line_p.rect.isProvided()) - { - line_p.rect = text_rect; - } - if (!line_p.font.isProvided()) - { - line_p.font = p.font; - } - - line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit); - line_p.prevalidate_callback(&LLTextValidate::validateFloat); - mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); - - mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); - // don't do this, as selecting the entire text is single clicking in some cases - // and double clicking in others - //mEditor->setSelectAllonFocusReceived(TRUE); - addChild(mEditor); - } - else - { - LLTextBox::Params text_p(p.value_text); - if (!text_p.rect.isProvided()) - { - text_p.rect = text_rect; - } - if (!text_p.font.isProvided()) - { - text_p.font = p.font; - } - mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p); - addChild(mTextBox); - } - } - - updateText(); + S32 top = getRect().getHeight(); + S32 bottom = 0; + S32 left = 0; + + S32 label_width = p.label_width; + S32 text_width = p.text_width; + + // Label + if( !p.label().empty() ) + { + if (!p.label_width.isProvided()) + { + label_width = p.font()->getWidth(p.label); + } + LLRect label_rect( left, top, label_width, bottom ); + LLTextBox::Params params(p.slider_label); + if (!params.rect.isProvided()) + { + params.rect = label_rect; + } + if (!params.font.isProvided()) + { + params.font = p.font; + } + params.initial_value(p.label()); + mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mLabelBox); + mLabelFont = params.font(); + } + + if (p.show_text && !p.text_width.isProvided()) + { + // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) + if ( p.max_value ) + text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 ); + + if ( p.increment < 1.0f ) + text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value + + if ( p.min_value < 0.0f || p.max_value < 0.0f ) + text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign + + // padding to make things look nicer + text_width += 8; + } + + + S32 text_left = getRect().getWidth() - text_width; + static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0); + + S32 slider_right = getRect().getWidth(); + if( p.show_text ) + { + slider_right = text_left - sliderctrl_spacing; + } + + S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0; + LLSlider::Params slider_p(p.slider_bar); + slider_p.name("slider_bar"); + if (!slider_p.rect.isProvided()) + { + slider_p.rect = LLRect(slider_left,top,slider_right,bottom); + } + if (!slider_p.initial_value.isProvided()) + { + slider_p.initial_value = p.initial_value().asReal(); + } + if (!slider_p.min_value.isProvided()) + { + slider_p.min_value = p.min_value; + } + if (!slider_p.max_value.isProvided()) + { + slider_p.max_value = p.max_value; + } + if (!slider_p.increment.isProvided()) + { + slider_p.increment = p.increment; + } + if (!slider_p.orientation.isProvided()) + { + slider_p.orientation = p.orientation; + } + + slider_p.commit_callback.function = &LLSliderCtrl::onSliderCommit; + slider_p.control_name = p.control_name; + slider_p.mouse_down_callback( p.mouse_down_callback ); + slider_p.mouse_up_callback( p.mouse_up_callback ); + mSlider = LLUICtrlFactory::create<LLSlider> (slider_p); + + addChild( mSlider ); + + if( p.show_text() ) + { + LLRect text_rect( text_left, top, getRect().getWidth(), bottom ); + if( p.can_edit_text() ) + { + LLLineEditor::Params line_p(p.value_editor); + if (!line_p.rect.isProvided()) + { + line_p.rect = text_rect; + } + if (!line_p.font.isProvided()) + { + line_p.font = p.font; + } + + line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit); + line_p.prevalidator(&LLTextValidate::validateFloat); + mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p); + + mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this )); + // don't do this, as selecting the entire text is single clicking in some cases + // and double clicking in others + //mEditor->setSelectAllonFocusReceived(TRUE); + addChild(mEditor); + } + else + { + LLTextBox::Params text_p(p.value_text); + if (!text_p.rect.isProvided()) + { + text_p.rect = text_rect; + } + if (!text_p.font.isProvided()) + { + text_p.font = p.font; + } + mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p); + addChild(mTextBox); + } + } + + updateText(); } LLSliderCtrl::~LLSliderCtrl() { - delete mEditorCommitSignal; + delete mEditorCommitSignal; } // static void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) { - LLSliderCtrl* self = (LLSliderCtrl*) userdata; - llassert( caller == self->mEditor ); + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + llassert( caller == self->mEditor ); - self->onFocusReceived(); + self->onFocusReceived(); } void LLSliderCtrl::setValue(F32 v, BOOL from_event) { - mSlider->setValue( v, from_event ); - mValue = mSlider->getValueF32(); - updateText(); + mSlider->setValue( v, from_event ); + mValue = mSlider->getValueF32(); + updateText(); } BOOL LLSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - BOOL res = FALSE; - if (mLabelBox) - { - res = mLabelBox->setTextArg(key, text); - if (res && mLabelFont && mLabelWidth == 0) - { - S32 label_width = mLabelFont->getWidth(mLabelBox->getText()); - LLRect rect = mLabelBox->getRect(); - S32 prev_right = rect.mRight; - rect.mRight = rect.mLeft + label_width; - mLabelBox->setRect(rect); - - S32 delta = rect.mRight - prev_right; - rect = mSlider->getRect(); - S32 left = rect.mLeft + delta; - static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0); - left = llclamp(left, 0, rect.mRight - sliderctrl_spacing); - rect.mLeft = left; - mSlider->setRect(rect); - } - } - return res; + BOOL res = FALSE; + if (mLabelBox) + { + res = mLabelBox->setTextArg(key, text); + if (res && mLabelFont && mLabelWidth == 0) + { + S32 label_width = mLabelFont->getWidth(mLabelBox->getText()); + LLRect rect = mLabelBox->getRect(); + S32 prev_right = rect.mRight; + rect.mRight = rect.mLeft + label_width; + mLabelBox->setRect(rect); + + S32 delta = rect.mRight - prev_right; + rect = mSlider->getRect(); + S32 left = rect.mLeft + delta; + static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0); + left = llclamp(left, 0, rect.mRight - sliderctrl_spacing); + rect.mLeft = left; + mSlider->setRect(rect); + } + } + return res; } void LLSliderCtrl::clear() { - setValue(0.0f); - if( mEditor ) - { - mEditor->setText( LLStringUtil::null ); - } - if( mTextBox ) - { - mTextBox->setText( LLStringUtil::null ); - } + setValue(0.0f); + if( mEditor ) + { + mEditor->setText( LLStringUtil::null ); + } + if( mTextBox ) + { + mTextBox->setText( LLStringUtil::null ); + } } void LLSliderCtrl::updateText() { - if( mEditor || mTextBox ) - { - LLLocale locale(LLLocale::USER_LOCALE); - - // Don't display very small negative values as -0.000 - F32 displayed_value = (F32)(floor(getValueF32() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision)); - - std::string format = llformat("%%.%df", mPrecision); - std::string text = llformat(format.c_str(), displayed_value); - if( mEditor ) - { - // Setting editor text here to "" before using actual text is here because if text which - // is set is the same as the one which is actually typed into lineeditor, LLLineEditor::setText() - // will exit at it's beginning, so text for revert on escape won't be saved. (EXT-8536) - mEditor->setText( LLStringUtil::null ); - mEditor->setText( text ); - } - else - { - mTextBox->setText( text ); - } - } + if( mEditor || mTextBox ) + { + LLLocale locale(LLLocale::USER_LOCALE); + + // Don't display very small negative values as -0.000 + F32 displayed_value = (F32)(floor(getValueF32() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision)); + + std::string format = llformat("%%.%df", mPrecision); + std::string text = llformat(format.c_str(), displayed_value); + if( mEditor ) + { + // Setting editor text here to "" before using actual text is here because if text which + // is set is the same as the one which is actually typed into lineeditor, LLLineEditor::setText() + // will exit at it's beginning, so text for revert on escape won't be saved. (EXT-8536) + mEditor->setText( LLStringUtil::null ); + mEditor->setText( text ); + } + else + { + mTextBox->setText( text ); + } + } } void LLSliderCtrl::updateSliderRect() @@ -315,122 +315,122 @@ void LLSliderCtrl::updateSliderRect() // static void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata ) { - LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent()); - if (!self) - return; - - BOOL success = FALSE; - F32 val = self->mValue; - F32 saved_val = self->mValue; - - std::string text = self->mEditor->getText(); - if( LLLineEditor::postvalidateFloat( text ) ) - { - LLLocale locale(LLLocale::USER_LOCALE); - val = (F32) atof( text.c_str() ); - if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() ) - { - self->setValue( val ); // set the value temporarily so that the callback can retrieve it. - if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) ) - { - success = TRUE; - } - } - } - - if( success ) - { - self->onCommit(); - if (self->mEditorCommitSignal) - (*(self->mEditorCommitSignal))(self, self->getValueF32()); - } - else - { - if( self->getValueF32() != saved_val ) - { - self->setValue( saved_val ); - } - self->reportInvalidData(); - } - self->updateText(); + LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent()); + if (!self) + return; + + BOOL success = FALSE; + F32 val = self->mValue; + F32 saved_val = self->mValue; + + std::string text = self->mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + LLLocale locale(LLLocale::USER_LOCALE); + val = (F32) atof( text.c_str() ); + if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() ) + { + self->setValue( val ); // set the value temporarily so that the callback can retrieve it. + if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) ) + { + success = TRUE; + } + } + } + + if( success ) + { + self->onCommit(); + if (self->mEditorCommitSignal) + (*(self->mEditorCommitSignal))(self, self->getValueF32()); + } + else + { + if( self->getValueF32() != saved_val ) + { + self->setValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); } // static void LLSliderCtrl::onSliderCommit( LLUICtrl* ctrl, const LLSD& userdata ) { - LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent()); - if (!self) - return; - - BOOL success = FALSE; - F32 saved_val = self->mValue; - F32 new_val = self->mSlider->getValueF32(); - - self->mValue = new_val; // set the value temporarily so that the callback can retrieve it. - if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) ) - { - success = TRUE; - } - - if( success ) - { - self->onCommit(); - } - else - { - if( self->mValue != saved_val ) - { - self->setValue( saved_val ); - } - self->reportInvalidData(); - } - self->updateText(); + LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent()); + if (!self) + return; + + BOOL success = FALSE; + F32 saved_val = self->mValue; + F32 new_val = self->mSlider->getValueF32(); + + self->mValue = new_val; // set the value temporarily so that the callback can retrieve it. + if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) ) + { + success = TRUE; + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->mValue != saved_val ) + { + self->setValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); } void LLSliderCtrl::setEnabled(BOOL b) { - LLView::setEnabled( b ); + LLView::setEnabled( b ); - if( mLabelBox ) - { - mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + if( mLabelBox ) + { + mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } - mSlider->setEnabled( b ); + mSlider->setEnabled( b ); - if( mEditor ) - { - mEditor->setEnabled( b ); - } + if( mEditor ) + { + mEditor->setEnabled( b ); + } - if( mTextBox ) - { - mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + if( mTextBox ) + { + mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } } void LLSliderCtrl::setTentative(BOOL b) { - if( mEditor ) - { - mEditor->setTentative(b); - } - LLF32UICtrl::setTentative(b); + if( mEditor ) + { + mEditor->setTentative(b); + } + LLF32UICtrl::setTentative(b); } void LLSliderCtrl::onCommit() { - setTentative(FALSE); - - if( mEditor ) - { - mEditor->setTentative(FALSE); - } - - setControlValue(getValueF32()); - LLF32UICtrl::onCommit(); + setTentative(FALSE); + + if( mEditor ) + { + mEditor->setTentative(FALSE); + } + + setControlValue(getValueF32()); + LLF32UICtrl::onCommit(); } void LLSliderCtrl::setRect(const LLRect& rect) @@ -448,42 +448,42 @@ void LLSliderCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) void LLSliderCtrl::setPrecision(S32 precision) { - if (precision < 0 || precision > 10) - { - LL_ERRS() << "LLSliderCtrl::setPrecision - precision out of range" << LL_ENDL; - return; - } - - mPrecision = precision; - updateText(); + if (precision < 0 || precision > 10) + { + LL_ERRS() << "LLSliderCtrl::setPrecision - precision out of range" << LL_ENDL; + return; + } + + mPrecision = precision; + updateText(); } boost::signals2::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ) { - return mSlider->setMouseDownCallback( cb ); + return mSlider->setMouseDownCallback( cb ); } boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ) { - return mSlider->setMouseUpCallback( cb ); + return mSlider->setMouseUpCallback( cb ); } -boost::signals2::connection LLSliderCtrl::setSliderEditorCommitCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mEditorCommitSignal) mEditorCommitSignal = new commit_signal_t(); - return mEditorCommitSignal->connect(cb); +boost::signals2::connection LLSliderCtrl::setSliderEditorCommitCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mEditorCommitSignal) mEditorCommitSignal = new commit_signal_t(); + return mEditorCommitSignal->connect(cb); } void LLSliderCtrl::onTabInto() { - if( mEditor ) - { - mEditor->onTabInto(); - } + if( mEditor ) + { + mEditor->onTabInto(); + } LLF32UICtrl::onTabInto(); } void LLSliderCtrl::reportInvalidData() { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 541c167717..48e59045a7 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file llsliderctrl.h * @brief Decorated wrapper for a LLSlider. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,138 +38,138 @@ class LLSliderCtrl: public LLF32UICtrl, public ll::ui::SearchableControl { public: - struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> - { - Optional<std::string> orientation; - Optional<S32> label_width; - Optional<S32> text_width; - Optional<bool> show_text; - Optional<bool> can_edit_text; - Optional<bool> is_volume_slider; - Optional<S32> decimal_digits; - - Optional<LLUIColor> text_color, - text_disabled_color; - - Optional<CommitCallbackParam> mouse_down_callback, - mouse_up_callback; - - Optional<LLSlider::Params> slider_bar; - Optional<LLLineEditor::Params> value_editor; - Optional<LLTextBox::Params> value_text; - Optional<LLTextBox::Params> slider_label; - - Params() - : text_width("text_width"), - label_width("label_width"), - show_text("show_text"), - can_edit_text("can_edit_text"), - is_volume_slider("volume"), - decimal_digits("decimal_digits", 3), - text_color("text_color"), - text_disabled_color("text_disabled_color"), - slider_bar("slider_bar"), - value_editor("value_editor"), - value_text("value_text"), - slider_label("slider_label"), - mouse_down_callback("mouse_down_callback"), - mouse_up_callback("mouse_up_callback"), - orientation("orientation", std::string ("horizontal")) - {} - }; + struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> + { + Optional<std::string> orientation; + Optional<S32> label_width; + Optional<S32> text_width; + Optional<bool> show_text; + Optional<bool> can_edit_text; + Optional<bool> is_volume_slider; + Optional<S32> decimal_digits; + + Optional<LLUIColor> text_color, + text_disabled_color; + + Optional<CommitCallbackParam> mouse_down_callback, + mouse_up_callback; + + Optional<LLSlider::Params> slider_bar; + Optional<LLLineEditor::Params> value_editor; + Optional<LLTextBox::Params> value_text; + Optional<LLTextBox::Params> slider_label; + + Params() + : text_width("text_width"), + label_width("label_width"), + show_text("show_text"), + can_edit_text("can_edit_text"), + is_volume_slider("volume"), + decimal_digits("decimal_digits", 3), + text_color("text_color"), + text_disabled_color("text_disabled_color"), + slider_bar("slider_bar"), + value_editor("value_editor"), + value_text("value_text"), + slider_label("slider_label"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + orientation("orientation", std::string ("horizontal")) + {} + }; protected: - LLSliderCtrl(const Params&); - friend class LLUICtrlFactory; + LLSliderCtrl(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLSliderCtrl(); + virtual ~LLSliderCtrl(); + + /*virtual*/ F32 getValueF32() const { return mSlider->getValueF32(); } + void setValue(F32 v, BOOL from_event = FALSE); - /*virtual*/ F32 getValueF32() const { return mSlider->getValueF32(); } - void setValue(F32 v, BOOL from_event = FALSE); + /*virtual*/ void setValue(const LLSD& value) { setValue((F32)value.asReal(), TRUE); } + /*virtual*/ LLSD getValue() const { return LLSD(getValueF32()); } + /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - /*virtual*/ void setValue(const LLSD& value) { setValue((F32)value.asReal(), TRUE); } - /*virtual*/ LLSD getValue() const { return LLSD(getValueF32()); } - /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + BOOL isMouseHeldDown() const { return mSlider->hasMouseCapture(); } - BOOL isMouseHeldDown() const { return mSlider->hasMouseCapture(); } + virtual void setPrecision(S32 precision); - virtual void setPrecision(S32 precision); + /*virtual*/ void setEnabled( BOOL b ); + /*virtual*/ void clear(); - /*virtual*/ void setEnabled( BOOL b ); - /*virtual*/ void clear(); + /*virtual*/ void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + /*virtual*/ void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + /*virtual*/ void setMinValue(F32 min_value) { mSlider->setMinValue(min_value); updateText(); } + /*virtual*/ void setMaxValue(F32 max_value) { mSlider->setMaxValue(max_value); updateText(); } + /*virtual*/ void setIncrement(F32 increment) { mSlider->setIncrement(increment);} - /*virtual*/ void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } - /*virtual*/ void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } - /*virtual*/ void setMinValue(F32 min_value) { mSlider->setMinValue(min_value); updateText(); } - /*virtual*/ void setMaxValue(F32 max_value) { mSlider->setMaxValue(max_value); updateText(); } - /*virtual*/ void setIncrement(F32 increment) { mSlider->setIncrement(increment);} + F32 getMinValue() const { return mSlider->getMinValue(); } + F32 getMaxValue() const { return mSlider->getMaxValue(); } - F32 getMinValue() const { return mSlider->getMinValue(); } - F32 getMaxValue() const { return mSlider->getMaxValue(); } + void setLabel(const LLStringExplicit& label) { if (mLabelBox) mLabelBox->setText(label); } + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } - void setLabel(const LLStringExplicit& label) { if (mLabelBox) mLabelBox->setText(label); } - void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } - void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } + boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setSliderEditorCommitCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setSliderEditorCommitCallback( const commit_signal_t::slot_type& cb ); + /*virtual*/ void onTabInto(); - /*virtual*/ void onTabInto(); + /*virtual*/ void setTentative(BOOL b); // marks value as tentative + /*virtual*/ void onCommit(); // mark not tentative, then commit - /*virtual*/ void setTentative(BOOL b); // marks value as tentative - /*virtual*/ void onCommit(); // mark not tentative, then commit + /*virtual*/ void setControlName(const std::string& control_name, LLView* context) + { + LLUICtrl::setControlName(control_name, context); + mSlider->setControlName(control_name, context); + } - /*virtual*/ void setControlName(const std::string& control_name, LLView* context) - { - LLUICtrl::setControlName(control_name, context); - mSlider->setControlName(control_name, context); - } + /*virtual*/ void setRect(const LLRect& rect); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void setRect(const LLRect& rect); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata); - static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata); - - static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); + static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); + static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); + static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); protected: - virtual std::string _getSearchText() const - { - std::string strLabel; - if( mLabelBox ) - strLabel = mLabelBox->getLabel(); - return strLabel + getToolTip(); - } - virtual void onSetHighlight() const // When highlight, really do highlight the label - { - if( mLabelBox ) - mLabelBox->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); - } + virtual std::string _getSearchText() const + { + std::string strLabel; + if( mLabelBox ) + strLabel = mLabelBox->getLabel(); + return strLabel + getToolTip(); + } + virtual void onSetHighlight() const // When highlight, really do highlight the label + { + if( mLabelBox ) + mLabelBox->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); + } private: - void updateText(); - void updateSliderRect(); - void reportInvalidData(); - - const LLFontGL* mFont; - const LLFontGL* mLabelFont; - BOOL mShowText; - BOOL mCanEditText; - - S32 mPrecision; - LLTextBox* mLabelBox; - S32 mLabelWidth; - - F32 mValue; - LLSlider* mSlider; - class LLLineEditor* mEditor; - LLTextBox* mTextBox; - - LLUIColor mTextEnabledColor; - LLUIColor mTextDisabledColor; - - commit_signal_t* mEditorCommitSignal; + void updateText(); + void updateSliderRect(); + void reportInvalidData(); + + const LLFontGL* mFont; + const LLFontGL* mLabelFont; + BOOL mShowText; + BOOL mCanEditText; + + S32 mPrecision; + LLTextBox* mLabelBox; + S32 mLabelWidth; + + F32 mValue; + LLSlider* mSlider; + class LLLineEditor* mEditor; + LLTextBox* mTextBox; + + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; + + commit_signal_t* mEditorCommitSignal; }; #endif // LL_LLSLIDERCTRL_H diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index ebd8ca0923..b8aeb3b91f 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llspellcheck.cpp * @brief Spell checking functionality * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,10 +31,10 @@ #include "llspellcheck.h" #if LL_WINDOWS - #include <hunspell/hunspelldll.h> - #pragma comment(lib, "libhunspell.lib") + #include <hunspell/hunspelldll.h> + #pragma comment(lib, "libhunspell.lib") #else - #include <hunspell/hunspell.hxx> + #include <hunspell/hunspell.hxx> #endif static const std::string DICT_DIR = "dictionaries"; @@ -47,453 +47,453 @@ static const std::string DICT_FILE_USER = "user_dictionaries.xml"; LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; LLSpellChecker::LLSpellChecker() - : mHunspell(NULL) + : mHunspell(NULL) { } LLSpellChecker::~LLSpellChecker() { - delete mHunspell; + delete mHunspell; } void LLSpellChecker::initSingleton() { - // Load initial dictionary information - refreshDictionaryMap(); + // Load initial dictionary information + refreshDictionaryMap(); } bool LLSpellChecker::checkSpelling(const std::string& word) const { - if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) ) - { - return true; - } - if (mIgnoreList.size() > 0) - { - std::string word_lower(word); - LLStringUtil::toLower(word_lower); - return (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)); - } - return false; + if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) ) + { + return true; + } + if (mIgnoreList.size() > 0) + { + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + return (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)); + } + return false; } S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const { - suggestions.clear(); - if ( (!mHunspell) || (word.length() < 3) ) - { - return 0; - } - - char** suggestion_list; int suggestion_cnt = 0; - if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 ) - { - for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++) - { - suggestions.push_back(suggestion_list[suggestion_index]); - } - mHunspell->free_list(&suggestion_list, suggestion_cnt); - } - return suggestions.size(); + suggestions.clear(); + if ( (!mHunspell) || (word.length() < 3) ) + { + return 0; + } + + char** suggestion_list; int suggestion_cnt = 0; + if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 ) + { + for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++) + { + suggestions.push_back(suggestion_list[suggestion_index]); + } + mHunspell->free_list(&suggestion_list, suggestion_cnt); + } + return suggestions.size(); } const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language) { - for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) - { - const LLSD& dict_entry = *it; - if (dict_language == dict_entry["language"].asString()) - { - return dict_entry; - } - } - return LLSD(); + for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + { + const LLSD& dict_entry = *it; + if (dict_language == dict_entry["language"].asString()) + { + return dict_entry; + } + } + return LLSD(); } bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed) { - const LLSD dict_info = getDictionaryData(dict_language); - return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) ); + const LLSD dict_info = getDictionaryData(dict_language); + return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) ); } void LLSpellChecker::setDictionaryData(const LLSD& dict_info) { - const std::string dict_language = dict_info["language"].asString(); - if (dict_language.empty()) - { - return; - } - - for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) - { - LLSD& dict_entry = *it; - if (dict_language == dict_entry["language"].asString()) - { - dict_entry = dict_info; - return; - } - } - mDictMap.append(dict_info); - return; + const std::string dict_language = dict_info["language"].asString(); + if (dict_language.empty()) + { + return; + } + + for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + { + LLSD& dict_entry = *it; + if (dict_language == dict_entry["language"].asString()) + { + dict_entry = dict_info; + return; + } + } + mDictMap.append(dict_info); + return; } // static void LLSpellChecker::refreshDictionaryMap() { - const std::string app_path = getDictionaryAppPath(); - const std::string user_path = getDictionaryUserPath(); + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); - // Load dictionary information (file name, friendly name, ...) + // Load dictionary information (file name, friendly name, ...) std::string user_filename(user_path + DICT_FILE_MAIN); - llifstream user_file(user_filename.c_str(), std::ios::binary); - if ( (!user_file.is_open()) - || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, user_file)) - || (0 == mDictMap.size()) ) - { + llifstream user_file(user_filename.c_str(), std::ios::binary); + if ( (!user_file.is_open()) + || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, user_file)) + || (0 == mDictMap.size()) ) + { std::string app_filename(app_path + DICT_FILE_MAIN); - llifstream app_file(app_filename.c_str(), std::ios::binary); - if ( (!app_file.is_open()) - || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, app_file)) - || (0 == mDictMap.size()) ) - { - return; - } - } - - // Load user installed dictionary information - user_filename = user_path + DICT_FILE_USER; - llifstream custom_file(user_filename.c_str(), std::ios::binary); - if (custom_file.is_open()) - { - LLSD custom_dict_map; - LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file); - for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it) - { - LLSD& dict_info = *it; - dict_info["user_installed"] = true; - setDictionaryData(dict_info); - } - custom_file.close(); - } - - // Look for installed dictionaries - std::string tmp_app_path, tmp_user_path; - for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) - { - LLSD& sdDict = *it; - tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; - tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; - sdDict["installed"] = - (!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic"))); - } - - sSettingsChangeSignal(); + llifstream app_file(app_filename.c_str(), std::ios::binary); + if ( (!app_file.is_open()) + || (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(mDictMap, app_file)) + || (0 == mDictMap.size()) ) + { + return; + } + } + + // Load user installed dictionary information + user_filename = user_path + DICT_FILE_USER; + llifstream custom_file(user_filename.c_str(), std::ios::binary); + if (custom_file.is_open()) + { + LLSD custom_dict_map; + LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file); + for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it) + { + LLSD& dict_info = *it; + dict_info["user_installed"] = true; + setDictionaryData(dict_info); + } + custom_file.close(); + } + + // Look for installed dictionaries + std::string tmp_app_path, tmp_user_path; + for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + { + LLSD& sdDict = *it; + tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; + tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; + sdDict["installed"] = + (!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic"))); + } + + sSettingsChangeSignal(); } void LLSpellChecker::addToCustomDictionary(const std::string& word) { - if (mHunspell) - { - mHunspell->add(word.c_str()); - } - addToDictFile(getDictionaryUserPath() + DICT_FILE_CUSTOM, word); - sSettingsChangeSignal(); + if (mHunspell) + { + mHunspell->add(word.c_str()); + } + addToDictFile(getDictionaryUserPath() + DICT_FILE_CUSTOM, word); + sSettingsChangeSignal(); } void LLSpellChecker::addToIgnoreList(const std::string& word) { - std::string word_lower(word); - LLStringUtil::toLower(word_lower); - if (mIgnoreList.end() == std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)) - { - mIgnoreList.push_back(word_lower); - addToDictFile(getDictionaryUserPath() + DICT_FILE_IGNORE, word_lower); - sSettingsChangeSignal(); - } + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + if (mIgnoreList.end() == std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)) + { + mIgnoreList.push_back(word_lower); + addToDictFile(getDictionaryUserPath() + DICT_FILE_IGNORE, word_lower); + sSettingsChangeSignal(); + } } void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::string& word) { - std::vector<std::string> word_list; - - if (gDirUtilp->fileExists(dict_path)) - { - llifstream file_in(dict_path.c_str(), std::ios::in); - if (file_in.is_open()) - { - std::string word; int line_num = 0; - while (getline(file_in, word)) - { - // Skip over the first line since that's just a line count - if (0 != line_num) - { - word_list.push_back(word); - } - line_num++; - } - } - else - { - // TODO: show error message? - return; - } - } - - word_list.push_back(word); - - llofstream file_out(dict_path.c_str(), std::ios::out | std::ios::trunc); - if (file_out.is_open()) - { - file_out << word_list.size() << std::endl; - for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord) - { - file_out << *itWord << std::endl; - } - file_out.close(); - } + std::vector<std::string> word_list; + + if (gDirUtilp->fileExists(dict_path)) + { + llifstream file_in(dict_path.c_str(), std::ios::in); + if (file_in.is_open()) + { + std::string word; int line_num = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != line_num) + { + word_list.push_back(word); + } + line_num++; + } + } + else + { + // TODO: show error message? + return; + } + } + + word_list.push_back(word); + + llofstream file_out(dict_path.c_str(), std::ios::out | std::ios::trunc); + if (file_out.is_open()) + { + file_out << word_list.size() << std::endl; + for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord) + { + file_out << *itWord << std::endl; + } + file_out.close(); + } } bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const { - return - (mDictLanguage == dict_language) || - (mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language)); + return + (mDictLanguage == dict_language) || + (mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language)); } void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) { - if (!getUseSpellCheck()) - { - return; - } - - // Check if we're only adding secondary dictionaries, or removing them - dict_list_t dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); - dict_list.sort(); - mDictSecondary.sort(); - dict_list_t::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); - dict_list_t::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); - - if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance - { - mDictSecondary = dict_list; - - std::string dict_language = mDictLanguage; - initHunspell(dict_language); - } - else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one - { - const std::string app_path = getDictionaryAppPath(); - const std::string user_path = getDictionaryUserPath(); - for (dict_list_t::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) - { - const LLSD dict_entry = getDictionaryData(*it_added); - if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) - { - continue; - } - - const std::string strFileDic = dict_entry["name"].asString() + ".dic"; - if (gDirUtilp->fileExists(user_path + strFileDic)) - { - mHunspell->add_dic((user_path + strFileDic).c_str()); - } - else if (gDirUtilp->fileExists(app_path + strFileDic)) - { - mHunspell->add_dic((app_path + strFileDic).c_str()); - } - } - mDictSecondary = dict_list; - sSettingsChangeSignal(); - } + if (!getUseSpellCheck()) + { + return; + } + + // Check if we're only adding secondary dictionaries, or removing them + dict_list_t dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); + dict_list.sort(); + mDictSecondary.sort(); + dict_list_t::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); + dict_list_t::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); + + if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance + { + mDictSecondary = dict_list; + + std::string dict_language = mDictLanguage; + initHunspell(dict_language); + } + else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one + { + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + for (dict_list_t::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) + { + const LLSD dict_entry = getDictionaryData(*it_added); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { + continue; + } + + const std::string strFileDic = dict_entry["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(user_path + strFileDic)) + { + mHunspell->add_dic((user_path + strFileDic).c_str()); + } + else if (gDirUtilp->fileExists(app_path + strFileDic)) + { + mHunspell->add_dic((app_path + strFileDic).c_str()); + } + } + mDictSecondary = dict_list; + sSettingsChangeSignal(); + } } void LLSpellChecker::initHunspell(const std::string& dict_language) { - if (mHunspell) - { - delete mHunspell; - mHunspell = NULL; - mDictLanguage.clear(); - mDictFile.clear(); - mIgnoreList.clear(); - } - - const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD(); - if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) - { - sSettingsChangeSignal(); - return; - } - - const std::string app_path = getDictionaryAppPath(); - const std::string user_path = getDictionaryUserPath(); - if (dict_entry.has("name")) - { - const std::string filename_aff = dict_entry["name"].asString() + ".aff"; - const std::string filename_dic = dict_entry["name"].asString() + ".dic"; - if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) ) - { - mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str()); - } - else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) ) - { - mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str()); - } - if (!mHunspell) - { - return; - } - - mDictLanguage = dict_language; - mDictFile = dict_entry["name"].asString(); - - if (gDirUtilp->fileExists(user_path + DICT_FILE_CUSTOM)) - { - mHunspell->add_dic((user_path + DICT_FILE_CUSTOM).c_str()); - } - - if (gDirUtilp->fileExists(user_path + DICT_FILE_IGNORE)) - { - llifstream file_in((user_path + DICT_FILE_IGNORE).c_str(), std::ios::in); - if (file_in.is_open()) - { - std::string word; int idxLine = 0; - while (getline(file_in, word)) - { - // Skip over the first line since that's just a line count - if (0 != idxLine) - { - LLStringUtil::toLower(word); - mIgnoreList.push_back(word); - } - idxLine++; - } - } - } - - for (dict_list_t::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) - { - const LLSD dict_entry = getDictionaryData(*it); - if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) - { - continue; - } - - const std::string filename_dic = dict_entry["name"].asString() + ".dic"; - if (gDirUtilp->fileExists(user_path + filename_dic)) - { - mHunspell->add_dic((user_path + filename_dic).c_str()); - } - else if (gDirUtilp->fileExists(app_path + filename_dic)) - { - mHunspell->add_dic((app_path + filename_dic).c_str()); - } - } - } - - sSettingsChangeSignal(); + if (mHunspell) + { + delete mHunspell; + mHunspell = NULL; + mDictLanguage.clear(); + mDictFile.clear(); + mIgnoreList.clear(); + } + + const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD(); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) + { + sSettingsChangeSignal(); + return; + } + + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + if (dict_entry.has("name")) + { + const std::string filename_aff = dict_entry["name"].asString() + ".aff"; + const std::string filename_dic = dict_entry["name"].asString() + ".dic"; + if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) ) + { + mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str()); + } + else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) ) + { + mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str()); + } + if (!mHunspell) + { + return; + } + + mDictLanguage = dict_language; + mDictFile = dict_entry["name"].asString(); + + if (gDirUtilp->fileExists(user_path + DICT_FILE_CUSTOM)) + { + mHunspell->add_dic((user_path + DICT_FILE_CUSTOM).c_str()); + } + + if (gDirUtilp->fileExists(user_path + DICT_FILE_IGNORE)) + { + llifstream file_in((user_path + DICT_FILE_IGNORE).c_str(), std::ios::in); + if (file_in.is_open()) + { + std::string word; int idxLine = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != idxLine) + { + LLStringUtil::toLower(word); + mIgnoreList.push_back(word); + } + idxLine++; + } + } + } + + for (dict_list_t::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) + { + const LLSD dict_entry = getDictionaryData(*it); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { + continue; + } + + const std::string filename_dic = dict_entry["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(user_path + filename_dic)) + { + mHunspell->add_dic((user_path + filename_dic).c_str()); + } + else if (gDirUtilp->fileExists(app_path + filename_dic)) + { + mHunspell->add_dic((app_path + filename_dic).c_str()); + } + } + } + + sSettingsChangeSignal(); } // static const std::string LLSpellChecker::getDictionaryAppPath() { - std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, DICT_DIR, ""); - return dict_path; + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, DICT_DIR, ""); + return dict_path; } // static const std::string LLSpellChecker::getDictionaryUserPath() { - std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, ""); - LLFile::mkdir(dict_path); - return dict_path; + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, ""); + LLFile::mkdir(dict_path); + return dict_path; } // static bool LLSpellChecker::getUseSpellCheck() { - return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); + return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); } bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language) { - // Only user-installed inactive dictionaries can be removed - const LLSD dict_info = getDictionaryData(dict_language); - return - (dict_info["user_installed"].asBoolean()) && - ( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) ); + // Only user-installed inactive dictionaries can be removed + const LLSD dict_info = getDictionaryData(dict_language); + return + (dict_info["user_installed"].asBoolean()) && + ( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) ); } void LLSpellChecker::removeDictionary(const std::string& dict_language) { - if (!canRemoveDictionary(dict_language)) - { - return; - } - - LLSD dict_map = loadUserDictionaryMap(); - for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it) - { - const LLSD& dict_info = *it; - if (dict_info["language"].asString() == dict_language) - { - const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic"; - if (gDirUtilp->fileExists(dict_dic)) - { - LLFile::remove(dict_dic); - } - const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff"; - if (gDirUtilp->fileExists(dict_aff)) - { - LLFile::remove(dict_aff); - } - dict_map.erase(it - dict_map.beginArray()); - break; - } - } - saveUserDictionaryMap(dict_map); - - refreshDictionaryMap(); + if (!canRemoveDictionary(dict_language)) + { + return; + } + + LLSD dict_map = loadUserDictionaryMap(); + for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it) + { + const LLSD& dict_info = *it; + if (dict_info["language"].asString() == dict_language) + { + const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(dict_dic)) + { + LLFile::remove(dict_dic); + } + const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff"; + if (gDirUtilp->fileExists(dict_aff)) + { + LLFile::remove(dict_aff); + } + dict_map.erase(it - dict_map.beginArray()); + break; + } + } + saveUserDictionaryMap(dict_map); + + refreshDictionaryMap(); } // static LLSD LLSpellChecker::loadUserDictionaryMap() { - LLSD dict_map; + LLSD dict_map; std::string dict_filename(getDictionaryUserPath() + DICT_FILE_USER); - llifstream dict_file(dict_filename.c_str(), std::ios::binary); - if (dict_file.is_open()) - { - LLSDSerialize::fromXMLDocument(dict_map, dict_file); - dict_file.close(); - } - return dict_map; + llifstream dict_file(dict_filename.c_str(), std::ios::binary); + if (dict_file.is_open()) + { + LLSDSerialize::fromXMLDocument(dict_map, dict_file); + dict_file.close(); + } + return dict_map; } // static void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map) { - llofstream dict_file((getDictionaryUserPath() + DICT_FILE_USER).c_str(), std::ios::trunc); - if (dict_file.is_open()) - { - LLSDSerialize::toPrettyXML(dict_map, dict_file); - dict_file.close(); - } + llofstream dict_file((getDictionaryUserPath() + DICT_FILE_USER).c_str(), std::ios::trunc); + if (dict_file.is_open()) + { + LLSDSerialize::toPrettyXML(dict_map, dict_file); + dict_file.close(); + } } // static boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb) { - return sSettingsChangeSignal.connect(cb); + return sSettingsChangeSignal.connect(cb); } // static void LLSpellChecker::setUseSpellCheck(const std::string& dict_language) { - if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) && - (LLSpellChecker::instance().mDictLanguage != dict_language) ) - { - LLSpellChecker::instance().initHunspell(dict_language); - } + if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) && + (LLSpellChecker::instance().mDictLanguage != dict_language) ) + { + LLSpellChecker::instance().initHunspell(dict_language); + } } diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index 14f9b44fe4..e4d8a12ef1 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -1,25 +1,25 @@ -/** +/** * @file llspellcheck.h * @brief Spell checking functionality * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,55 +36,55 @@ class Hunspell; class LLSpellChecker : public LLSingleton<LLSpellChecker> { - LLSINGLETON(LLSpellChecker); - ~LLSpellChecker(); + LLSINGLETON(LLSpellChecker); + ~LLSpellChecker(); public: - void addToCustomDictionary(const std::string& word); - void addToIgnoreList(const std::string& word); - bool checkSpelling(const std::string& word) const; - S32 getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const; + void addToCustomDictionary(const std::string& word); + void addToIgnoreList(const std::string& word); + bool checkSpelling(const std::string& word) const; + S32 getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const; protected: - void addToDictFile(const std::string& dict_path, const std::string& word); - void initHunspell(const std::string& dict_language); - void initSingleton() override; + void addToDictFile(const std::string& dict_path, const std::string& word); + void initHunspell(const std::string& dict_language); + void initSingleton() override; public: - typedef std::list<std::string> dict_list_t; + typedef std::list<std::string> dict_list_t; - const std::string& getPrimaryDictionary() const { return mDictLanguage; } - const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } - bool isActiveDictionary(const std::string& dict_language) const; - void setSecondaryDictionaries(dict_list_t dict_list); + const std::string& getPrimaryDictionary() const { return mDictLanguage; } + const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } + bool isActiveDictionary(const std::string& dict_language) const; + void setSecondaryDictionaries(dict_list_t dict_list); - bool canRemoveDictionary(const std::string& dict_language); - static const std::string getDictionaryAppPath(); - static const std::string getDictionaryUserPath(); - const LLSD getDictionaryData(const std::string& dict_language); - const LLSD& getDictionaryMap() { return mDictMap; } - static bool getUseSpellCheck(); - bool hasDictionary(const std::string& dict_language, bool check_installed = false); - void refreshDictionaryMap(); - void removeDictionary(const std::string& dict_language); - static void setUseSpellCheck(const std::string& dict_language); + bool canRemoveDictionary(const std::string& dict_language); + static const std::string getDictionaryAppPath(); + static const std::string getDictionaryUserPath(); + const LLSD getDictionaryData(const std::string& dict_language); + const LLSD& getDictionaryMap() { return mDictMap; } + static bool getUseSpellCheck(); + bool hasDictionary(const std::string& dict_language, bool check_installed = false); + void refreshDictionaryMap(); + void removeDictionary(const std::string& dict_language); + static void setUseSpellCheck(const std::string& dict_language); protected: - static LLSD loadUserDictionaryMap(); - void setDictionaryData(const LLSD& dict_info); - static void saveUserDictionaryMap(const LLSD& dict_map); + static LLSD loadUserDictionaryMap(); + void setDictionaryData(const LLSD& dict_info); + static void saveUserDictionaryMap(const LLSD& dict_map); public: - typedef boost::signals2::signal<void()> settings_change_signal_t; - static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); + typedef boost::signals2::signal<void()> settings_change_signal_t; + static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); protected: - Hunspell* mHunspell; - std::string mDictLanguage; - std::string mDictFile; - dict_list_t mDictSecondary; - std::vector<std::string> mIgnoreList; - LLSD mDictMap; + Hunspell* mHunspell; + std::string mDictLanguage; + std::string mDictFile; + dict_list_t mDictSecondary; + std::vector<std::string> mIgnoreList; + LLSD mDictMap; - static settings_change_signal_t sSettingsChangeSignal; + static settings_change_signal_t sSettingsChangeSignal; }; #endif // LLSPELLCHECK_H diff --git a/indra/llui/llspellcheckmenuhandler.h b/indra/llui/llspellcheckmenuhandler.h index d5c95bad39..e1fec5cbea 100644 --- a/indra/llui/llspellcheckmenuhandler.h +++ b/indra/llui/llspellcheckmenuhandler.h @@ -1,25 +1,25 @@ -/** +/** * @file llspellcheckmenuhandler.h * @brief Interface used by spell check menu handling * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,17 +30,17 @@ class LLSpellCheckMenuHandler { public: - virtual bool getSpellCheck() const { return false; } + virtual bool getSpellCheck() const { return false; } - virtual const std::string& getSuggestion(U32 index) const { return LLStringUtil::null; } - virtual U32 getSuggestionCount() const { return 0; } - virtual void replaceWithSuggestion(U32 index){} + virtual const std::string& getSuggestion(U32 index) const { return LLStringUtil::null; } + virtual U32 getSuggestionCount() const { return 0; } + virtual void replaceWithSuggestion(U32 index){} - virtual void addToDictionary() {} - virtual bool canAddToDictionary() const { return false; } + virtual void addToDictionary() {} + virtual bool canAddToDictionary() const { return false; } - virtual void addToIgnore() {} - virtual bool canAddToIgnore() const { return false; } + virtual void addToIgnore() {} + virtual bool canAddToIgnore() const { return false; } }; #endif // LLSPELLCHECKMENUHANDLER_H diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index c411aafb1a..888edd093e 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -1,31 +1,31 @@ -/** +/** * @file llspinctrl.cpp * @brief LLSpinCtrl base class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" - + #include "llspinctrl.h" #include "llgl.h" @@ -49,456 +49,456 @@ const U32 MAX_STRING_LENGTH = 255; static LLDefaultChildRegistry::Register<LLSpinCtrl> r2("spinner"); LLSpinCtrl::Params::Params() -: label_width("label_width"), - decimal_digits("decimal_digits"), - allow_text_entry("allow_text_entry", true), - allow_digits_only("allow_digits_only", false), - label_wrap("label_wrap", false), - text_enabled_color("text_enabled_color"), - text_disabled_color("text_disabled_color"), - up_button("up_button"), - down_button("down_button") +: label_width("label_width"), + decimal_digits("decimal_digits"), + allow_text_entry("allow_text_entry", true), + allow_digits_only("allow_digits_only", false), + label_wrap("label_wrap", false), + text_enabled_color("text_enabled_color"), + text_disabled_color("text_disabled_color"), + up_button("up_button"), + down_button("down_button") {} LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p) -: LLF32UICtrl(p), - mLabelBox(NULL), - mbHasBeenSet( FALSE ), - mPrecision(p.decimal_digits), - mTextEnabledColor(p.text_enabled_color()), - mTextDisabledColor(p.text_disabled_color()) +: LLF32UICtrl(p), + mLabelBox(NULL), + mbHasBeenSet( FALSE ), + mPrecision(p.decimal_digits), + mTextEnabledColor(p.text_enabled_color()), + mTextDisabledColor(p.text_disabled_color()) { - static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0); - static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0); - static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0); - S32 centered_top = getRect().getHeight(); - S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height; - S32 btn_left = 0; - // reserve space for spinner - S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40)); - - // Label - if( !p.label().empty() ) - { - LLRect label_rect( 0, centered_top, label_width, centered_bottom ); - LLTextBox::Params params; - params.wrap(p.label_wrap); - params.name("SpinCtrl Label"); - params.rect(label_rect); - params.initial_value(p.label()); - if (p.font.isProvided()) - { - params.font(p.font); - } - mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mLabelBox); - - btn_left += label_rect.mRight + spinctrl_spacing; - } - - S32 btn_right = btn_left + spinctrl_btn_width; - - // Spin buttons - LLButton::Params up_button_params(p.up_button); - up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height); + static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0); + static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0); + static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0); + S32 centered_top = getRect().getHeight(); + S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height; + S32 btn_left = 0; + // reserve space for spinner + S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40)); + + // Label + if( !p.label().empty() ) + { + LLRect label_rect( 0, centered_top, label_width, centered_bottom ); + LLTextBox::Params params; + params.wrap(p.label_wrap); + params.name("SpinCtrl Label"); + params.rect(label_rect); + params.initial_value(p.label()); + if (p.font.isProvided()) + { + params.font(p.font); + } + mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mLabelBox); + + btn_left += label_rect.mRight + spinctrl_spacing; + } + + S32 btn_right = btn_left + spinctrl_btn_width; + + // Spin buttons + LLButton::Params up_button_params(p.up_button); + up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height); // Click callback starts within the button and ends within the button, // but LLSpinCtrl handles the action continuosly so subsribers needs to // be informed about click ending even if outside view, use 'up' instead - up_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2)); - up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2)); + up_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2)); + up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2)); up_button_params.commit_on_capture_lost = true; - mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params); - addChild(mUpBtn); + mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params); + addChild(mUpBtn); - LLButton::Params down_button_params(p.down_button); - down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height); - down_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2)); - down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2)); + LLButton::Params down_button_params(p.down_button); + down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height); + down_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2)); + down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2)); down_button_params.commit_on_capture_lost = true; - mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params); - addChild(mDownBtn); - - LLRect editor_rect( btn_right + 1, centered_top, getRect().getWidth(), centered_bottom ); - LLLineEditor::Params params; - params.name("SpinCtrl Editor"); - params.rect(editor_rect); - if (p.font.isProvided()) - { - params.font(p.font); - } - params.max_length.bytes(MAX_STRING_LENGTH); - params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2))); - - //*NOTE: allow entering of any chars for LLCalc, proper input will be evaluated on commit - - params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - mEditor = LLUICtrlFactory::create<LLLineEditor> (params); - mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); - mEditor->setFocusLostCallback( boost::bind(&LLSpinCtrl::onEditorLostFocus, _1, this )); - if (p.allow_digits_only) - { - mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); - } - //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus - // than when it doesn't. Instead, if you always have to double click to select all the text, - // it's easier to understand - //mEditor->setSelectAllonFocusReceived(TRUE); - mEditor->setSelectAllonCommit(FALSE); - addChild(mEditor); - - updateEditor(); - setUseBoundingRect( TRUE ); + mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params); + addChild(mDownBtn); + + LLRect editor_rect( btn_right + 1, centered_top, getRect().getWidth(), centered_bottom ); + LLLineEditor::Params params; + params.name("SpinCtrl Editor"); + params.rect(editor_rect); + if (p.font.isProvided()) + { + params.font(p.font); + } + params.max_length.bytes(MAX_STRING_LENGTH); + params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2))); + + //*NOTE: allow entering of any chars for LLCalc, proper input will be evaluated on commit + + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + mEditor = LLUICtrlFactory::create<LLLineEditor> (params); + mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this )); + mEditor->setFocusLostCallback( boost::bind(&LLSpinCtrl::onEditorLostFocus, _1, this )); + if (p.allow_digits_only) + { + mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); + } + //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus + // than when it doesn't. Instead, if you always have to double click to select all the text, + // it's easier to understand + //mEditor->setSelectAllonFocusReceived(TRUE); + mEditor->setSelectAllonCommit(FALSE); + addChild(mEditor); + + updateEditor(); + setUseBoundingRect( TRUE ); } F32 clamp_precision(F32 value, S32 decimal_precision) { - // pow() isn't perfect - - F64 clamped_value = value; - for (S32 i = 0; i < decimal_precision; i++) - clamped_value *= 10.0; - - clamped_value = ll_round(clamped_value); - - for (S32 i = 0; i < decimal_precision; i++) - clamped_value /= 10.0; - - return (F32)clamped_value; + // pow() isn't perfect + + F64 clamped_value = value; + for (S32 i = 0; i < decimal_precision; i++) + clamped_value *= 10.0; + + clamped_value = ll_round(clamped_value); + + for (S32 i = 0; i < decimal_precision; i++) + clamped_value /= 10.0; + + return (F32)clamped_value; } void LLSpinCtrl::onUpBtn( const LLSD& data ) { - if( getEnabled() ) - { - std::string text = mEditor->getText(); - if( LLLineEditor::postvalidateFloat( text ) ) - { - - LLLocale locale(LLLocale::USER_LOCALE); - F32 cur_val = (F32) atof(text.c_str()); - - // use getValue()/setValue() to force reload from/to control - F32 val = cur_val + mIncrement; - val = clamp_precision(val, mPrecision); - val = llmin( val, mMaxValue ); - if (val < mMinValue) val = mMinValue; - if (val > mMaxValue) val = mMaxValue; - - F32 saved_val = (F32)getValue().asReal(); - setValue(val); - if( mValidateSignal && !(*mValidateSignal)( this, val ) ) - { - setValue( saved_val ); - reportInvalidData(); - updateEditor(); - return; - } - - updateEditor(); - onCommit(); - } - } + if( getEnabled() ) + { + std::string text = mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + + LLLocale locale(LLLocale::USER_LOCALE); + F32 cur_val = (F32) atof(text.c_str()); + + // use getValue()/setValue() to force reload from/to control + F32 val = cur_val + mIncrement; + val = clamp_precision(val, mPrecision); + val = llmin( val, mMaxValue ); + if (val < mMinValue) val = mMinValue; + if (val > mMaxValue) val = mMaxValue; + + F32 saved_val = (F32)getValue().asReal(); + setValue(val); + if( mValidateSignal && !(*mValidateSignal)( this, val ) ) + { + setValue( saved_val ); + reportInvalidData(); + updateEditor(); + return; + } + + updateEditor(); + onCommit(); + } + } } void LLSpinCtrl::onDownBtn( const LLSD& data ) { - if( getEnabled() ) - { - std::string text = mEditor->getText(); - if( LLLineEditor::postvalidateFloat( text ) ) - { - - LLLocale locale(LLLocale::USER_LOCALE); - F32 cur_val = (F32) atof(text.c_str()); - - F32 val = cur_val - mIncrement; - val = clamp_precision(val, mPrecision); - val = llmax( val, mMinValue ); - - if (val < mMinValue) val = mMinValue; - if (val > mMaxValue) val = mMaxValue; - - F32 saved_val = (F32)getValue().asReal(); - setValue(val); - if( mValidateSignal && !(*mValidateSignal)( this, val ) ) - { - setValue( saved_val ); - reportInvalidData(); - updateEditor(); - return; - } - - updateEditor(); - onCommit(); - } - } + if( getEnabled() ) + { + std::string text = mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + + LLLocale locale(LLLocale::USER_LOCALE); + F32 cur_val = (F32) atof(text.c_str()); + + F32 val = cur_val - mIncrement; + val = clamp_precision(val, mPrecision); + val = llmax( val, mMinValue ); + + if (val < mMinValue) val = mMinValue; + if (val > mMaxValue) val = mMaxValue; + + F32 saved_val = (F32)getValue().asReal(); + setValue(val); + if( mValidateSignal && !(*mValidateSignal)( this, val ) ) + { + setValue( saved_val ); + reportInvalidData(); + updateEditor(); + return; + } + + updateEditor(); + onCommit(); + } + } } // static void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) { - LLSpinCtrl* self = (LLSpinCtrl*) userdata; - llassert( caller == self->mEditor ); + LLSpinCtrl* self = (LLSpinCtrl*) userdata; + llassert( caller == self->mEditor ); - self->onFocusReceived(); + self->onFocusReceived(); } // static void LLSpinCtrl::onEditorLostFocus( LLFocusableElement* caller, void *userdata ) { - LLSpinCtrl* self = (LLSpinCtrl*) userdata; - llassert( caller == self->mEditor ); - - self->onFocusLost(); - - std::string text = self->mEditor->getText(); - - LLLocale locale(LLLocale::USER_LOCALE); - F32 val = (F32)atof(text.c_str()); - - F32 saved_val = self->getValueF32(); - if (saved_val != val && !self->mEditor->isDirty()) - { - // Editor was focused when value update arrived, string - // in editor is different from one in spin control. - // Since editor is not dirty, it won't commit, so either - // attempt to commit value from editor or revert to a more - // recent value from spin control - self->updateEditor(); - } + LLSpinCtrl* self = (LLSpinCtrl*) userdata; + llassert( caller == self->mEditor ); + + self->onFocusLost(); + + std::string text = self->mEditor->getText(); + + LLLocale locale(LLLocale::USER_LOCALE); + F32 val = (F32)atof(text.c_str()); + + F32 saved_val = self->getValueF32(); + if (saved_val != val && !self->mEditor->isDirty()) + { + // Editor was focused when value update arrived, string + // in editor is different from one in spin control. + // Since editor is not dirty, it won't commit, so either + // attempt to commit value from editor or revert to a more + // recent value from spin control + self->updateEditor(); + } } void LLSpinCtrl::setValue(const LLSD& value ) { - F32 v = (F32)value.asReal(); - if (getValueF32() != v || !mbHasBeenSet) - { - mbHasBeenSet = TRUE; + F32 v = (F32)value.asReal(); + if (getValueF32() != v || !mbHasBeenSet) + { + mbHasBeenSet = TRUE; LLF32UICtrl::setValue(value); - - if (!mEditor->hasFocus()) - { - updateEditor(); - } - } + + if (!mEditor->hasFocus()) + { + updateEditor(); + } + } } //no matter if Editor has the focus, update the value void LLSpinCtrl::forceSetValue(const LLSD& value ) { - F32 v = (F32)value.asReal(); - if (getValueF32() != v || !mbHasBeenSet) - { - mbHasBeenSet = TRUE; + F32 v = (F32)value.asReal(); + if (getValueF32() != v || !mbHasBeenSet) + { + mbHasBeenSet = TRUE; LLF32UICtrl::setValue(value); - - updateEditor(); - mEditor->resetScrollPosition(); - } + + updateEditor(); + mEditor->resetScrollPosition(); + } } void LLSpinCtrl::clear() { - setValue(mMinValue); - mEditor->clear(); - mbHasBeenSet = FALSE; + setValue(mMinValue); + mEditor->clear(); + mbHasBeenSet = FALSE; } void LLSpinCtrl::updateLabelColor() { - if( mLabelBox ) - { - mLabelBox->setColor( getEnabled() ? mTextEnabledColor.get() : mTextDisabledColor.get() ); - } + if( mLabelBox ) + { + mLabelBox->setColor( getEnabled() ? mTextEnabledColor.get() : mTextDisabledColor.get() ); + } } void LLSpinCtrl::updateEditor() { - LLLocale locale(LLLocale::USER_LOCALE); + LLLocale locale(LLLocale::USER_LOCALE); - // Don't display very small negative valu es as -0.000 - F32 displayed_value = clamp_precision((F32)getValue().asReal(), mPrecision); + // Don't display very small negative valu es as -0.000 + F32 displayed_value = clamp_precision((F32)getValue().asReal(), mPrecision); -// if( S32( displayed_value * pow( 10, mPrecision ) ) == 0 ) -// { -// displayed_value = 0.f; -// } +// if( S32( displayed_value * pow( 10, mPrecision ) ) == 0 ) +// { +// displayed_value = 0.f; +// } - std::string format = llformat("%%.%df", mPrecision); - std::string text = llformat(format.c_str(), displayed_value); - mEditor->setText( text ); + std::string format = llformat("%%.%df", mPrecision); + std::string text = llformat(format.c_str(), displayed_value); + mEditor->setText( text ); } void LLSpinCtrl::onEditorCommit( const LLSD& data ) { - BOOL success = FALSE; - - if( mEditor->evaluateFloat() ) - { - std::string text = mEditor->getText(); - - LLLocale locale(LLLocale::USER_LOCALE); - F32 val = (F32) atof(text.c_str()); - - if (val < mMinValue) val = mMinValue; - if (val > mMaxValue) val = mMaxValue; - - F32 saved_val = getValueF32(); - setValue(val); - if( !mValidateSignal || (*mValidateSignal)( this, val ) ) - { - success = TRUE; - onCommit(); - } - else - { - setValue(saved_val); - } - } - updateEditor(); - - if( success ) - { - // We commited and clamped value - // try to display as much as possible - mEditor->resetScrollPosition(); - } - else - { - reportInvalidData(); - } + BOOL success = FALSE; + + if( mEditor->evaluateFloat() ) + { + std::string text = mEditor->getText(); + + LLLocale locale(LLLocale::USER_LOCALE); + F32 val = (F32) atof(text.c_str()); + + if (val < mMinValue) val = mMinValue; + if (val > mMaxValue) val = mMaxValue; + + F32 saved_val = getValueF32(); + setValue(val); + if( !mValidateSignal || (*mValidateSignal)( this, val ) ) + { + success = TRUE; + onCommit(); + } + else + { + setValue(saved_val); + } + } + updateEditor(); + + if( success ) + { + // We commited and clamped value + // try to display as much as possible + mEditor->resetScrollPosition(); + } + else + { + reportInvalidData(); + } } void LLSpinCtrl::forceEditorCommit() { - onEditorCommit( LLSD() ); + onEditorCommit( LLSD() ); } void LLSpinCtrl::setFocus(BOOL b) { - LLUICtrl::setFocus( b ); - mEditor->setFocus( b ); + LLUICtrl::setFocus( b ); + mEditor->setFocus( b ); } void LLSpinCtrl::setEnabled(BOOL b) { - LLView::setEnabled( b ); - mEditor->setEnabled( b ); - updateLabelColor(); + LLView::setEnabled( b ); + mEditor->setEnabled( b ); + updateLabelColor(); } void LLSpinCtrl::setTentative(BOOL b) { - mEditor->setTentative(b); - LLUICtrl::setTentative(b); + mEditor->setTentative(b); + LLUICtrl::setTentative(b); } BOOL LLSpinCtrl::isMouseHeldDown() const { - return - mDownBtn->hasMouseCapture() - || mUpBtn->hasMouseCapture(); + return + mDownBtn->hasMouseCapture() + || mUpBtn->hasMouseCapture(); } void LLSpinCtrl::onCommit() { - setTentative(FALSE); - setControlValue(getValueF32()); - LLF32UICtrl::onCommit(); + setTentative(FALSE); + setControlValue(getValueF32()); + LLF32UICtrl::onCommit(); } void LLSpinCtrl::setPrecision(S32 precision) { - if (precision < 0 || precision > 10) - { - LL_ERRS() << "LLSpinCtrl::setPrecision - precision out of range" << LL_ENDL; - return; - } - - mPrecision = precision; - updateEditor(); + if (precision < 0 || precision > 10) + { + LL_ERRS() << "LLSpinCtrl::setPrecision - precision out of range" << LL_ENDL; + return; + } + + mPrecision = precision; + updateEditor(); } void LLSpinCtrl::setLabel(const LLStringExplicit& label) { - if (mLabelBox) - { - mLabelBox->setText(label); - } - else - { - LL_WARNS() << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << LL_ENDL; - } - updateLabelColor(); + if (mLabelBox) + { + mLabelBox->setText(label); + } + else + { + LL_WARNS() << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << LL_ENDL; + } + updateLabelColor(); } void LLSpinCtrl::setAllowEdit(BOOL allow_edit) { - mEditor->setEnabled(allow_edit); - mAllowEdit = allow_edit; + mEditor->setEnabled(allow_edit); + mAllowEdit = allow_edit; } void LLSpinCtrl::onTabInto() { - mEditor->onTabInto(); + mEditor->onTabInto(); LLF32UICtrl::onTabInto(); } void LLSpinCtrl::reportInvalidData() { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } BOOL LLSpinCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if( clicks > 0 ) - { - while( clicks-- ) - { - onDownBtn(getValue()); - } - } - else - while( clicks++ ) - { - onUpBtn(getValue()); - } - - return TRUE; + if( clicks > 0 ) + { + while( clicks-- ) + { + onDownBtn(getValue()); + } + } + else + while( clicks++ ) + { + onUpBtn(getValue()); + } + + return TRUE; } BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask) { - if (mEditor->hasFocus()) - { - if(key == KEY_ESCAPE) - { - // text editors don't support revert normally (due to user confusion) - // but not allowing revert on a spinner seems dangerous - updateEditor(); - mEditor->resetScrollPosition(); - mEditor->setFocus(FALSE); - return TRUE; - } - if(key == KEY_UP) - { - onUpBtn(getValue()); - return TRUE; - } - if(key == KEY_DOWN) - { - onDownBtn(getValue()); - return TRUE; - } - } - return FALSE; + if (mEditor->hasFocus()) + { + if(key == KEY_ESCAPE) + { + // text editors don't support revert normally (due to user confusion) + // but not allowing revert on a spinner seems dangerous + updateEditor(); + mEditor->resetScrollPosition(); + mEditor->setFocus(FALSE); + return TRUE; + } + if(key == KEY_UP) + { + onUpBtn(getValue()); + return TRUE; + } + if(key == KEY_DOWN) + { + onDownBtn(getValue()); + return TRUE; + } + } + return FALSE; } diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index cab99c35bd..7eddc2ce4e 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -1,25 +1,25 @@ -/** +/** * @file llspinctrl.h * @brief Typical spinner with "up" and "down" arrow buttons. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,86 +39,86 @@ class LLSpinCtrl : public LLF32UICtrl { public: - struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> - { - Optional<S32> label_width; - Optional<U32> decimal_digits; - Optional<bool> allow_text_entry; - Optional<bool> allow_digits_only; - Optional<bool> label_wrap; - - Optional<LLUIColor> text_enabled_color; - Optional<LLUIColor> text_disabled_color; - - Optional<LLButton::Params> up_button; - Optional<LLButton::Params> down_button; - - Params(); - }; + struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params> + { + Optional<S32> label_width; + Optional<U32> decimal_digits; + Optional<bool> allow_text_entry; + Optional<bool> allow_digits_only; + Optional<bool> label_wrap; + + Optional<LLUIColor> text_enabled_color; + Optional<LLUIColor> text_disabled_color; + + Optional<LLButton::Params> up_button; + Optional<LLButton::Params> down_button; + + Params(); + }; protected: - LLSpinCtrl(const Params&); - friend class LLUICtrlFactory; + LLSpinCtrl(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLSpinCtrl() {} // Children all cleaned up by default view destructor. + virtual ~LLSpinCtrl() {} // Children all cleaned up by default view destructor. + + virtual void forceSetValue(const LLSD& value ) ; + virtual void setValue(const LLSD& value ); + F32 get() const { return getValueF32(); } + void set(F32 value) { setValue(value); mInitialValue = value; } - virtual void forceSetValue(const LLSD& value ) ; - virtual void setValue(const LLSD& value ); - F32 get() const { return getValueF32(); } - void set(F32 value) { setValue(value); mInitialValue = value; } + BOOL isMouseHeldDown() const; - BOOL isMouseHeldDown() const; + virtual void setEnabled( BOOL b ); + virtual void setFocus( BOOL b ); + virtual void clear(); + virtual BOOL isDirty() const { return( getValueF32() != mInitialValue ); } + virtual void resetDirty() { mInitialValue = getValueF32(); } - virtual void setEnabled( BOOL b ); - virtual void setFocus( BOOL b ); - virtual void clear(); - virtual BOOL isDirty() const { return( getValueF32() != mInitialValue ); } - virtual void resetDirty() { mInitialValue = getValueF32(); } + virtual void setPrecision(S32 precision); - virtual void setPrecision(S32 precision); + void setLabel(const LLStringExplicit& label); + void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } + void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor();} + void setAllowEdit(BOOL allow_edit); - void setLabel(const LLStringExplicit& label); - void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } - void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor();} - void setAllowEdit(BOOL allow_edit); + virtual void onTabInto(); - virtual void onTabInto(); + virtual void setTentative(BOOL b); // marks value as tentative + virtual void onCommit(); // mark not tentative, then commit - virtual void setTentative(BOOL b); // marks value as tentative - virtual void onCommit(); // mark not tentative, then commit + void forceEditorCommit(); // for commit on external button - void forceEditorCommit(); // for commit on external button + virtual BOOL handleScrollWheel(S32 x,S32 y,S32 clicks); + virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleScrollWheel(S32 x,S32 y,S32 clicks); - virtual BOOL handleKeyHere(KEY key, MASK mask); + void onEditorCommit(const LLSD& data); + static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); + static void onEditorLostFocus(LLFocusableElement* caller, void *userdata); + static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); - void onEditorCommit(const LLSD& data); - static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); - static void onEditorLostFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); + void onUpBtn(const LLSD& data); + void onDownBtn(const LLSD& data); - void onUpBtn(const LLSD& data); - void onDownBtn(const LLSD& data); - - const LLColor4& getEnabledTextColor() const { return mTextEnabledColor.get(); } - const LLColor4& getDisabledTextColor() const { return mTextDisabledColor.get(); } + const LLColor4& getEnabledTextColor() const { return mTextEnabledColor.get(); } + const LLColor4& getDisabledTextColor() const { return mTextDisabledColor.get(); } private: - void updateLabelColor(); - void updateEditor(); - void reportInvalidData(); + void updateLabelColor(); + void updateEditor(); + void reportInvalidData(); - S32 mPrecision; - class LLTextBox* mLabelBox; + S32 mPrecision; + class LLTextBox* mLabelBox; - class LLLineEditor* mEditor; - LLUIColor mTextEnabledColor; - LLUIColor mTextDisabledColor; + class LLLineEditor* mEditor; + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; - class LLButton* mUpBtn; - class LLButton* mDownBtn; + class LLButton* mUpBtn; + class LLButton* mDownBtn; - BOOL mbHasBeenSet; - BOOL mAllowEdit; + BOOL mbHasBeenSet; + BOOL mAllowEdit; }; #endif // LL_LLSPINCTRL_H diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index fc3024c0de..5ea2eaabcd 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstatbar.cpp * @brief A little map of the world with network information * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,10 +43,10 @@ #include "lltrans.h" // rate at which to update display of value that is rapidly changing -const F32 MEAN_VALUE_UPDATE_TIME = 1.f / 4.f; +const F32 MEAN_VALUE_UPDATE_TIME = 1.f / 4.f; // time between value changes that qualifies as a "rapid change" -const F32Seconds RAPID_CHANGE_THRESHOLD(0.2f); -// maximum number of rapid changes in RAPID_CHANGE_WINDOW before switching over to displaying the mean +const F32Seconds RAPID_CHANGE_THRESHOLD(0.2f); +// maximum number of rapid changes in RAPID_CHANGE_WINDOW before switching over to displaying the mean // instead of latest value const S32 MAX_RAPID_CHANGES_PER_SEC = 10; // period of time over which to measure rapid changes @@ -54,663 +54,663 @@ const F32Seconds RAPID_CHANGE_WINDOW(1.f); F32 calc_tick_value(F32 min, F32 max) { - F32 range = max - min; - const S32 DIVISORS[] = {6, 8, 10, 4, 5}; - // try storing - S32 best_decimal_digit_count = S32_MAX; - S32 best_divisor = 10; - for (U32 divisor_idx = 0; divisor_idx < LL_ARRAY_SIZE(DIVISORS); divisor_idx++) - { - S32 divisor = DIVISORS[divisor_idx]; - F32 possible_tick_value = range / divisor; - S32 num_whole_digits = llceil(logf(llabs(min + possible_tick_value)) * OO_LN10); - for (S32 digit_count = -(num_whole_digits - 1); digit_count < 6; digit_count++) - { - F32 test_tick_value = min + (possible_tick_value * pow(10.0, digit_count)); - - if (is_approx_equal((F32)(S32)test_tick_value, test_tick_value)) - { - if (digit_count < best_decimal_digit_count) - { - best_decimal_digit_count = digit_count; - best_divisor = divisor; - } - break; - } - } - } - - return is_approx_equal(range, 0.f) ? 0.f : range / best_divisor; + F32 range = max - min; + const S32 DIVISORS[] = {6, 8, 10, 4, 5}; + // try storing + S32 best_decimal_digit_count = S32_MAX; + S32 best_divisor = 10; + for (U32 divisor_idx = 0; divisor_idx < LL_ARRAY_SIZE(DIVISORS); divisor_idx++) + { + S32 divisor = DIVISORS[divisor_idx]; + F32 possible_tick_value = range / divisor; + S32 num_whole_digits = llceil(logf(llabs(min + possible_tick_value)) * OO_LN10); + for (S32 digit_count = -(num_whole_digits - 1); digit_count < 6; digit_count++) + { + F32 test_tick_value = min + (possible_tick_value * pow(10.0, digit_count)); + + if (is_approx_equal((F32)(S32)test_tick_value, test_tick_value)) + { + if (digit_count < best_decimal_digit_count) + { + best_decimal_digit_count = digit_count; + best_divisor = divisor; + } + break; + } + } + } + + return is_approx_equal(range, 0.f) ? 0.f : range / best_divisor; } void calc_auto_scale_range(F32& min, F32& max, F32& tick) { - min = llmin(0.f, min, max); - max = llmax(0.f, min, max); - - const F32 RANGES[] = {0.f, 1.f, 1.5f, 2.f, 3.f, 5.f, 10.f}; - const F32 TICKS[] = {0.f, 0.25f, 0.5f, 1.f, 1.f, 1.f, 2.f }; - - const S32 num_digits_max = is_approx_equal(llabs(max), 0.f) - ? S32_MIN + 1 - : llceil(logf(llabs(max)) * OO_LN10); - const S32 num_digits_min = is_approx_equal(llabs(min), 0.f) - ? S32_MIN + 1 - : llceil(logf(llabs(min)) * OO_LN10); - - const S32 num_digits = llmax(num_digits_max, num_digits_min); - const F32 power_of_10 = pow(10.0, num_digits - 1); - const F32 starting_max = power_of_10 * ((max < 0.f) ? -1 : 1); - const F32 starting_min = power_of_10 * ((min < 0.f) ? -1 : 1); - - F32 cur_max = starting_max; - F32 cur_min = starting_min; - F32 out_max = max; - F32 out_min = min; - - F32 cur_tick_min = 0.f; - F32 cur_tick_max = 0.f; - - for (S32 range_idx = 0; range_idx < LL_ARRAY_SIZE(RANGES); range_idx++) - { - cur_max = starting_max * RANGES[range_idx]; - cur_min = starting_min * RANGES[range_idx]; - - if (min > 0.f && cur_min <= min) - { - out_min = cur_min; - cur_tick_min = TICKS[range_idx]; - } - if (max < 0.f && cur_max >= max) - { - out_max = cur_max; - cur_tick_max = TICKS[range_idx]; - } - } - - cur_max = starting_max; - cur_min = starting_min; - for (S32 range_idx = LL_ARRAY_SIZE(RANGES) - 1; range_idx >= 0; range_idx--) - { - cur_max = starting_max * RANGES[range_idx]; - cur_min = starting_min * RANGES[range_idx]; - - if (min < 0.f && cur_min <= min) - { - out_min = cur_min; - cur_tick_min = TICKS[range_idx]; - } - if (max > 0.f && cur_max >= max) - { - out_max = cur_max; - cur_tick_max = TICKS[range_idx]; - } - } - - tick = power_of_10 * llmax(cur_tick_min, cur_tick_max); - min = out_min; - max = out_max; + min = llmin(0.f, min, max); + max = llmax(0.f, min, max); + + const F32 RANGES[] = {0.f, 1.f, 1.5f, 2.f, 3.f, 5.f, 10.f}; + const F32 TICKS[] = {0.f, 0.25f, 0.5f, 1.f, 1.f, 1.f, 2.f }; + + const S32 num_digits_max = is_approx_equal(llabs(max), 0.f) + ? S32_MIN + 1 + : llceil(logf(llabs(max)) * OO_LN10); + const S32 num_digits_min = is_approx_equal(llabs(min), 0.f) + ? S32_MIN + 1 + : llceil(logf(llabs(min)) * OO_LN10); + + const S32 num_digits = llmax(num_digits_max, num_digits_min); + const F32 power_of_10 = pow(10.0, num_digits - 1); + const F32 starting_max = power_of_10 * ((max < 0.f) ? -1 : 1); + const F32 starting_min = power_of_10 * ((min < 0.f) ? -1 : 1); + + F32 cur_max = starting_max; + F32 cur_min = starting_min; + F32 out_max = max; + F32 out_min = min; + + F32 cur_tick_min = 0.f; + F32 cur_tick_max = 0.f; + + for (S32 range_idx = 0; range_idx < LL_ARRAY_SIZE(RANGES); range_idx++) + { + cur_max = starting_max * RANGES[range_idx]; + cur_min = starting_min * RANGES[range_idx]; + + if (min > 0.f && cur_min <= min) + { + out_min = cur_min; + cur_tick_min = TICKS[range_idx]; + } + if (max < 0.f && cur_max >= max) + { + out_max = cur_max; + cur_tick_max = TICKS[range_idx]; + } + } + + cur_max = starting_max; + cur_min = starting_min; + for (S32 range_idx = LL_ARRAY_SIZE(RANGES) - 1; range_idx >= 0; range_idx--) + { + cur_max = starting_max * RANGES[range_idx]; + cur_min = starting_min * RANGES[range_idx]; + + if (min < 0.f && cur_min <= min) + { + out_min = cur_min; + cur_tick_min = TICKS[range_idx]; + } + if (max > 0.f && cur_max >= max) + { + out_max = cur_max; + cur_tick_max = TICKS[range_idx]; + } + } + + tick = power_of_10 * llmax(cur_tick_min, cur_tick_max); + min = out_min; + max = out_max; } LLStatBar::Params::Params() -: label("label"), - unit_label("unit_label"), - bar_min("bar_min", 0.f), - bar_max("bar_max", 0.f), - tick_spacing("tick_spacing", 0.f), - decimal_digits("decimal_digits", 3), - show_bar("show_bar", false), - show_median("show_median", false), - show_history("show_history", false), - scale_range("scale_range", true), - num_frames("num_frames", 200), - num_frames_short("num_frames_short", 20), - max_height("max_height", 100), - stat("stat"), - orientation("orientation", VERTICAL) +: label("label"), + unit_label("unit_label"), + bar_min("bar_min", 0.f), + bar_max("bar_max", 0.f), + tick_spacing("tick_spacing", 0.f), + decimal_digits("decimal_digits", 3), + show_bar("show_bar", false), + show_median("show_median", false), + show_history("show_history", false), + scale_range("scale_range", true), + num_frames("num_frames", 200), + num_frames_short("num_frames_short", 20), + max_height("max_height", 100), + stat("stat"), + orientation("orientation", VERTICAL) { - changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT); + changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT); } /////////////////////////////////////////////////////////////////////////////////// LLStatBar::LLStatBar(const Params& p) -: LLView(p), - mLabel(p.label), - mUnitLabel(p.unit_label), - mTargetMinBar(llmin(p.bar_min, p.bar_max)), - mTargetMaxBar(llmax(p.bar_max, p.bar_min)), - mCurMaxBar(p.bar_max), - mCurMinBar(0), - mDecimalDigits(p.decimal_digits), - mNumHistoryFrames(p.num_frames), - mNumShortHistoryFrames(p.num_frames_short), - mMaxHeight(p.max_height), - mDisplayBar(p.show_bar), - mShowMedian(p.show_median), - mDisplayHistory(p.show_history), - mOrientation(p.orientation), - mAutoScaleMax(!p.bar_max.isProvided()), - mAutoScaleMin(!p.bar_min.isProvided()), - mTickSpacing(p.tick_spacing), - mLastDisplayValue(0.f), - mStatType(STAT_NONE) +: LLView(p), + mLabel(p.label), + mUnitLabel(p.unit_label), + mTargetMinBar(llmin(p.bar_min, p.bar_max)), + mTargetMaxBar(llmax(p.bar_max, p.bar_min)), + mCurMaxBar(p.bar_max), + mCurMinBar(0), + mDecimalDigits(p.decimal_digits), + mNumHistoryFrames(p.num_frames), + mNumShortHistoryFrames(p.num_frames_short), + mMaxHeight(p.max_height), + mDisplayBar(p.show_bar), + mShowMedian(p.show_median), + mDisplayHistory(p.show_history), + mOrientation(p.orientation), + mAutoScaleMax(!p.bar_max.isProvided()), + mAutoScaleMin(!p.bar_min.isProvided()), + mTickSpacing(p.tick_spacing), + mLastDisplayValue(0.f), + mStatType(STAT_NONE) { - mFloatingTargetMinBar = mTargetMinBar; - mFloatingTargetMaxBar = mTargetMaxBar; + mFloatingTargetMinBar = mTargetMinBar; + mFloatingTargetMaxBar = mTargetMaxBar; - mStat.valid = NULL; - // tick value will be automatically calculated later - if (!p.tick_spacing.isProvided() && p.bar_min.isProvided() && p.bar_max.isProvided()) - { - mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); - } + mStat.valid = NULL; + // tick value will be automatically calculated later + if (!p.tick_spacing.isProvided() && p.bar_min.isProvided() && p.bar_max.isProvided()) + { + mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); + } - setStat(p.stat); + setStat(p.stat); } BOOL LLStatBar::handleHover(S32 x, S32 y, MASK mask) { - switch(mStatType) - { - case STAT_COUNT: - LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.countStatp->getDescription()).sticky_rect(calcScreenRect())); - break; - case STAT_EVENT: - LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.eventStatp->getDescription()).sticky_rect(calcScreenRect())); - break; - case STAT_SAMPLE: - LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.sampleStatp->getDescription()).sticky_rect(calcScreenRect())); - break; - default: - break; - } - return TRUE; + switch(mStatType) + { + case STAT_COUNT: + LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.countStatp->getDescription()).sticky_rect(calcScreenRect())); + break; + case STAT_EVENT: + LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.eventStatp->getDescription()).sticky_rect(calcScreenRect())); + break; + case STAT_SAMPLE: + LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.sampleStatp->getDescription()).sticky_rect(calcScreenRect())); + break; + default: + break; + } + return TRUE; } BOOL LLStatBar::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleMouseDown(x, y, mask); - if (!handled) - { - if (mDisplayBar) - { - if (mDisplayHistory || mOrientation == HORIZONTAL) - { - mDisplayBar = FALSE; - mDisplayHistory = FALSE; - } - else - { - mDisplayHistory = TRUE; - } - } - else - { - mDisplayBar = TRUE; - if (mOrientation == HORIZONTAL) - { - mDisplayHistory = TRUE; - } - } - LLView* parent = getParent(); - parent->reshape(parent->getRect().getWidth(), parent->getRect().getHeight(), FALSE); - } - return TRUE; + BOOL handled = LLView::handleMouseDown(x, y, mask); + if (!handled) + { + if (mDisplayBar) + { + if (mDisplayHistory || mOrientation == HORIZONTAL) + { + mDisplayBar = FALSE; + mDisplayHistory = FALSE; + } + else + { + mDisplayHistory = TRUE; + } + } + else + { + mDisplayBar = TRUE; + if (mOrientation == HORIZONTAL) + { + mDisplayHistory = TRUE; + } + } + LLView* parent = getParent(); + parent->reshape(parent->getRect().getWidth(), parent->getRect().getHeight(), FALSE); + } + return TRUE; } template<typename T> S32 calc_num_rapid_changes(LLTrace::PeriodicRecording& periodic_recording, const T& stat, const F32Seconds time_period) { - F32Seconds elapsed_time, - time_since_value_changed; - S32 num_rapid_changes = 0; - const F32Seconds RAPID_CHANGE_THRESHOLD = F32Seconds(0.3f); - F64 last_value = periodic_recording.getPrevRecording(1).getLastValue(stat); - - for (S32 i = 2; i < periodic_recording.getNumRecordedPeriods(); i++) - { - LLTrace::Recording& recording = periodic_recording.getPrevRecording(i); - F64 cur_value = recording.getLastValue(stat); - - if (last_value != cur_value) - { - if (time_since_value_changed < RAPID_CHANGE_THRESHOLD) num_rapid_changes++; - time_since_value_changed = (F32Seconds)0; - } - last_value = cur_value; - - elapsed_time += recording.getDuration(); - if (elapsed_time > time_period) break; - } - - return num_rapid_changes; + F32Seconds elapsed_time, + time_since_value_changed; + S32 num_rapid_changes = 0; + const F32Seconds RAPID_CHANGE_THRESHOLD = F32Seconds(0.3f); + F64 last_value = periodic_recording.getPrevRecording(1).getLastValue(stat); + + for (S32 i = 2; i < periodic_recording.getNumRecordedPeriods(); i++) + { + LLTrace::Recording& recording = periodic_recording.getPrevRecording(i); + F64 cur_value = recording.getLastValue(stat); + + if (last_value != cur_value) + { + if (time_since_value_changed < RAPID_CHANGE_THRESHOLD) num_rapid_changes++; + time_since_value_changed = (F32Seconds)0; + } + last_value = cur_value; + + elapsed_time += recording.getDuration(); + if (elapsed_time > time_period) break; + } + + return num_rapid_changes; } void LLStatBar::draw() { - LLLocalClipRect _(getLocalRect()); - - LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); - LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); - - std::string unit_label; - F32 current = 0, - min = 0, - max = 0, - mean = 0, - display_value = 0; - S32 num_frames = mDisplayHistory - ? mNumHistoryFrames - : mNumShortHistoryFrames; - S32 num_rapid_changes = 0; - S32 decimal_digits = mDecimalDigits; - - switch(mStatType) - { - case STAT_COUNT: - { - const LLTrace::StatType<LLTrace::CountAccumulator>& count_stat = *mStat.countStatp; - - unit_label = std::string(count_stat.getUnitLabel()) + "/s"; - current = last_frame_recording.getPerSec(count_stat); - min = frame_recording.getPeriodMinPerSec(count_stat, num_frames); - max = frame_recording.getPeriodMaxPerSec(count_stat, num_frames); - mean = frame_recording.getPeriodMeanPerSec(count_stat, num_frames); - if (mShowMedian) - { - display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames); - } - else - { - display_value = mean; - } - } - break; - case STAT_EVENT: - { - const LLTrace::StatType<LLTrace::EventAccumulator>& event_stat = *mStat.eventStatp; - - unit_label = mUnitLabel.empty() ? event_stat.getUnitLabel() : mUnitLabel; - current = last_frame_recording.getLastValue(event_stat); - min = frame_recording.getPeriodMin(event_stat, num_frames); - max = frame_recording.getPeriodMax(event_stat, num_frames); - mean = frame_recording.getPeriodMean(event_stat, num_frames); - display_value = mean; - } - break; - case STAT_SAMPLE: - { - const LLTrace::StatType<LLTrace::SampleAccumulator>& sample_stat = *mStat.sampleStatp; - - unit_label = mUnitLabel.empty() ? sample_stat.getUnitLabel() : mUnitLabel; - current = last_frame_recording.getLastValue(sample_stat); - min = frame_recording.getPeriodMin(sample_stat, num_frames); - max = frame_recording.getPeriodMax(sample_stat, num_frames); - mean = frame_recording.getPeriodMean(sample_stat, num_frames); - num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW); - - if (mShowMedian) - { - display_value = frame_recording.getPeriodMedian(sample_stat, num_frames); - } - else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) - { - display_value = mean; - } - else - { - display_value = current; - // always display current value, don't rate limit - mLastDisplayValue = current; - if (is_approx_equal((F32)(S32)display_value, display_value)) - { - decimal_digits = 0; - } - } - } - break; - default: - break; - } - - LLRect bar_rect; - if (mOrientation == HORIZONTAL) - { - bar_rect.mTop = llmax(5, getRect().getHeight() - 15); - bar_rect.mLeft = 0; - bar_rect.mRight = getRect().getWidth() - 40; - bar_rect.mBottom = llmin(bar_rect.mTop - 5, 0); - } - else // VERTICAL - { - bar_rect.mTop = llmax(5, getRect().getHeight() - 15); - bar_rect.mLeft = 0; - bar_rect.mRight = getRect().getWidth(); - bar_rect.mBottom = llmin(bar_rect.mTop - 5, 20); - } - - mCurMaxBar = LLSmoothInterpolation::lerp(mCurMaxBar, mTargetMaxBar, 0.05f); - mCurMinBar = LLSmoothInterpolation::lerp(mCurMinBar, mTargetMinBar, 0.05f); - - // rate limited updates - if (mLastDisplayValueTimer.getElapsedTimeF32() < MEAN_VALUE_UPDATE_TIME) - { - display_value = mLastDisplayValue; - } - else - { - mLastDisplayValueTimer.reset(); - } - drawLabelAndValue(display_value, unit_label, bar_rect, decimal_digits); - mLastDisplayValue = display_value; - - if (mDisplayBar && mStat.valid) - { - // Draw the tick marks. - LLGLSUIDefault gls_ui; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - F32 value_scale; - if (mCurMaxBar == mCurMinBar) - { - value_scale = 0.f; - } - else - { - value_scale = (mOrientation == HORIZONTAL) - ? (bar_rect.getHeight())/(mCurMaxBar - mCurMinBar) - : (bar_rect.getWidth())/(mCurMaxBar - mCurMinBar); - } - - drawTicks(min, max, value_scale, bar_rect); - - // draw background bar. - gl_rect_2d(bar_rect.mLeft, bar_rect.mTop, bar_rect.mRight, bar_rect.mBottom, LLColor4(0.f, 0.f, 0.f, 0.25f)); - - // draw values - if (!llisnan(display_value) && frame_recording.getNumRecordedPeriods() != 0) - { - // draw min and max - S32 begin = (S32) ((min - mCurMinBar) * value_scale); - - if (begin < 0) - { - begin = 0; - } - - S32 end = (S32) ((max - mCurMinBar) * value_scale); - if (mOrientation == HORIZONTAL) - { - gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight, begin, LLColor4(1.f, 0.f, 0.f, 0.25f)); - } - else // VERTICAL - { - gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom, LLColor4(1.f, 0.f, 0.f, 0.25f)); - } - - F32 span = (mOrientation == HORIZONTAL) - ? (bar_rect.getWidth()) - : (bar_rect.getHeight()); - - if (mDisplayHistory && mStat.valid) - { - const S32 num_values = frame_recording.getNumRecordedPeriods() - 1; - F32 min_value = 0.f, - max_value = 0.f; - - gGL.color4f(1.f, 0.f, 0.f, 1.f); - gGL.begin( LLRender::QUADS ); - const S32 max_frame = llmin(num_frames, num_values); - U32 num_samples = 0; - for (S32 i = 1; i <= max_frame; i++) - { - F32 offset = ((F32)i / (F32)num_frames) * span; - LLTrace::Recording& recording = frame_recording.getPrevRecording(i); - - switch(mStatType) - { - case STAT_COUNT: - min_value = recording.getPerSec(*mStat.countStatp); - max_value = min_value; - num_samples = recording.getSampleCount(*mStat.countStatp); - break; - case STAT_EVENT: - min_value = recording.getMin(*mStat.eventStatp); - max_value = recording.getMax(*mStat.eventStatp); - num_samples = recording.getSampleCount(*mStat.eventStatp); - break; - case STAT_SAMPLE: - min_value = recording.getMin(*mStat.sampleStatp); - max_value = recording.getMax(*mStat.sampleStatp); - num_samples = recording.getSampleCount(*mStat.sampleStatp); - break; - default: - break; - } - - if (!num_samples) continue; - - F32 min = (min_value - mCurMinBar) * value_scale; - F32 max = llmax(min + 1, (max_value - mCurMinBar) * value_scale); - if (mOrientation == HORIZONTAL) - { - gGL.vertex2f((F32)bar_rect.mRight - offset, max); - gGL.vertex2f((F32)bar_rect.mRight - offset, min); - gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); - gGL.vertex2f((F32)bar_rect.mRight - offset - 1, max); - } - else - { - gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); - gGL.vertex2f(min, (F32)bar_rect.mBottom + offset); - gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); - gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1 ); - } - } - gGL.end(); - } - else - { - S32 begin = (S32) ((current - mCurMinBar) * value_scale) - 1; - S32 end = (S32) ((current - mCurMinBar) * value_scale) + 1; - // draw current - if (mOrientation == HORIZONTAL) - { - gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight, begin, LLColor4(1.f, 0.f, 0.f, 1.f)); - } - else - { - gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom, LLColor4(1.f, 0.f, 0.f, 1.f)); - } - } - - // draw mean bar - { - const S32 begin = (S32) ((mean - mCurMinBar) * value_scale) - 1; - const S32 end = (S32) ((mean - mCurMinBar) * value_scale) + 1; - if (mOrientation == HORIZONTAL) - { - gl_rect_2d(bar_rect.mLeft - 2, begin, bar_rect.mRight + 2, end, LLColor4(0.f, 1.f, 0.f, 1.f)); - } - else - { - gl_rect_2d(begin, bar_rect.mTop + 2, end, bar_rect.mBottom - 2, LLColor4(0.f, 1.f, 0.f, 1.f)); - } - } - } - } - - LLView::draw(); + LLLocalClipRect _(getLocalRect()); + + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); + + std::string unit_label; + F32 current = 0, + min = 0, + max = 0, + mean = 0, + display_value = 0; + S32 num_frames = mDisplayHistory + ? mNumHistoryFrames + : mNumShortHistoryFrames; + S32 num_rapid_changes = 0; + S32 decimal_digits = mDecimalDigits; + + switch(mStatType) + { + case STAT_COUNT: + { + const LLTrace::StatType<LLTrace::CountAccumulator>& count_stat = *mStat.countStatp; + + unit_label = std::string(count_stat.getUnitLabel()) + "/s"; + current = last_frame_recording.getPerSec(count_stat); + min = frame_recording.getPeriodMinPerSec(count_stat, num_frames); + max = frame_recording.getPeriodMaxPerSec(count_stat, num_frames); + mean = frame_recording.getPeriodMeanPerSec(count_stat, num_frames); + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames); + } + else + { + display_value = mean; + } + } + break; + case STAT_EVENT: + { + const LLTrace::StatType<LLTrace::EventAccumulator>& event_stat = *mStat.eventStatp; + + unit_label = mUnitLabel.empty() ? event_stat.getUnitLabel() : mUnitLabel; + current = last_frame_recording.getLastValue(event_stat); + min = frame_recording.getPeriodMin(event_stat, num_frames); + max = frame_recording.getPeriodMax(event_stat, num_frames); + mean = frame_recording.getPeriodMean(event_stat, num_frames); + display_value = mean; + } + break; + case STAT_SAMPLE: + { + const LLTrace::StatType<LLTrace::SampleAccumulator>& sample_stat = *mStat.sampleStatp; + + unit_label = mUnitLabel.empty() ? sample_stat.getUnitLabel() : mUnitLabel; + current = last_frame_recording.getLastValue(sample_stat); + min = frame_recording.getPeriodMin(sample_stat, num_frames); + max = frame_recording.getPeriodMax(sample_stat, num_frames); + mean = frame_recording.getPeriodMean(sample_stat, num_frames); + num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW); + + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedian(sample_stat, num_frames); + } + else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) + { + display_value = mean; + } + else + { + display_value = current; + // always display current value, don't rate limit + mLastDisplayValue = current; + if (is_approx_equal((F32)(S32)display_value, display_value)) + { + decimal_digits = 0; + } + } + } + break; + default: + break; + } + + LLRect bar_rect; + if (mOrientation == HORIZONTAL) + { + bar_rect.mTop = llmax(5, getRect().getHeight() - 15); + bar_rect.mLeft = 0; + bar_rect.mRight = getRect().getWidth() - 40; + bar_rect.mBottom = llmin(bar_rect.mTop - 5, 0); + } + else // VERTICAL + { + bar_rect.mTop = llmax(5, getRect().getHeight() - 15); + bar_rect.mLeft = 0; + bar_rect.mRight = getRect().getWidth(); + bar_rect.mBottom = llmin(bar_rect.mTop - 5, 20); + } + + mCurMaxBar = LLSmoothInterpolation::lerp(mCurMaxBar, mTargetMaxBar, 0.05f); + mCurMinBar = LLSmoothInterpolation::lerp(mCurMinBar, mTargetMinBar, 0.05f); + + // rate limited updates + if (mLastDisplayValueTimer.getElapsedTimeF32() < MEAN_VALUE_UPDATE_TIME) + { + display_value = mLastDisplayValue; + } + else + { + mLastDisplayValueTimer.reset(); + } + drawLabelAndValue(display_value, unit_label, bar_rect, decimal_digits); + mLastDisplayValue = display_value; + + if (mDisplayBar && mStat.valid) + { + // Draw the tick marks. + LLGLSUIDefault gls_ui; + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + F32 value_scale; + if (mCurMaxBar == mCurMinBar) + { + value_scale = 0.f; + } + else + { + value_scale = (mOrientation == HORIZONTAL) + ? (bar_rect.getHeight())/(mCurMaxBar - mCurMinBar) + : (bar_rect.getWidth())/(mCurMaxBar - mCurMinBar); + } + + drawTicks(min, max, value_scale, bar_rect); + + // draw background bar. + gl_rect_2d(bar_rect.mLeft, bar_rect.mTop, bar_rect.mRight, bar_rect.mBottom, LLColor4(0.f, 0.f, 0.f, 0.25f)); + + // draw values + if (!llisnan(display_value) && frame_recording.getNumRecordedPeriods() != 0) + { + // draw min and max + S32 begin = (S32) ((min - mCurMinBar) * value_scale); + + if (begin < 0) + { + begin = 0; + } + + S32 end = (S32) ((max - mCurMinBar) * value_scale); + if (mOrientation == HORIZONTAL) + { + gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight, begin, LLColor4(1.f, 0.f, 0.f, 0.25f)); + } + else // VERTICAL + { + gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom, LLColor4(1.f, 0.f, 0.f, 0.25f)); + } + + F32 span = (mOrientation == HORIZONTAL) + ? (bar_rect.getWidth()) + : (bar_rect.getHeight()); + + if (mDisplayHistory && mStat.valid) + { + const S32 num_values = frame_recording.getNumRecordedPeriods() - 1; + F32 min_value = 0.f, + max_value = 0.f; + + gGL.color4f(1.f, 0.f, 0.f, 1.f); + gGL.begin( LLRender::QUADS ); + const S32 max_frame = llmin(num_frames, num_values); + U32 num_samples = 0; + for (S32 i = 1; i <= max_frame; i++) + { + F32 offset = ((F32)i / (F32)num_frames) * span; + LLTrace::Recording& recording = frame_recording.getPrevRecording(i); + + switch(mStatType) + { + case STAT_COUNT: + min_value = recording.getPerSec(*mStat.countStatp); + max_value = min_value; + num_samples = recording.getSampleCount(*mStat.countStatp); + break; + case STAT_EVENT: + min_value = recording.getMin(*mStat.eventStatp); + max_value = recording.getMax(*mStat.eventStatp); + num_samples = recording.getSampleCount(*mStat.eventStatp); + break; + case STAT_SAMPLE: + min_value = recording.getMin(*mStat.sampleStatp); + max_value = recording.getMax(*mStat.sampleStatp); + num_samples = recording.getSampleCount(*mStat.sampleStatp); + break; + default: + break; + } + + if (!num_samples) continue; + + F32 min = (min_value - mCurMinBar) * value_scale; + F32 max = llmax(min + 1, (max_value - mCurMinBar) * value_scale); + if (mOrientation == HORIZONTAL) + { + gGL.vertex2f((F32)bar_rect.mRight - offset, max); + gGL.vertex2f((F32)bar_rect.mRight - offset, min); + gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); + gGL.vertex2f((F32)bar_rect.mRight - offset - 1, max); + } + else + { + gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); + gGL.vertex2f(min, (F32)bar_rect.mBottom + offset); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1 ); + } + } + gGL.end(); + } + else + { + S32 begin = (S32) ((current - mCurMinBar) * value_scale) - 1; + S32 end = (S32) ((current - mCurMinBar) * value_scale) + 1; + // draw current + if (mOrientation == HORIZONTAL) + { + gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight, begin, LLColor4(1.f, 0.f, 0.f, 1.f)); + } + else + { + gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom, LLColor4(1.f, 0.f, 0.f, 1.f)); + } + } + + // draw mean bar + { + const S32 begin = (S32) ((mean - mCurMinBar) * value_scale) - 1; + const S32 end = (S32) ((mean - mCurMinBar) * value_scale) + 1; + if (mOrientation == HORIZONTAL) + { + gl_rect_2d(bar_rect.mLeft - 2, begin, bar_rect.mRight + 2, end, LLColor4(0.f, 1.f, 0.f, 1.f)); + } + else + { + gl_rect_2d(begin, bar_rect.mTop + 2, end, bar_rect.mBottom - 2, LLColor4(0.f, 1.f, 0.f, 1.f)); + } + } + } + } + + LLView::draw(); } void LLStatBar::setStat(const std::string& stat_name) { - using namespace LLTrace; - - if (auto count_stat = StatType<CountAccumulator>::getInstance(stat_name)) - { - mStat.countStatp = count_stat.get(); - mStatType = STAT_COUNT; - } - else if (auto event_stat = StatType<EventAccumulator>::getInstance(stat_name)) - { - mStat.eventStatp = event_stat.get(); - mStatType = STAT_EVENT; - } - else if (auto sample_stat = StatType<SampleAccumulator>::getInstance(stat_name)) - { - mStat.sampleStatp = sample_stat.get(); - mStatType = STAT_SAMPLE; - } + using namespace LLTrace; + + if (auto count_stat = StatType<CountAccumulator>::getInstance(stat_name)) + { + mStat.countStatp = count_stat.get(); + mStatType = STAT_COUNT; + } + else if (auto event_stat = StatType<EventAccumulator>::getInstance(stat_name)) + { + mStat.eventStatp = event_stat.get(); + mStatType = STAT_EVENT; + } + else if (auto sample_stat = StatType<SampleAccumulator>::getInstance(stat_name)) + { + mStat.sampleStatp = sample_stat.get(); + mStatType = STAT_SAMPLE; + } } void LLStatBar::setRange(F32 bar_min, F32 bar_max) { - mTargetMinBar = llmin(bar_min, bar_max); - mTargetMaxBar = llmax(bar_min, bar_max); - mFloatingTargetMinBar = mTargetMinBar; - mFloatingTargetMaxBar = mTargetMaxBar; - mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); + mTargetMinBar = llmin(bar_min, bar_max); + mTargetMaxBar = llmax(bar_min, bar_max); + mFloatingTargetMinBar = mTargetMinBar; + mFloatingTargetMaxBar = mTargetMaxBar; + mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); } LLRect LLStatBar::getRequiredRect() { - LLRect rect; - - if (mDisplayBar) - { - if (mDisplayHistory) - { - rect.mTop = mMaxHeight; - } - else - { - rect.mTop = 40; - } - } - else - { - rect.mTop = 14; - } - return rect; + LLRect rect; + + if (mDisplayBar) + { + if (mDisplayHistory) + { + rect.mTop = mMaxHeight; + } + else + { + rect.mTop = 40; + } + } + else + { + rect.mTop = 14; + } + return rect; } void LLStatBar::drawLabelAndValue( F32 value, std::string &label, LLRect &bar_rect, S32 decimal_digits ) { - LLFontGL::getFontMonospace()->renderUTF8(mLabel, 0, 0, getRect().getHeight(), LLColor4(1.f, 1.f, 1.f, 1.f), - LLFontGL::LEFT, LLFontGL::TOP); - - std::string value_str = !llisnan(value) - ? llformat("%10.*f %s", decimal_digits, value, label.c_str()) - : LLTrans::getString("na"); - - // Draw the current value. - if (mOrientation == HORIZONTAL) - { - LLFontGL::getFontMonospace()->renderUTF8(value_str, 0, bar_rect.mRight, getRect().getHeight(), - LLColor4(1.f, 1.f, 1.f, 1.f), - LLFontGL::RIGHT, LLFontGL::TOP); - } - else - { - LLFontGL::getFontMonospace()->renderUTF8(value_str, 0, bar_rect.mRight, getRect().getHeight(), - LLColor4(1.f, 1.f, 1.f, 1.f), - LLFontGL::RIGHT, LLFontGL::TOP); - } + LLFontGL::getFontMonospace()->renderUTF8(mLabel, 0, 0, getRect().getHeight(), LLColor4(1.f, 1.f, 1.f, 1.f), + LLFontGL::LEFT, LLFontGL::TOP); + + std::string value_str = !llisnan(value) + ? llformat("%10.*f %s", decimal_digits, value, label.c_str()) + : LLTrans::getString("na"); + + // Draw the current value. + if (mOrientation == HORIZONTAL) + { + LLFontGL::getFontMonospace()->renderUTF8(value_str, 0, bar_rect.mRight, getRect().getHeight(), + LLColor4(1.f, 1.f, 1.f, 1.f), + LLFontGL::RIGHT, LLFontGL::TOP); + } + else + { + LLFontGL::getFontMonospace()->renderUTF8(value_str, 0, bar_rect.mRight, getRect().getHeight(), + LLColor4(1.f, 1.f, 1.f, 1.f), + LLFontGL::RIGHT, LLFontGL::TOP); + } } void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect ) { - if (!llisnan(min) && (mAutoScaleMax || mAutoScaleMin)) - { - F32 u = LLSmoothInterpolation::getInterpolant(10.f); - mFloatingTargetMinBar = llmin(min, lerp(mFloatingTargetMinBar, min, u)); - mFloatingTargetMaxBar = llmax(max, lerp(mFloatingTargetMaxBar, max, u)); - F32 range_min = mAutoScaleMin ? mFloatingTargetMinBar : mTargetMinBar; - F32 range_max = mAutoScaleMax ? mFloatingTargetMaxBar : mTargetMaxBar; - F32 tick_value = 0.f; - calc_auto_scale_range(range_min, range_max, tick_value); - if (mAutoScaleMin) { mTargetMinBar = range_min; } - if (mAutoScaleMax) { mTargetMaxBar = range_max; } - if (mAutoScaleMin && mAutoScaleMax) - { - mTickSpacing = tick_value; - } - else - { - mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); - } - } - - // start counting from actual min, not current, animating min, so that ticks don't float between numbers - // ensure ticks always hit 0 - S32 last_tick = S32_MIN; - S32 last_label = S32_MIN; - if (mTickSpacing > 0.f && value_scale > 0.f) - { - const S32 MIN_TICK_SPACING = mOrientation == HORIZONTAL ? 20 : 30; - const S32 MIN_LABEL_SPACING = mOrientation == HORIZONTAL ? 30 : 60; - const S32 TICK_LENGTH = 4; - const S32 TICK_WIDTH = 1; - - F32 start = mCurMinBar < 0.f - ? llceil(-mCurMinBar / mTickSpacing) * -mTickSpacing - : 0.f; - for (F32 tick_value = start; ;tick_value += mTickSpacing) - { - // clamp to S32_MAX / 2 to avoid floating point to integer overflow resulting in S32_MIN - const S32 tick_begin = llfloor(llmin((F32)(S32_MAX / 2), (tick_value - mCurMinBar)*value_scale)); - const S32 tick_end = tick_begin + TICK_WIDTH; - if (tick_begin < last_tick + MIN_TICK_SPACING) - { - continue; - } - last_tick = tick_begin; - - S32 decimal_digits = mDecimalDigits; - if (is_approx_equal((F32)(S32)tick_value, tick_value)) - { - decimal_digits = 0; - } - std::string tick_label = llformat("%.*f", decimal_digits, tick_value); - S32 tick_label_width = LLFontGL::getFontMonospace()->getWidth(tick_label); - if (mOrientation == HORIZONTAL) - { - if (tick_begin > last_label + MIN_LABEL_SPACING) - { - gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.25f)); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, bar_rect.mRight, tick_begin, - LLColor4(1.f, 1.f, 1.f, 0.5f), - LLFontGL::LEFT, LLFontGL::VCENTER); - last_label = tick_begin; - } - else - { - gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH/2, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.1f)); - } - } - else - { - if (tick_begin > last_label + MIN_LABEL_SPACING) - { - gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH, LLColor4(1.f, 1.f, 1.f, 0.25f)); - S32 label_pos = tick_begin - ll_round((F32)tick_label_width * ((F32)tick_begin / (F32)bar_rect.getWidth())); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, label_pos, bar_rect.mBottom - TICK_LENGTH, - LLColor4(1.f, 1.f, 1.f, 0.5f), - LLFontGL::LEFT, LLFontGL::TOP); - last_label = label_pos; - } - else - { - gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH/2, LLColor4(1.f, 1.f, 1.f, 0.1f)); - } - } - // always draw one tick value past tick_end, so we can see part of the text, if possible - if (tick_value > mCurMaxBar) - { - break; - } - } - } + if (!llisnan(min) && (mAutoScaleMax || mAutoScaleMin)) + { + F32 u = LLSmoothInterpolation::getInterpolant(10.f); + mFloatingTargetMinBar = llmin(min, lerp(mFloatingTargetMinBar, min, u)); + mFloatingTargetMaxBar = llmax(max, lerp(mFloatingTargetMaxBar, max, u)); + F32 range_min = mAutoScaleMin ? mFloatingTargetMinBar : mTargetMinBar; + F32 range_max = mAutoScaleMax ? mFloatingTargetMaxBar : mTargetMaxBar; + F32 tick_value = 0.f; + calc_auto_scale_range(range_min, range_max, tick_value); + if (mAutoScaleMin) { mTargetMinBar = range_min; } + if (mAutoScaleMax) { mTargetMaxBar = range_max; } + if (mAutoScaleMin && mAutoScaleMax) + { + mTickSpacing = tick_value; + } + else + { + mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar); + } + } + + // start counting from actual min, not current, animating min, so that ticks don't float between numbers + // ensure ticks always hit 0 + S32 last_tick = S32_MIN; + S32 last_label = S32_MIN; + if (mTickSpacing > 0.f && value_scale > 0.f) + { + const S32 MIN_TICK_SPACING = mOrientation == HORIZONTAL ? 20 : 30; + const S32 MIN_LABEL_SPACING = mOrientation == HORIZONTAL ? 30 : 60; + const S32 TICK_LENGTH = 4; + const S32 TICK_WIDTH = 1; + + F32 start = mCurMinBar < 0.f + ? llceil(-mCurMinBar / mTickSpacing) * -mTickSpacing + : 0.f; + for (F32 tick_value = start; ;tick_value += mTickSpacing) + { + // clamp to S32_MAX / 2 to avoid floating point to integer overflow resulting in S32_MIN + const S32 tick_begin = llfloor(llmin((F32)(S32_MAX / 2), (tick_value - mCurMinBar)*value_scale)); + const S32 tick_end = tick_begin + TICK_WIDTH; + if (tick_begin < last_tick + MIN_TICK_SPACING) + { + continue; + } + last_tick = tick_begin; + + S32 decimal_digits = mDecimalDigits; + if (is_approx_equal((F32)(S32)tick_value, tick_value)) + { + decimal_digits = 0; + } + std::string tick_label = llformat("%.*f", decimal_digits, tick_value); + S32 tick_label_width = LLFontGL::getFontMonospace()->getWidth(tick_label); + if (mOrientation == HORIZONTAL) + { + if (tick_begin > last_label + MIN_LABEL_SPACING) + { + gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.25f)); + LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, bar_rect.mRight, tick_begin, + LLColor4(1.f, 1.f, 1.f, 0.5f), + LLFontGL::LEFT, LLFontGL::VCENTER); + last_label = tick_begin; + } + else + { + gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH/2, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.1f)); + } + } + else + { + if (tick_begin > last_label + MIN_LABEL_SPACING) + { + gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH, LLColor4(1.f, 1.f, 1.f, 0.25f)); + S32 label_pos = tick_begin - ll_round((F32)tick_label_width * ((F32)tick_begin / (F32)bar_rect.getWidth())); + LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, label_pos, bar_rect.mBottom - TICK_LENGTH, + LLColor4(1.f, 1.f, 1.f, 0.5f), + LLFontGL::LEFT, LLFontGL::TOP); + last_label = label_pos; + } + else + { + gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH/2, LLColor4(1.f, 1.f, 1.f, 0.1f)); + } + } + // always draw one tick value past tick_end, so we can see part of the text, if possible + if (tick_value > mCurMaxBar) + { + break; + } + } + } } diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 384d0950a6..e398c41601 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -1,25 +1,25 @@ -/** +/** * @file llstatbar.h * @brief A little map of the world with network information * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,85 +35,85 @@ class LLStatBar : public LLView { public: - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Optional<std::string> label, - unit_label; + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Optional<std::string> label, + unit_label; + + Optional<F32> bar_min, + bar_max, + tick_spacing; - Optional<F32> bar_min, - bar_max, - tick_spacing; + Optional<bool> show_bar, + show_history, + scale_range, + show_median; // default is mean - Optional<bool> show_bar, - show_history, - scale_range, - show_median; // default is mean + Optional<S32> decimal_digits, + num_frames, + num_frames_short, + max_height; + Optional<std::string> stat; + Optional<EOrientation> orientation; - Optional<S32> decimal_digits, - num_frames, - num_frames_short, - max_height; - Optional<std::string> stat; - Optional<EOrientation> orientation; + Params(); + }; + LLStatBar(const Params&); - Params(); - }; - LLStatBar(const Params&); + virtual void draw(); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual void draw(); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); + void setStat(const std::string& stat_name); - void setStat(const std::string& stat_name); + void setRange(F32 bar_min, F32 bar_max); + void getRange(F32& bar_min, F32& bar_max) { bar_min = mTargetMinBar; bar_max = mTargetMaxBar; } - void setRange(F32 bar_min, F32 bar_max); - void getRange(F32& bar_min, F32& bar_max) { bar_min = mTargetMinBar; bar_max = mTargetMaxBar; } - - /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. + /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. private: - void drawLabelAndValue( F32 mean, std::string &unit_label, LLRect &bar_rect, S32 decimal_digits ); - void drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect ); - - F32 mTargetMinBar, - mTargetMaxBar, - mFloatingTargetMinBar, - mFloatingTargetMaxBar, - mCurMaxBar, - mCurMinBar, - mTickSpacing; - S32 mDecimalDigits, - mNumHistoryFrames, - mNumShortHistoryFrames; - S32 mMaxHeight; - EOrientation mOrientation; - F32 mLastDisplayValue; - LLFrameTimer mLastDisplayValueTimer; - - enum - { - STAT_NONE, - STAT_COUNT, - STAT_EVENT, - STAT_SAMPLE - } mStatType; - - union - { - void* valid; - const LLTrace::StatType<LLTrace::CountAccumulator>* countStatp; - const LLTrace::StatType<LLTrace::EventAccumulator>* eventStatp; - const LLTrace::StatType<LLTrace::SampleAccumulator>* sampleStatp; - } mStat; - - LLUIString mLabel; - std::string mUnitLabel; - - bool mDisplayBar, // Display the bar graph. - mDisplayHistory, - mShowMedian, - mAutoScaleMax, - mAutoScaleMin; + void drawLabelAndValue( F32 mean, std::string &unit_label, LLRect &bar_rect, S32 decimal_digits ); + void drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect ); + + F32 mTargetMinBar, + mTargetMaxBar, + mFloatingTargetMinBar, + mFloatingTargetMaxBar, + mCurMaxBar, + mCurMinBar, + mTickSpacing; + S32 mDecimalDigits, + mNumHistoryFrames, + mNumShortHistoryFrames; + S32 mMaxHeight; + EOrientation mOrientation; + F32 mLastDisplayValue; + LLFrameTimer mLastDisplayValueTimer; + + enum + { + STAT_NONE, + STAT_COUNT, + STAT_EVENT, + STAT_SAMPLE + } mStatType; + + union + { + void* valid; + const LLTrace::StatType<LLTrace::CountAccumulator>* countStatp; + const LLTrace::StatType<LLTrace::EventAccumulator>* eventStatp; + const LLTrace::StatType<LLTrace::SampleAccumulator>* sampleStatp; + } mStat; + + LLUIString mLabel; + std::string mUnitLabel; + + bool mDisplayBar, // Display the bar graph. + mDisplayHistory, + mShowMedian, + mAutoScaleMax, + mAutoScaleMin; }; #endif diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp index 3fe314e77a..bf08055554 100644 --- a/indra/llui/llstatgraph.cpp +++ b/indra/llui/llstatgraph.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstatgraph.cpp * @brief Simpler compact stat graph with tooltip * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,86 +41,86 @@ /////////////////////////////////////////////////////////////////////////////////// LLStatGraph::LLStatGraph(const Params& p) -: LLView(p), - mMin(p.min), - mMax(p.max), - mPerSec(p.per_sec), - mPrecision(p.precision), - mValue(p.value), - mUnits(p.units), - mNewStatFloatp(p.stat.count_stat_float) +: LLView(p), + mMin(p.min), + mMax(p.max), + mPerSec(p.per_sec), + mPrecision(p.precision), + mValue(p.value), + mUnits(p.units), + mNewStatFloatp(p.stat.count_stat_float) { - setToolTip(p.name()); - - for(LLInitParam::ParamIterator<ThresholdParams>::const_iterator it = p.thresholds.threshold.begin(), end_it = p.thresholds.threshold.end(); - it != end_it; - ++it) - { - mThresholds.push_back(Threshold(it->value(), it->color)); - } + setToolTip(p.name()); + + for(LLInitParam::ParamIterator<ThresholdParams>::const_iterator it = p.thresholds.threshold.begin(), end_it = p.thresholds.threshold.end(); + it != end_it; + ++it) + { + mThresholds.push_back(Threshold(it->value(), it->color)); + } } void LLStatGraph::draw() { - F32 range, frac; - range = mMax - mMin; - if (mNewStatFloatp) - { - LLTrace::Recording& recording = LLTrace::get_frame_recording().getLastRecording(); - - if (mPerSec) - { - mValue = recording.getPerSec(*mNewStatFloatp); - } - else - { - mValue = recording.getSum(*mNewStatFloatp); - } - } - - frac = (mValue - mMin) / range; - frac = llmax(0.f, frac); - frac = llmin(1.f, frac); - - if (mUpdateTimer.getElapsedTimeF32() > 0.5f) - { - std::string format_str; - std::string tmp_str; - format_str = llformat("%%s%%.%df%%s", mPrecision); - tmp_str = llformat(format_str.c_str(), mLabel.c_str(), mValue, mUnits.c_str()); - setToolTip(tmp_str); - - mUpdateTimer.reset(); - } - - LLColor4 color; - - threshold_vec_t::iterator it = std::lower_bound(mThresholds.begin(), mThresholds.end(), Threshold(mValue / mMax, LLUIColor())); - - if (it != mThresholds.begin()) - { - it--; - } - - color = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" ); - gGL.color4fv(color.mV); - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, TRUE); - - gGL.color4fv(LLColor4::black.mV); - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, FALSE); - - color = it->mColor; - gGL.color4fv(color.mV); - gl_rect_2d(1, ll_round(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE); + F32 range, frac; + range = mMax - mMin; + if (mNewStatFloatp) + { + LLTrace::Recording& recording = LLTrace::get_frame_recording().getLastRecording(); + + if (mPerSec) + { + mValue = recording.getPerSec(*mNewStatFloatp); + } + else + { + mValue = recording.getSum(*mNewStatFloatp); + } + } + + frac = (mValue - mMin) / range; + frac = llmax(0.f, frac); + frac = llmin(1.f, frac); + + if (mUpdateTimer.getElapsedTimeF32() > 0.5f) + { + std::string format_str; + std::string tmp_str; + format_str = llformat("%%s%%.%df%%s", mPrecision); + tmp_str = llformat(format_str.c_str(), mLabel.c_str(), mValue, mUnits.c_str()); + setToolTip(tmp_str); + + mUpdateTimer.reset(); + } + + LLColor4 color; + + threshold_vec_t::iterator it = std::lower_bound(mThresholds.begin(), mThresholds.end(), Threshold(mValue / mMax, LLUIColor())); + + if (it != mThresholds.begin()) + { + it--; + } + + color = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" ); + gGL.color4fv(color.mV); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, TRUE); + + gGL.color4fv(LLColor4::black.mV); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, FALSE); + + color = it->mColor; + gGL.color4fv(color.mV); + gl_rect_2d(1, ll_round(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE); } void LLStatGraph::setMin(const F32 min) { - mMin = min; + mMin = min; } void LLStatGraph::setMax(const F32 max) { - mMax = max; + mMax = max; } diff --git a/indra/llui/llstatgraph.h b/indra/llui/llstatgraph.h index ba7cfc5d10..679cd72cd4 100644 --- a/indra/llui/llstatgraph.h +++ b/indra/llui/llstatgraph.h @@ -1,25 +1,25 @@ -/** +/** * @file llstatgraph.h * @brief Simpler compact stat graph with tooltip * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,107 +35,107 @@ class LLStatGraph : public LLView { public: - struct ThresholdParams : public LLInitParam::Block<ThresholdParams> - { - Mandatory<F32> value; - Optional<LLUIColor> color; - - ThresholdParams() - : value("value"), - color("color", LLColor4::white) - {} - }; - - struct Thresholds : public LLInitParam::Block<Thresholds> - { - Multiple<ThresholdParams> threshold; - - Thresholds() - : threshold("threshold") - {} - }; - - struct StatParams : public LLInitParam::ChoiceBlock<StatParams> - { - Alternative<LLTrace::StatType<LLTrace::CountAccumulator>* > count_stat_float; - Alternative<LLTrace::StatType<LLTrace::EventAccumulator>* > event_stat_float; - Alternative<LLTrace::StatType<LLTrace::SampleAccumulator>* > sample_stat_float; - }; - - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Mandatory<StatParams> stat; - Optional<std::string> label, - units; - Optional<S32> precision; - Optional<F32> min, - max; - Optional<bool> per_sec; - Optional<F32> value; - - Optional<Thresholds> thresholds; - - Params() - : stat("stat"), - label("label"), - units("units"), - precision("precision", 0), - min("min", 0.f), - max("max", 125.f), - per_sec("per_sec", true), - value("value", 0.f), - thresholds("thresholds") - { - Thresholds _thresholds; - _thresholds.threshold.add(ThresholdParams().value(0.f).color(LLColor4::green)) - .add(ThresholdParams().value(0.33f).color(LLColor4::yellow)) - .add(ThresholdParams().value(0.5f).color(LLColor4::red)) - .add(ThresholdParams().value(0.75f).color(LLColor4::red)); - thresholds = _thresholds; - } - }; - LLStatGraph(const Params&); - - void setMin(const F32 min); - void setMax(const F32 max); - - virtual void draw(); - - /*virtual*/ void setValue(const LLSD& value); - + struct ThresholdParams : public LLInitParam::Block<ThresholdParams> + { + Mandatory<F32> value; + Optional<LLUIColor> color; + + ThresholdParams() + : value("value"), + color("color", LLColor4::white) + {} + }; + + struct Thresholds : public LLInitParam::Block<Thresholds> + { + Multiple<ThresholdParams> threshold; + + Thresholds() + : threshold("threshold") + {} + }; + + struct StatParams : public LLInitParam::ChoiceBlock<StatParams> + { + Alternative<LLTrace::StatType<LLTrace::CountAccumulator>* > count_stat_float; + Alternative<LLTrace::StatType<LLTrace::EventAccumulator>* > event_stat_float; + Alternative<LLTrace::StatType<LLTrace::SampleAccumulator>* > sample_stat_float; + }; + + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Mandatory<StatParams> stat; + Optional<std::string> label, + units; + Optional<S32> precision; + Optional<F32> min, + max; + Optional<bool> per_sec; + Optional<F32> value; + + Optional<Thresholds> thresholds; + + Params() + : stat("stat"), + label("label"), + units("units"), + precision("precision", 0), + min("min", 0.f), + max("max", 125.f), + per_sec("per_sec", true), + value("value", 0.f), + thresholds("thresholds") + { + Thresholds _thresholds; + _thresholds.threshold.add(ThresholdParams().value(0.f).color(LLColor4::green)) + .add(ThresholdParams().value(0.33f).color(LLColor4::yellow)) + .add(ThresholdParams().value(0.5f).color(LLColor4::red)) + .add(ThresholdParams().value(0.75f).color(LLColor4::red)); + thresholds = _thresholds; + } + }; + LLStatGraph(const Params&); + + void setMin(const F32 min); + void setMax(const F32 max); + + virtual void draw(); + + /*virtual*/ void setValue(const LLSD& value); + private: - LLTrace::StatType<LLTrace::CountAccumulator>* mNewStatFloatp; - - BOOL mPerSec; - - F32 mValue; - - F32 mMin; - F32 mMax; - LLFrameTimer mUpdateTimer; - std::string mLabel; - std::string mUnits; - S32 mPrecision; // Num of digits of precision after dot - - struct Threshold - { - Threshold(F32 value, const LLUIColor& color) - : mValue(value), - mColor(color) - {} - - F32 mValue; - LLUIColor mColor; - bool operator <(const Threshold& other) const - { - return mValue < other.mValue; - } - }; - typedef std::vector<Threshold> threshold_vec_t; - threshold_vec_t mThresholds; - //S32 mNumThresholds; - //F32 mThresholds[4]; - //LLColor4 mThresholdColors[4]; + LLTrace::StatType<LLTrace::CountAccumulator>* mNewStatFloatp; + + BOOL mPerSec; + + F32 mValue; + + F32 mMin; + F32 mMax; + LLFrameTimer mUpdateTimer; + std::string mLabel; + std::string mUnits; + S32 mPrecision; // Num of digits of precision after dot + + struct Threshold + { + Threshold(F32 value, const LLUIColor& color) + : mValue(value), + mColor(color) + {} + + F32 mValue; + LLUIColor mColor; + bool operator <(const Threshold& other) const + { + return mValue < other.mValue; + } + }; + typedef std::vector<Threshold> threshold_vec_t; + threshold_vec_t mThresholds; + //S32 mNumThresholds; + //F32 mThresholds[4]; + //LLColor4 mThresholdColors[4]; }; #endif // LL_LLSTATGRAPH_H diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp index 03f2fb7cc0..377474084d 100644 --- a/indra/llui/llstatview.cpp +++ b/indra/llui/llstatview.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstatview.cpp * @brief Container for all statistics info. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,25 +37,25 @@ #include "llstatbar.h" LLStatView::LLStatView(const LLStatView::Params& p) -: LLContainerView(p), - mSetting(p.setting) +: LLContainerView(p), + mSetting(p.setting) { - BOOL isopen = getDisplayChildren(); - if (mSetting.length() > 0) - { - isopen = LLUI::getInstance()->mSettingGroups["config"]->getBOOL(mSetting); - } - setDisplayChildren(isopen); + BOOL isopen = getDisplayChildren(); + if (mSetting.length() > 0) + { + isopen = LLUI::getInstance()->mSettingGroups["config"]->getBOOL(mSetting); + } + setDisplayChildren(isopen); } LLStatView::~LLStatView() { - // Children all cleaned up by default view destructor. - if (mSetting.length() > 0) - { - BOOL isopen = getDisplayChildren(); - LLUI::getInstance()->mSettingGroups["config"]->setBOOL(mSetting, isopen); - } + // Children all cleaned up by default view destructor. + if (mSetting.length() > 0) + { + BOOL isopen = getDisplayChildren(); + LLUI::getInstance()->mSettingGroups["config"]->setBOOL(mSetting, isopen); + } } static StatViewRegistry::Register<LLStatBar> r1("stat_bar"); diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h index 044f0a8679..b5187f886d 100644 --- a/indra/llui/llstatview.h +++ b/indra/llui/llstatview.h @@ -1,25 +1,25 @@ -/** +/** * @file llstatview.h * @brief Container for all statistics info. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,34 +36,34 @@ class LLStatBar; // widget registrars struct StatViewRegistry : public LLChildRegistry<StatViewRegistry> { - LLSINGLETON_EMPTY_CTOR(StatViewRegistry); + LLSINGLETON_EMPTY_CTOR(StatViewRegistry); }; class LLStatView : public LLContainerView { public: - struct Params : public LLInitParam::Block<Params, LLContainerView::Params> - { - Optional<std::string> setting; - Params() - : setting("setting") - { - changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); - changeDefault(show_label, true); - } - }; + struct Params : public LLInitParam::Block<Params, LLContainerView::Params> + { + Optional<std::string> setting; + Params() + : setting("setting") + { + changeDefault(follows.flags, FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); + changeDefault(show_label, true); + } + }; - // my valid children are stored in this registry - typedef StatViewRegistry child_registry_t; + // my valid children are stored in this registry + typedef StatViewRegistry child_registry_t; - ~LLStatView(); + ~LLStatView(); protected: - LLStatView(const Params&); - friend class LLUICtrlFactory; + LLStatView(const Params&); + friend class LLUICtrlFactory; protected: - const std::string mSetting; + const std::string mSetting; }; #endif // LL_STATVIEW_ diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index bb731f4f7e..a8c0aa8ad6 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstyle.cpp * @brief Text style class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,72 +33,72 @@ #include "llui.h" LLStyle::Params::Params() -: visible("visible", true), - drop_shadow("drop_shadow", LLFontGL::NO_SHADOW), - color("color", LLColor4::black), - readonly_color("readonly_color", LLColor4::black), - selected_color("selected_color", LLColor4::black), - font("font", LLFontGL::getFontMonospace()), - image("image"), - link_href("href"), - is_link("is_link") +: visible("visible", true), + drop_shadow("drop_shadow", LLFontGL::NO_SHADOW), + color("color", LLColor4::black), + readonly_color("readonly_color", LLColor4::black), + selected_color("selected_color", LLColor4::black), + font("font", LLFontGL::getFontMonospace()), + image("image"), + link_href("href"), + is_link("is_link") {} LLStyle::LLStyle(const LLStyle::Params& p) -: mVisible(p.visible), - mColor(p.color), - mReadOnlyColor(p.readonly_color), - mSelectedColor(p.selected_color), - mFont(p.font()), - mLink(p.link_href), - mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()), - mDropShadow(p.drop_shadow), - mImagep(p.image()) +: mVisible(p.visible), + mColor(p.color), + mReadOnlyColor(p.readonly_color), + mSelectedColor(p.selected_color), + mFont(p.font()), + mLink(p.link_href), + mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()), + mDropShadow(p.drop_shadow), + mImagep(p.image()) {} void LLStyle::setFont(const LLFontGL* font) { - mFont = font; + mFont = font; } const LLFontGL* LLStyle::getFont() const { - return mFont; + return mFont; } void LLStyle::setLinkHREF(const std::string& href) { - mLink = href; + mLink = href; } BOOL LLStyle::isLink() const { - return mIsLink; + return mIsLink; } BOOL LLStyle::isVisible() const { - return mVisible; + return mVisible; } void LLStyle::setVisible(BOOL is_visible) { - mVisible = is_visible; + mVisible = is_visible; } LLPointer<LLUIImage> LLStyle::getImage() const { - return mImagep; + return mImagep; } void LLStyle::setImage(const LLUUID& src) { - mImagep = LLUI::getUIImageByID(src); + mImagep = LLUI::getUIImageByID(src); } void LLStyle::setImage(const std::string& name) { - mImagep = LLUI::getUIImage(name); + mImagep = LLUI::getUIImage(name); } diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index 9f1eba79d8..2a60bd265e 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -1,25 +1,25 @@ -/** +/** * @file llstyle.h * @brief Text style class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,79 +37,79 @@ class LLFontGL; class LLStyle : public LLRefCount { public: - struct Params : public LLInitParam::Block<Params> - { - Optional<bool> visible; - Optional<LLFontGL::ShadowType> drop_shadow; - Optional<LLUIColor> color, - readonly_color, - selected_color; - Optional<const LLFontGL*> font; - Optional<LLUIImage*> image; - Optional<std::string> link_href; - Optional<bool> is_link; - Params(); - }; - LLStyle(const Params& p = Params()); + struct Params : public LLInitParam::Block<Params> + { + Optional<bool> visible; + Optional<LLFontGL::ShadowType> drop_shadow; + Optional<LLUIColor> color, + readonly_color, + selected_color; + Optional<const LLFontGL*> font; + Optional<LLUIImage*> image; + Optional<std::string> link_href; + Optional<bool> is_link; + Params(); + }; + LLStyle(const Params& p = Params()); public: - const LLUIColor& getColor() const { return mColor; } - void setColor(const LLUIColor &color) { mColor = color; } + const LLUIColor& getColor() const { return mColor; } + void setColor(const LLUIColor &color) { mColor = color; } - const LLUIColor& getReadOnlyColor() const { return mReadOnlyColor; } - void setReadOnlyColor(const LLUIColor& color) { mReadOnlyColor = color; } + const LLUIColor& getReadOnlyColor() const { return mReadOnlyColor; } + void setReadOnlyColor(const LLUIColor& color) { mReadOnlyColor = color; } - const LLUIColor& getSelectedColor() const { return mSelectedColor; } - void setSelectedColor(const LLUIColor& color) { mSelectedColor = color; } + const LLUIColor& getSelectedColor() const { return mSelectedColor; } + void setSelectedColor(const LLUIColor& color) { mSelectedColor = color; } - BOOL isVisible() const; - void setVisible(BOOL is_visible); + BOOL isVisible() const; + void setVisible(BOOL is_visible); - LLFontGL::ShadowType getShadowType() const { return mDropShadow; } + LLFontGL::ShadowType getShadowType() const { return mDropShadow; } - void setFont(const LLFontGL* font); - const LLFontGL* getFont() const; + void setFont(const LLFontGL* font); + const LLFontGL* getFont() const; - const std::string& getLinkHREF() const { return mLink; } - void setLinkHREF(const std::string& href); - BOOL isLink() const; + const std::string& getLinkHREF() const { return mLink; } + void setLinkHREF(const std::string& href); + BOOL isLink() const; - LLPointer<LLUIImage> getImage() const; - void setImage(const LLUUID& src); - void setImage(const std::string& name); + LLPointer<LLUIImage> getImage() const; + void setImage(const LLUUID& src); + void setImage(const std::string& name); - BOOL isImage() const { return mImagep.notNull(); } + BOOL isImage() const { return mImagep.notNull(); } - bool operator==(const LLStyle &rhs) const - { - return - mVisible == rhs.mVisible - && mColor == rhs.mColor - && mReadOnlyColor == rhs.mReadOnlyColor - && mSelectedColor == rhs.mSelectedColor - && mFont == rhs.mFont - && mLink == rhs.mLink - && mImagep == rhs.mImagep - && mDropShadow == rhs.mDropShadow; - } + bool operator==(const LLStyle &rhs) const + { + return + mVisible == rhs.mVisible + && mColor == rhs.mColor + && mReadOnlyColor == rhs.mReadOnlyColor + && mSelectedColor == rhs.mSelectedColor + && mFont == rhs.mFont + && mLink == rhs.mLink + && mImagep == rhs.mImagep + && mDropShadow == rhs.mDropShadow; + } - bool operator!=(const LLStyle& rhs) const { return !(*this == rhs); } + bool operator!=(const LLStyle& rhs) const { return !(*this == rhs); } -public: - LLFontGL::ShadowType mDropShadow; +public: + LLFontGL::ShadowType mDropShadow; protected: - ~LLStyle() { } + ~LLStyle() { } private: - BOOL mVisible; - LLUIColor mColor; - LLUIColor mReadOnlyColor; - LLUIColor mSelectedColor; - std::string mFontName; - const LLFontGL* mFont; - std::string mLink; - bool mIsLink; - LLPointer<LLUIImage> mImagep; + BOOL mVisible; + LLUIColor mColor; + LLUIColor mReadOnlyColor; + LLUIColor mSelectedColor; + std::string mFontName; + const LLFontGL* mFont; + std::string mLink; + bool mIsLink; + LLPointer<LLUIImage> mImagep; }; typedef LLPointer<LLStyle> LLStyleSP; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 6aeae0f291..78c4f3c03c 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltabcontainer.cpp * @brief LLTabContainer class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,9 +59,9 @@ const F32 SCROLL_DELAY_TIME = 0.5f; void LLTabContainer::TabPositions::declareValues() { - declare("top", LLTabContainer::TOP); - declare("bottom", LLTabContainer::BOTTOM); - declare("left", LLTabContainer::LEFT); + declare("top", LLTabContainer::TOP); + declare("bottom", LLTabContainer::BOTTOM); + declare("left", LLTabContainer::LEFT); } //---------------------------------------------------------------------------- @@ -70,25 +70,25 @@ void LLTabContainer::TabPositions::declareValues() class LLTabTuple { public: - LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL) - : - mTabContainer(c), - mTabPanel(p), - mButton(b), - mOldState(FALSE), - mPlaceholderText(placeholder), - mPadding(0), - mVisible(true) - {} - - LLTabContainer* mTabContainer; - LLPanel* mTabPanel; - LLButton* mButton; - BOOL mOldState; - LLTextBox* mPlaceholderText; - S32 mPadding; - - mutable bool mVisible; + LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL) + : + mTabContainer(c), + mTabPanel(p), + mButton(b), + mOldState(FALSE), + mPlaceholderText(placeholder), + mPadding(0), + mVisible(true) + {} + + LLTabContainer* mTabContainer; + LLPanel* mTabPanel; + LLButton* mButton; + BOOL mOldState; + LLTextBox* mPlaceholderText; + S32 mPadding; + + mutable bool mVisible; }; //---------------------------------------------------------------------------- @@ -101,1349 +101,1350 @@ public: 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; + 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) - {} - }; + Params() + : icon_ctrl_pad("icon_ctrl_pad", 1) + {} + }; protected: - friend class LLUICtrlFactory; + friend class LLUICtrlFactory; - LLCustomButtonIconCtrl(const Params& p) - : LLButton(p), - mIcon(NULL), - mIconAlignment(LLFontGL::HCENTER), - mIconCtrlPad(p.icon_ctrl_pad) - {} + 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(); - } - } - - LLIconCtrl* getIconCtrl() const - { - return mIcon; - } + 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(); + } + } + + LLIconCtrl* getIconCtrl() const + { + return mIcon; + } private: - LLIconCtrl* mIcon; - LLFontGL::HAlign mIconAlignment; - S32 mIconCtrlPad; + LLIconCtrl* mIcon; + LLFontGL::HAlign mIconAlignment; + S32 mIconCtrlPad; }; //============================================================================ struct LLPlaceHolderPanel : public LLPanel { - // create dummy param block to register with "placeholder" nane - struct Params : public LLPanel::Params{}; - LLPlaceHolderPanel(const Params& p) : LLPanel(p) - {} + // create dummy param block to register with "placeholder" nane + struct Params : public LLPanel::Params{}; + LLPlaceHolderPanel(const Params& p) : LLPanel(p) + {} }; static LLDefaultChildRegistry::Register<LLPlaceHolderPanel> r1("placeholder"); static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container"); LLTabContainer::TabParams::TabParams() -: tab_top_image_unselected("tab_top_image_unselected"), - tab_top_image_selected("tab_top_image_selected"), - tab_top_image_flash("tab_top_image_flash"), - tab_bottom_image_unselected("tab_bottom_image_unselected"), - tab_bottom_image_selected("tab_bottom_image_selected"), - tab_bottom_image_flash("tab_bottom_image_flash"), - tab_left_image_unselected("tab_left_image_unselected"), - tab_left_image_selected("tab_left_image_selected"), - tab_left_image_flash("tab_left_image_flash") +: tab_top_image_unselected("tab_top_image_unselected"), + tab_top_image_selected("tab_top_image_selected"), + tab_top_image_flash("tab_top_image_flash"), + tab_bottom_image_unselected("tab_bottom_image_unselected"), + tab_bottom_image_selected("tab_bottom_image_selected"), + tab_bottom_image_flash("tab_bottom_image_flash"), + tab_left_image_unselected("tab_left_image_unselected"), + tab_left_image_selected("tab_left_image_selected"), + tab_left_image_flash("tab_left_image_flash") {} LLTabContainer::Params::Params() -: tab_width("tab_width"), - tab_min_width("tab_min_width"), - tab_max_width("tab_max_width"), - tab_height("tab_height"), - label_pad_bottom("label_pad_bottom"), - label_pad_left("label_pad_left"), - tab_position("tab_position"), - hide_tabs("hide_tabs", false), - hide_scroll_arrows("hide_scroll_arrows", false), - tab_padding_right("tab_padding_right"), - first_tab("first_tab"), - middle_tab("middle_tab"), - last_tab("last_tab"), - use_custom_icon_ctrl("use_custom_icon_ctrl", false), - open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false), - enable_tabs_flashing("enable_tabs_flashing", false), - tabs_flashing_color("tabs_flashing_color"), - tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), - use_ellipses("use_ellipses"), - font_halign("halign") +: tab_width("tab_width"), + tab_min_width("tab_min_width"), + tab_max_width("tab_max_width"), + tab_height("tab_height"), + label_pad_bottom("label_pad_bottom"), + label_pad_left("label_pad_left"), + tab_position("tab_position"), + hide_tabs("hide_tabs", false), + hide_scroll_arrows("hide_scroll_arrows", false), + tab_padding_right("tab_padding_right"), + first_tab("first_tab"), + middle_tab("middle_tab"), + last_tab("last_tab"), + use_custom_icon_ctrl("use_custom_icon_ctrl", false), + open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false), + enable_tabs_flashing("enable_tabs_flashing", false), + tabs_flashing_color("tabs_flashing_color"), + tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), + use_ellipses("use_ellipses"), + font_halign("halign"), + use_tab_offset("use_tab_offset", false) {} LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) -: LLPanel(p), - mCurrentTabIdx(-1), - mTabsHidden(p.hide_tabs), - mScrolled(FALSE), - mScrollPos(0), - mScrollPosPixels(0), - mMaxScrollPos(0), - mTitleBox(NULL), - mTopBorderHeight(LLPANEL_BORDER_WIDTH), - mLockedTabCount(0), - mMinTabWidth(0), - mMaxTabWidth(p.tab_max_width), - mTabHeight(p.tab_height), - mLabelPadBottom(p.label_pad_bottom), - mLabelPadLeft(p.label_pad_left), - mPrevArrowBtn(NULL), - mNextArrowBtn(NULL), - mIsVertical( p.tab_position == LEFT ), - mHideScrollArrows(p.hide_scroll_arrows), - // Horizontal Specific - mJumpPrevArrowBtn(NULL), - mJumpNextArrowBtn(NULL), - mRightTabBtnOffset(p.tab_padding_right), - mTotalTabWidth(0), - mTabPosition(p.tab_position), - mFontHalign(p.font_halign), - mFont(p.font), - mFirstTabParams(p.first_tab), - mMiddleTabParams(p.middle_tab), - mLastTabParams(p.last_tab), - mCustomIconCtrlUsed(p.use_custom_icon_ctrl), - mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), - mTabIconCtrlPad(p.tab_icon_ctrl_pad), - mEnableTabsFlashing(p.enable_tabs_flashing), - mTabsFlashingColor(p.tabs_flashing_color), - mUseTabEllipses(p.use_ellipses) -{ - static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); - - mDragAndDropDelayTimer.stop(); - - if (p.tab_width.isProvided()) - { - mMinTabWidth = p.tab_width; - } - else if (!mIsVertical) - { - mMinTabWidth = p.tab_min_width; - } - else - { - // *HACK: support default min width for legacy vertical - // tab containers - mMinTabWidth = tabcntr_vert_tab_min_width; - } +: LLPanel(p), + mCurrentTabIdx(-1), + mTabsHidden(p.hide_tabs), + mScrolled(FALSE), + mScrollPos(0), + mScrollPosPixels(0), + mMaxScrollPos(0), + mTitleBox(NULL), + mTopBorderHeight(LLPANEL_BORDER_WIDTH), + mLockedTabCount(0), + mMinTabWidth(0), + mMaxTabWidth(p.tab_max_width), + mTabHeight(p.tab_height), + mLabelPadBottom(p.label_pad_bottom), + mLabelPadLeft(p.label_pad_left), + mPrevArrowBtn(NULL), + mNextArrowBtn(NULL), + mIsVertical( p.tab_position == LEFT ), + mHideScrollArrows(p.hide_scroll_arrows), + // Horizontal Specific + mJumpPrevArrowBtn(NULL), + mJumpNextArrowBtn(NULL), + mRightTabBtnOffset(p.tab_padding_right), + mTotalTabWidth(0), + mTabPosition(p.tab_position), + mFontHalign(p.font_halign), + mFont(p.font), + mFirstTabParams(p.first_tab), + mMiddleTabParams(p.middle_tab), + mLastTabParams(p.last_tab), + mCustomIconCtrlUsed(p.use_custom_icon_ctrl), + mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), + mTabIconCtrlPad(p.tab_icon_ctrl_pad), + mEnableTabsFlashing(p.enable_tabs_flashing), + mTabsFlashingColor(p.tabs_flashing_color), + mUseTabEllipses(p.use_ellipses), + mUseTabOffset(p.use_tab_offset) +{ + static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); + + mDragAndDropDelayTimer.stop(); + + if (p.tab_width.isProvided()) + { + mMinTabWidth = p.tab_width; + } + else if (!mIsVertical) + { + mMinTabWidth = p.tab_min_width; + } + else + { + // *HACK: support default min width for legacy vertical + // tab containers + mMinTabWidth = tabcntr_vert_tab_min_width; + } if (p.tabs_flashing_color.isProvided()) { mEnableTabsFlashing = true; } - initButtons( ); + initButtons( ); } LLTabContainer::~LLTabContainer() { - std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); - mTabList.clear(); + std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); + mTabList.clear(); } //virtual void LLTabContainer::setValue(const LLSD& value) { - selectTab((S32) value.asInteger()); + selectTab((S32) value.asInteger()); } //virtual void LLTabContainer::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLPanel::reshape( width, height, called_from_parent ); - updateMaxScrollPos(); + LLPanel::reshape( width, height, called_from_parent ); + updateMaxScrollPos(); } //virtual LLView* LLTabContainer::getChildView(const std::string& name, BOOL recurse) const { - tuple_list_t::const_iterator itor; - for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) - { - LLPanel *panel = (*itor)->mTabPanel; - if (panel->getName() == name) - { - return panel; - } - } - - if (recurse) - { - for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) - { - LLPanel *panel = (*itor)->mTabPanel; - LLView *child = panel->getChildView(name, recurse); - if (child) - { - return child; - } - } - } - return LLView::getChildView(name, recurse); + tuple_list_t::const_iterator itor; + for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) + { + LLPanel *panel = (*itor)->mTabPanel; + if (panel->getName() == name) + { + return panel; + } + } + + if (recurse) + { + for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) + { + LLPanel *panel = (*itor)->mTabPanel; + LLView *child = panel->getChildView(name, recurse); + if (child) + { + return child; + } + } + } + return LLView::getChildView(name, recurse); } //virtual LLView* LLTabContainer::findChildView(const std::string& name, BOOL recurse) const { - tuple_list_t::const_iterator itor; - for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) - { - LLPanel *panel = (*itor)->mTabPanel; - if (panel->getName() == name) - { - return panel; - } - } - - if (recurse) - { - for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) - { - LLPanel *panel = (*itor)->mTabPanel; - LLView *child = panel->findChildView(name, recurse); - if (child) - { - return child; - } - } - } - return LLView::findChildView(name, recurse); + tuple_list_t::const_iterator itor; + for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) + { + LLPanel *panel = (*itor)->mTabPanel; + if (panel->getName() == name) + { + return panel; + } + } + + if (recurse) + { + for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) + { + LLPanel *panel = (*itor)->mTabPanel; + LLView *child = panel->findChildView(name, recurse); + if (child) + { + return child; + } + } + } + return LLView::findChildView(name, recurse); } bool LLTabContainer::addChild(LLView* view, S32 tab_group) { - LLPanel* panelp = dynamic_cast<LLPanel*>(view); + LLPanel* panelp = dynamic_cast<LLPanel*>(view); - if (panelp) - { - addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL)); - return true; - } - else - { - return LLUICtrl::addChild(view, tab_group); - } + if (panelp) + { + addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL)); + return true; + } + else + { + return LLUICtrl::addChild(view, tab_group); + } } BOOL LLTabContainer::postBuild() { - selectFirstTab(); + selectFirstTab(); - return TRUE; + return TRUE; } // virtual void LLTabContainer::draw() { - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); - static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0); - static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); - static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0); - S32 target_pixel_scroll = 0; - S32 cur_scroll_pos = getScrollPos(); - if (cur_scroll_pos > 0) - { - if (mIsVertical) - { - target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad); - } - else - { - S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - if (cur_scroll_pos == 0) - { - break; - } - - if( (*iter)->mVisible ) - target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); - - cur_scroll_pos--; - } - - // Show part of the tab to the left of what is fully visible - target_pixel_scroll -= tabcntr_tab_partial_width; - // clamp so that rightmost tab never leaves right side of screen - target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll); - } - } - - setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLSmoothInterpolation::getInterpolant(0.08f))); - - BOOL has_scroll_arrows = !mHideScrollArrows && !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0)); - if (!mIsVertical) - { - mJumpPrevArrowBtn->setVisible( has_scroll_arrows ); - mJumpNextArrowBtn->setVisible( has_scroll_arrows ); - } - mPrevArrowBtn->setVisible( has_scroll_arrows ); - mNextArrowBtn->setVisible( has_scroll_arrows ); - - S32 left = 0, top = 0; - if (mIsVertical) - { - top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? tabcntrv_arrow_btn_size : 0); - top += getScrollPosPixels(); - } - else - { - // Set the leftmost position of the tab buttons. - left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (tabcntr_arrow_btn_size * 2) : tabcntr_tab_h_pad); - left -= getScrollPosPixels(); - } - - // Hide all the buttons - if (getTabsHidden()) - { - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); - } - } - - { - LLRect clip_rect = getLocalRect(); - clip_rect.mLeft+=(LLPANEL_BORDER_WIDTH + 2); - clip_rect.mRight-=(LLPANEL_BORDER_WIDTH + 2); - LLLocalClipRect clip(clip_rect); - LLPanel::draw(); - } - - // if tabs are hidden, don't draw them and leave them in the invisible state - if (!getTabsHidden()) - { - // Show all the buttons - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - } - - S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos(); - S32 idx = 0; - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - - if( !tuple->mVisible ) - { - tuple->mButton->setVisible( false ); - continue; - } - - tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0, - top ? top - tuple->mButton->getRect().mTop : 0 ); - if (top) top -= BTN_HEIGHT + tabcntrv_pad; - if (left) left += tuple->mButton->getRect().getWidth(); - - if (!mIsVertical) - { - if( idx < getScrollPos() ) - { - if( tuple->mButton->getFlashing() ) - { - mPrevArrowBtn->setFlashing( TRUE ); - } - } - else if( max_scroll_visible < idx ) - { - if( tuple->mButton->getFlashing() ) - { - mNextArrowBtn->setFlashing( TRUE ); - } - } - } - - idx++; - } - - - if( mIsVertical && has_scroll_arrows ) - { - // Redraw the arrows so that they appears on top. - gGL.pushUIMatrix(); - gGL.translateUI((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f); - mPrevArrowBtn->draw(); - gGL.popUIMatrix(); - - gGL.pushUIMatrix(); - gGL.translateUI((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f); - mNextArrowBtn->draw(); - gGL.popUIMatrix(); - } - } - - mPrevArrowBtn->setFlashing(false); - mNextArrowBtn->setFlashing(false); + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); + static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0); + static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); + static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0); + S32 target_pixel_scroll = 0; + S32 cur_scroll_pos = getScrollPos(); + if (cur_scroll_pos > 0) + { + if (mIsVertical) + { + target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad); + } + else + { + S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + if (cur_scroll_pos == 0) + { + break; + } + + if( (*iter)->mVisible ) + target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); + + cur_scroll_pos--; + } + + // Show part of the tab to the left of what is fully visible + target_pixel_scroll -= tabcntr_tab_partial_width; + // clamp so that rightmost tab never leaves right side of screen + target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll); + } + } + + setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLSmoothInterpolation::getInterpolant(0.08f))); + + BOOL has_scroll_arrows = !mHideScrollArrows && !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0)); + if (!mIsVertical) + { + mJumpPrevArrowBtn->setVisible( has_scroll_arrows ); + mJumpNextArrowBtn->setVisible( has_scroll_arrows ); + } + mPrevArrowBtn->setVisible( has_scroll_arrows ); + mNextArrowBtn->setVisible( has_scroll_arrows ); + + S32 left = 0, top = 0; + if (mIsVertical) + { + top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? tabcntrv_arrow_btn_size : 0); + top += getScrollPosPixels(); + } + else + { + // Set the leftmost position of the tab buttons. + left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (tabcntr_arrow_btn_size * 2) : tabcntr_tab_h_pad); + left -= getScrollPosPixels(); + } + + // Hide all the buttons + if (getTabsHidden()) + { + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( FALSE ); + } + } + + { + LLRect clip_rect = getLocalRect(); + clip_rect.mLeft+=(LLPANEL_BORDER_WIDTH + 2); + clip_rect.mRight-=(LLPANEL_BORDER_WIDTH + 2); + LLLocalClipRect clip(clip_rect); + LLPanel::draw(); + } + + // if tabs are hidden, don't draw them and leave them in the invisible state + if (!getTabsHidden()) + { + // Show all the buttons + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( TRUE ); + } + + S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos(); + S32 idx = 0; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + + if( !tuple->mVisible ) + { + tuple->mButton->setVisible( false ); + continue; + } + + tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0, + top ? top - tuple->mButton->getRect().mTop : 0 ); + if (top) top -= BTN_HEIGHT + tabcntrv_pad; + if (left) left += tuple->mButton->getRect().getWidth(); + + if (!mIsVertical) + { + if( idx < getScrollPos() ) + { + if( tuple->mButton->getFlashing() ) + { + mPrevArrowBtn->setFlashing( TRUE ); + } + } + else if( max_scroll_visible < idx ) + { + if( tuple->mButton->getFlashing() ) + { + mNextArrowBtn->setFlashing( TRUE ); + } + } + } + + idx++; + } + + + if( mIsVertical && has_scroll_arrows ) + { + // Redraw the arrows so that they appears on top. + gGL.pushUIMatrix(); + gGL.translateUI((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f); + mPrevArrowBtn->draw(); + gGL.popUIMatrix(); + + gGL.pushUIMatrix(); + gGL.translateUI((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f); + mNextArrowBtn->draw(); + gGL.popUIMatrix(); + } + } + + mPrevArrowBtn->setFlashing(false); + mNextArrowBtn->setFlashing(false); } // virtual BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) { - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - BOOL handled = FALSE; - BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); - - if (has_scroll_arrows) - { - if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; - handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask); - } - else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; - handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask); - } - else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mPrevArrowBtn->getRect().mBottom; - handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask); - } - else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mNextArrowBtn->getRect().mLeft; - S32 local_y = y - mNextArrowBtn->getRect().mBottom; - handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask); - } - } - if (!handled) - { - handled = LLPanel::handleMouseDown( x, y, mask ); - } - - S32 tab_count = getTabCount(); - if (tab_count > 0 && !getTabsHidden()) - { - LLTabTuple* firsttuple = getTab(0); - LLRect tab_rect; - if (mIsVertical) - { - tab_rect = LLRect(firsttuple->mButton->getRect().mLeft, - has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, - firsttuple->mButton->getRect().mRight, - has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); - } - else - { - tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, - firsttuple->mButton->getRect().mTop, - has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, - firsttuple->mButton->getRect().mBottom ); - } - if( tab_rect.pointInRect( x, y ) ) - { - S32 index = getCurrentPanelIndex(); - index = llclamp(index, 0, tab_count-1); - LLButton* tab_button = getTab(index)->mButton; - gFocusMgr.setMouseCapture(this); - tab_button->setFocus(TRUE); + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + BOOL handled = FALSE; + BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); + + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask); + } + else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask); + } + else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask); + } + else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mNextArrowBtn->getRect().mLeft; + S32 local_y = y - mNextArrowBtn->getRect().mBottom; + handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask); + } + } + if (!handled) + { + handled = LLPanel::handleMouseDown( x, y, mask ); + } + + S32 tab_count = getTabCount(); + if (tab_count > 0 && !getTabsHidden()) + { + LLTabTuple* firsttuple = getTab(0); + LLRect tab_rect; + if (mIsVertical) + { + tab_rect = LLRect(firsttuple->mButton->getRect().mLeft, + has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, + firsttuple->mButton->getRect().mRight, + has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); + } + else + { + tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, + firsttuple->mButton->getRect().mTop, + has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, + firsttuple->mButton->getRect().mBottom ); + } + if( tab_rect.pointInRect( x, y ) ) + { + S32 index = getCurrentPanelIndex(); + index = llclamp(index, 0, tab_count-1); + LLButton* tab_button = getTab(index)->mButton; + gFocusMgr.setMouseCapture(this); + tab_button->setFocus(TRUE); mMouseDownTimer.start(); - } - } - if (handled) { - // Note: May need to also capture local coords right here ? - LLViewerEventRecorder::instance().update_xui(getPathname( )); - } + } + } + if (handled) { + // Note: May need to also capture local coords right here ? + LLViewerEventRecorder::instance().update_xui(getPathname( )); + } - return handled; + return handled; } // virtual BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; - BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); - - if (has_scroll_arrows) - { - if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; - handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); - } - else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; - handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask); - } - else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mPrevArrowBtn->getRect().mBottom; - handled = mPrevArrowBtn->handleHover(local_x, local_y, mask); - } - else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mNextArrowBtn->getRect().mLeft; - S32 local_y = y - mNextArrowBtn->getRect().mBottom; - handled = mNextArrowBtn->handleHover(local_x, local_y, mask); - } - } - if (!handled) - { - handled = LLPanel::handleHover(x, y, mask); - } + BOOL handled = FALSE; + BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); + + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + handled = mPrevArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mNextArrowBtn->getRect().mLeft; + S32 local_y = y - mNextArrowBtn->getRect().mBottom; + handled = mNextArrowBtn->handleHover(local_x, local_y, mask); + } + } + if (!handled) + { + handled = LLPanel::handleHover(x, y, mask); + } F32 drag_delay = 0.25f; // filter out clicks from dragging if (mMouseDownTimer.getElapsedTimeF32() > drag_delay) { commitHoveredButton(x, y); } - return handled; + return handled; } // virtual BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) { - BOOL handled = FALSE; - BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); - - S32 local_x = x - getRect().mLeft; - S32 local_y = y - getRect().mBottom; - - if (has_scroll_arrows) - { - if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) - { - local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - local_y = y - mJumpPrevArrowBtn->getRect().mBottom; - handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask); - } - else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - local_x = x - mJumpNextArrowBtn->getRect().mLeft; - local_y = y - mJumpNextArrowBtn->getRect().mBottom; - handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask); - } - else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) - { - local_x = x - mPrevArrowBtn->getRect().mLeft; - local_y = y - mPrevArrowBtn->getRect().mBottom; - handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask); - } - else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) - { - local_x = x - mNextArrowBtn->getRect().mLeft; - local_y = y - mNextArrowBtn->getRect().mBottom; - handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask); - } - } - if (!handled) - { - handled = LLPanel::handleMouseUp( x, y, mask ); - } - - commitHoveredButton(x, y); + BOOL handled = FALSE; + BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0) && !getTabsHidden(); + + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; + + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask); + } + else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + local_x = x - mJumpNextArrowBtn->getRect().mLeft; + local_y = y - mJumpNextArrowBtn->getRect().mBottom; + handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask); + } + else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) + { + local_x = x - mPrevArrowBtn->getRect().mLeft; + local_y = y - mPrevArrowBtn->getRect().mBottom; + handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask); + } + else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) + { + local_x = x - mNextArrowBtn->getRect().mLeft; + local_y = y - mNextArrowBtn->getRect().mBottom; + handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask); + } + } + if (!handled) + { + handled = LLPanel::handleMouseUp( x, y, mask ); + } + + commitHoveredButton(x, y); mMouseDownTimer.stop(); - LLPanel* cur_panel = getCurrentPanel(); - if (hasMouseCapture()) - { - if (cur_panel) - { - if (!cur_panel->focusFirstItem(FALSE)) - { - // if nothing in the panel gets focus, make sure the new tab does - // otherwise the last tab might keep focus - getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE); - } - } - gFocusMgr.setMouseCapture(NULL); - } - if (handled) { - // Note: may need to capture local coords here - LLViewerEventRecorder::instance().update_xui(getPathname( )); - } - return handled; + LLPanel* cur_panel = getCurrentPanel(); + if (hasMouseCapture()) + { + if (cur_panel) + { + if (!cur_panel->focusFirstItem(FALSE)) + { + // if nothing in the panel gets focus, make sure the new tab does + // otherwise the last tab might keep focus + getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE); + } + } + gFocusMgr.setMouseCapture(NULL); + } + if (handled) { + // Note: may need to capture local coords here + LLViewerEventRecorder::instance().update_xui(getPathname( )); + } + return handled; } // virtual BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask) { - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - BOOL handled = LLPanel::handleToolTip( x, y, mask); - if (!handled && getTabCount() > 0 && !getTabsHidden()) - { - LLTabTuple* firsttuple = getTab(0); - - BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0); - LLRect clip; - if (mIsVertical) - { - clip = LLRect(firsttuple->mButton->getRect().mLeft, - has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, - firsttuple->mButton->getRect().mRight, - has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); - } - else - { - clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, - firsttuple->mButton->getRect().mTop, - has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, - firsttuple->mButton->getRect().mBottom ); - } - - if( clip.pointInRect( x, y ) ) - { - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLButton* tab_button = (*iter)->mButton; - if (!tab_button->getVisible()) continue; - S32 local_x = x - tab_button->getRect().mLeft; - S32 local_y = y - tab_button->getRect().mBottom; - handled = tab_button->handleToolTip(local_x, local_y, mask); - if( handled ) - { - break; - } - } - } - } - return handled; + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + BOOL handled = LLPanel::handleToolTip( x, y, mask); + if (!handled && getTabCount() > 0 && !getTabsHidden()) + { + LLTabTuple* firsttuple = getTab(0); + + BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0); + LLRect clip; + if (mIsVertical) + { + clip = LLRect(firsttuple->mButton->getRect().mLeft, + has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop, + firsttuple->mButton->getRect().mRight, + has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom ); + } + else + { + clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, + firsttuple->mButton->getRect().mTop, + has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, + firsttuple->mButton->getRect().mBottom ); + } + + if( clip.pointInRect( x, y ) ) + { + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLButton* tab_button = (*iter)->mButton; + if (!tab_button->getVisible()) continue; + S32 local_x = x - tab_button->getRect().mLeft; + S32 local_y = y - tab_button->getRect().mBottom; + handled = tab_button->handleToolTip(local_x, local_y, mask); + if( handled ) + { + break; + } + } + } + } + return handled; } // virtual BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask) { - BOOL handled = FALSE; - if (key == KEY_LEFT && mask == MASK_ALT) - { - selectPrevTab(); - handled = TRUE; - } - else if (key == KEY_RIGHT && mask == MASK_ALT) - { - selectNextTab(); - handled = TRUE; - } - - if (handled) - { - if (getCurrentPanel()) - { - getCurrentPanel()->setFocus(TRUE); - } - } - - if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel())) - { - // if child has focus, but not the current panel, focus is on a button - if (mIsVertical) - { - switch(key) - { - case KEY_UP: - selectPrevTab(); - handled = TRUE; - break; - case KEY_DOWN: - selectNextTab(); - handled = TRUE; - break; - case KEY_LEFT: - handled = TRUE; - break; - case KEY_RIGHT: - if (getTabPosition() == LEFT && getCurrentPanel()) - { - getCurrentPanel()->setFocus(TRUE); - } - handled = TRUE; - break; - default: - break; - } - } - else - { - switch(key) - { - case KEY_UP: - if (getTabPosition() == BOTTOM && getCurrentPanel()) - { - getCurrentPanel()->setFocus(TRUE); - } - handled = TRUE; - break; - case KEY_DOWN: - if (getTabPosition() == TOP && getCurrentPanel()) - { - getCurrentPanel()->setFocus(TRUE); - } - handled = TRUE; - break; - case KEY_LEFT: - selectPrevTab(); - handled = TRUE; - break; - case KEY_RIGHT: - selectNextTab(); - handled = TRUE; - break; - default: - break; - } - } - } - return handled; + BOOL handled = FALSE; + if (key == KEY_LEFT && mask == MASK_ALT) + { + selectPrevTab(); + handled = TRUE; + } + else if (key == KEY_RIGHT && mask == MASK_ALT) + { + selectNextTab(); + handled = TRUE; + } + + if (handled) + { + if (getCurrentPanel()) + { + getCurrentPanel()->setFocus(TRUE); + } + } + + if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel())) + { + // if child has focus, but not the current panel, focus is on a button + if (mIsVertical) + { + switch(key) + { + case KEY_UP: + selectPrevTab(); + handled = TRUE; + break; + case KEY_DOWN: + selectNextTab(); + handled = TRUE; + break; + case KEY_LEFT: + handled = TRUE; + break; + case KEY_RIGHT: + if (getTabPosition() == LEFT && getCurrentPanel()) + { + getCurrentPanel()->setFocus(TRUE); + } + handled = TRUE; + break; + default: + break; + } + } + else + { + switch(key) + { + case KEY_UP: + if (getTabPosition() == BOTTOM && getCurrentPanel()) + { + getCurrentPanel()->setFocus(TRUE); + } + handled = TRUE; + break; + case KEY_DOWN: + if (getTabPosition() == TOP && getCurrentPanel()) + { + getCurrentPanel()->setFocus(TRUE); + } + handled = TRUE; + break; + case KEY_LEFT: + selectPrevTab(); + handled = TRUE; + break; + case KEY_RIGHT: + selectNextTab(); + handled = TRUE; + break; + default: + break; + } + } + } + return handled; } // virtual -BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string &tooltip) -{ - BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0); - - if(mOpenTabsOnDragAndDrop && !getTabsHidden()) - { - // In that case, we'll open the hovered tab while dragging and dropping items. - // This allows for drilling through tabs. - if (mDragAndDropDelayTimer.getStarted()) - { - if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME) - { - if (has_scroll_arrows) - { - if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; - mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); - } - if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; - S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; - mJumpNextArrowBtn->handleHover(local_x, local_y, mask); - } - if (mPrevArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mPrevArrowBtn->getRect().mLeft; - S32 local_y = y - mPrevArrowBtn->getRect().mBottom; - mPrevArrowBtn->handleHover(local_x, local_y, mask); - } - else if (mNextArrowBtn->getRect().pointInRect(x, y)) - { - S32 local_x = x - mNextArrowBtn->getRect().mLeft; - S32 local_y = y - mNextArrowBtn->getRect().mBottom; - mNextArrowBtn->handleHover(local_x, local_y, mask); - } - } - - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - S32 local_x = x - tuple->mButton->getRect().mLeft; - S32 local_y = y - tuple->mButton->getRect().mBottom; - if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) - { - tuple->mButton->onCommit(); - } - } - // Stop the timer whether successful or not. Don't let it run forever. - mDragAndDropDelayTimer.stop(); - } - } - else - { - // Start a timer so we don't open tabs as soon as we hover on them - mDragAndDropDelayTimer.start(); - } - } - - return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); +BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string &tooltip) +{ + BOOL has_scroll_arrows = !mHideScrollArrows && (getMaxScrollPos() > 0); + + if(mOpenTabsOnDragAndDrop && !getTabsHidden()) + { + // In that case, we'll open the hovered tab while dragging and dropping items. + // This allows for drilling through tabs. + if (mDragAndDropDelayTimer.getStarted()) + { + if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME) + { + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); + } + if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + mJumpNextArrowBtn->handleHover(local_x, local_y, mask); + } + if (mPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + mPrevArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mNextArrowBtn->getRect().mLeft; + S32 local_y = y - mNextArrowBtn->getRect().mBottom; + mNextArrowBtn->handleHover(local_x, local_y, mask); + } + } + + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( TRUE ); + S32 local_x = x - tuple->mButton->getRect().mLeft; + S32 local_y = y - tuple->mButton->getRect().mBottom; + if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) + { + tuple->mButton->onCommit(); + } + } + // Stop the timer whether successful or not. Don't let it run forever. + mDragAndDropDelayTimer.stop(); + } + } + else + { + // Start a timer so we don't open tabs as soon as we hover on them + mDragAndDropDelayTimer.start(); + } + } + + return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); } void LLTabContainer::addTabPanel(LLPanel* panelp) { - addTabPanel(TabPanelParams().panel(panelp)); + addTabPanel(TabPanelParams().panel(panelp)); } // function to update images void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos) { - if (tuple && tuple->mButton) - { - if (pos == LLTabContainer::TOP) - { - tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected)); - tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected)); - tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_top_image_flash)); - } - else if (pos == LLTabContainer::BOTTOM) - { - tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected)); - tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected)); - tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_bottom_image_flash)); - } - else if (pos == LLTabContainer::LEFT) - { - tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected)); - tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected)); - tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_left_image_flash)); - } - } + if (tuple && tuple->mButton) + { + if (pos == LLTabContainer::TOP) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_top_image_flash)); + } + else if (pos == LLTabContainer::BOTTOM) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_bottom_image_flash)); + } + else if (pos == LLTabContainer::LEFT) + { + tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected)); + tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected)); + tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_left_image_flash)); + } + } } void LLTabContainer::addTabPanel(const TabPanelParams& panel) { - LLPanel* child = panel.panel(); - - llassert(child); - if (!child) return; - - const std::string& label = panel.label.isProvided() - ? panel.label() - : panel.panel()->getLabel(); - BOOL select = panel.select_tab(); - S32 indent = panel.indent(); - BOOL placeholder = panel.is_placeholder; - eInsertionPoint insertion_point = panel.insert_at(); - - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0); - static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - if (child->getParent() == this) - { - // already a child of mine - return; - } - - // Store the original label for possible xml export. - child->setLabel(label); - std::string trimmed_label = label; - LLStringUtil::trim(trimmed_label); - - S32 button_width = mMinTabWidth; - if (!mIsVertical) - { - button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); - } - - // Tab panel - S32 tab_panel_top; - S32 tab_panel_bottom; - if (!getTabsHidden()) - { - if( getTabPosition() == LLTabContainer::TOP ) - { - S32 tab_height = mIsVertical ? BTN_HEIGHT : mTabHeight; - tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap); - tab_panel_bottom = LLPANEL_BORDER_WIDTH; - } - else - { - tab_panel_top = getRect().getHeight() - getTopBorderHeight(); - tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap); // Run to the edge, covering up the border - } - } - else - { - // Skip tab button space if tabs are invisible (EXT-576) - tab_panel_top = getRect().getHeight(); - tab_panel_bottom = LLPANEL_BORDER_WIDTH; - } - - LLRect tab_panel_rect; - if (!getTabsHidden() && mIsVertical) - { - tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, - getRect().getHeight() - LLPANEL_BORDER_WIDTH, - getRect().getWidth() - LLPANEL_BORDER_WIDTH, - LLPANEL_BORDER_WIDTH); - } - else - { - tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3, - tab_panel_top, - getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2, - tab_panel_bottom ); - } - child->setFollowsAll(); - child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom); - child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); - // add this child later - - child->setVisible( FALSE ); // Will be made visible when selected - - mTotalTabWidth += button_width; - - // Tab button - LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw(). - LLUIImage* tab_img = NULL; - LLUIImage* tab_selected_img = NULL; - S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel - - if (mIsVertical) - { - btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor - (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()), - mMinTabWidth, - BTN_HEIGHT); - } - else if( getTabPosition() == LLTabContainer::TOP ) - { - btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight); - tab_img = mMiddleTabParams.tab_top_image_unselected; - tab_selected_img = mMiddleTabParams.tab_top_image_selected; - } - else - { - btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight); - tab_img = mMiddleTabParams.tab_bottom_image_unselected; - tab_selected_img = mMiddleTabParams.tab_bottom_image_selected; - } - - 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) - { - btn_rect.translate(0, -6); // *TODO: make configurable - LLTextBox::Params params; - params.name(trimmed_label); - params.rect(btn_rect); - params.initial_value(trimmed_label); - params.font(mFont); - textbox = LLUICtrlFactory::create<LLTextBox> (params); - - LLButton::Params p; - p.name("placeholder"); - btn = LLUICtrlFactory::create<LLButton>(p); - } - else - { - LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params); - - p.rect(btn_rect); - p.font(mFont); - p.font_halign = mFontHalign; - p.label(trimmed_label); - p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); - if (indent) - { - p.pad_left(indent); - } - p.pad_bottom( mLabelPadBottom ); - p.scale_image(true); - p.tab_stop(false); - p.label_shadow(false); - p.follows.flags = FOLLOWS_LEFT; - - if (mIsVertical) - { - p.name("vtab_"+std::string(child->getName())); - p.image_unselected(mMiddleTabParams.tab_left_image_unselected); - p.image_selected(mMiddleTabParams.tab_left_image_selected); - p.follows.flags = p.follows.flags() | FOLLOWS_TOP; - } - else - { - p.name("htab_"+std::string(child->getName())); - p.visible(false); - p.image_unselected(tab_img); - p.image_selected(tab_selected_img); - p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM); - // Try to squeeze in a bit more text - p.pad_left( mLabelPadLeft ); - p.pad_right(2); - } - - // inits flash timer - p.button_flash_enable = mEnableTabsFlashing; - p.flash_color = mTabsFlashingColor; - - // *TODO : It seems wrong not to use p in both cases considering the way p is initialized - if (mCustomIconCtrlUsed) - { - btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); - } - else - { - btn = LLUICtrlFactory::create<LLButton>(p); - } - } - - LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); - insertTuple( tuple, insertion_point ); - - // if new tab was added as a first or last tab, update button image - // and update button image of any tab it may have affected - if (tuple == mTabList.front()) - { - update_images(tuple, mFirstTabParams, getTabPosition()); - - if (mTabList.size() == 2) - { - update_images(mTabList[1], mLastTabParams, getTabPosition()); - } - else if (mTabList.size() > 2) - { - update_images(mTabList[1], mMiddleTabParams, getTabPosition()); - } - } - else if (tuple == mTabList.back()) - { - update_images(tuple, mLastTabParams, getTabPosition()); - - if (mTabList.size() > 2) - { - update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition()); - } - } - - //Don't add button and textbox if tab buttons are invisible(EXT - 576) - if (!getTabsHidden()) - { - if (textbox) - { - addChild( textbox, 0 ); - } - if (btn) - { - addChild( btn, 0 ); - } - } - else - { - if (textbox) - { - LLUICtrl::addChild(textbox, 0); - } - if (btn) - { - LLUICtrl::addChild(btn, 0); - } - } - - if (child) - { - LLUICtrl::addChild(child, 1); - } - - sendChildToFront(mPrevArrowBtn); - sendChildToFront(mNextArrowBtn); - sendChildToFront(mJumpPrevArrowBtn); - sendChildToFront(mJumpNextArrowBtn); - - updateMaxScrollPos(); - - if( select ) - { - selectLastTab(); - mScrollPos = mMaxScrollPos; - } + LLPanel* child = panel.panel(); + + llassert(child); + if (!child) return; + + const std::string& label = panel.label.isProvided() + ? panel.label() + : panel.panel()->getLabel(); + BOOL select = panel.select_tab(); + S32 indent = panel.indent(); + BOOL placeholder = panel.is_placeholder; + eInsertionPoint insertion_point = panel.insert_at(); + + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0); + static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); + if (child->getParent() == this) + { + // already a child of mine + return; + } + + // Store the original label for possible xml export. + child->setLabel(label); + std::string trimmed_label = label; + LLStringUtil::trim(trimmed_label); + + S32 button_width = mMinTabWidth; + if (!mIsVertical) + { + button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); + } + + // Tab panel + S32 tab_panel_top; + S32 tab_panel_bottom; + if (!getTabsHidden()) + { + if( getTabPosition() == LLTabContainer::TOP ) + { + S32 tab_height = mIsVertical ? BTN_HEIGHT : mTabHeight; + tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; + } + else + { + tab_panel_top = getRect().getHeight() - getTopBorderHeight(); + tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap); // Run to the edge, covering up the border + } + } + else + { + // Skip tab button space if tabs are invisible (EXT-576) + tab_panel_top = getRect().getHeight(); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; + } + + LLRect tab_panel_rect; + if (!getTabsHidden() && mIsVertical) + { + tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, + getRect().getHeight() - LLPANEL_BORDER_WIDTH, + getRect().getWidth() - LLPANEL_BORDER_WIDTH, + LLPANEL_BORDER_WIDTH); + } + else + { + S32 left_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 3 : LLPANEL_BORDER_WIDTH; + S32 right_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 2 : LLPANEL_BORDER_WIDTH; + tab_panel_rect = LLRect(left_offset, tab_panel_top, getRect().getWidth() - right_offset, tab_panel_bottom); + } + child->setFollowsAll(); + child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom); + child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); + // add this child later + + child->setVisible( FALSE ); // Will be made visible when selected + + mTotalTabWidth += button_width; + + // Tab button + LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw(). + LLUIImage* tab_img = NULL; + LLUIImage* tab_selected_img = NULL; + S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel + + if (mIsVertical) + { + btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor + (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()), + mMinTabWidth, + BTN_HEIGHT); + } + else if( getTabPosition() == LLTabContainer::TOP ) + { + btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight); + tab_img = mMiddleTabParams.tab_top_image_unselected; + tab_selected_img = mMiddleTabParams.tab_top_image_selected; + } + else + { + btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight); + tab_img = mMiddleTabParams.tab_bottom_image_unselected; + tab_selected_img = mMiddleTabParams.tab_bottom_image_selected; + } + + 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) + { + btn_rect.translate(0, -6); // *TODO: make configurable + LLTextBox::Params params; + params.name(trimmed_label); + params.rect(btn_rect); + params.initial_value(trimmed_label); + params.font(mFont); + textbox = LLUICtrlFactory::create<LLTextBox> (params); + + LLButton::Params p; + p.name("placeholder"); + btn = LLUICtrlFactory::create<LLButton>(p); + } + else + { + LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params); + + p.rect(btn_rect); + p.font(mFont); + p.font_halign = mFontHalign; + p.label(trimmed_label); + p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); + if (indent) + { + p.pad_left(indent); + } + p.pad_bottom( mLabelPadBottom ); + p.scale_image(true); + p.tab_stop(false); + p.label_shadow(false); + p.follows.flags = FOLLOWS_LEFT; + + if (mIsVertical) + { + p.name("vtab_"+std::string(child->getName())); + p.image_unselected(mMiddleTabParams.tab_left_image_unselected); + p.image_selected(mMiddleTabParams.tab_left_image_selected); + p.follows.flags = p.follows.flags() | FOLLOWS_TOP; + } + else + { + p.name("htab_"+std::string(child->getName())); + p.visible(false); + p.image_unselected(tab_img); + p.image_selected(tab_selected_img); + p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM); + // Try to squeeze in a bit more text + p.pad_left( mLabelPadLeft ); + p.pad_right(2); + } + + // inits flash timer + p.button_flash_enable = mEnableTabsFlashing; + p.flash_color = mTabsFlashingColor; + + // *TODO : It seems wrong not to use p in both cases considering the way p is initialized + if (mCustomIconCtrlUsed) + { + btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params); + } + else + { + btn = LLUICtrlFactory::create<LLButton>(p); + } + } + + LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); + insertTuple( tuple, insertion_point ); + + // if new tab was added as a first or last tab, update button image + // and update button image of any tab it may have affected + if (tuple == mTabList.front()) + { + update_images(tuple, mFirstTabParams, getTabPosition()); + + if (mTabList.size() == 2) + { + update_images(mTabList[1], mLastTabParams, getTabPosition()); + } + else if (mTabList.size() > 2) + { + update_images(mTabList[1], mMiddleTabParams, getTabPosition()); + } + } + else if (tuple == mTabList.back()) + { + update_images(tuple, mLastTabParams, getTabPosition()); + + if (mTabList.size() > 2) + { + update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition()); + } + } + + //Don't add button and textbox if tab buttons are invisible(EXT - 576) + if (!getTabsHidden()) + { + if (textbox) + { + addChild( textbox, 0 ); + } + if (btn) + { + addChild( btn, 0 ); + } + } + else + { + if (textbox) + { + LLUICtrl::addChild(textbox, 0); + } + if (btn) + { + LLUICtrl::addChild(btn, 0); + } + } + + if (child) + { + LLUICtrl::addChild(child, 1); + } + + sendChildToFront(mPrevArrowBtn); + sendChildToFront(mNextArrowBtn); + sendChildToFront(mJumpPrevArrowBtn); + sendChildToFront(mJumpNextArrowBtn); + + updateMaxScrollPos(); + + if( select ) + { + selectLastTab(); + mScrollPos = mMaxScrollPos; + } } void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label) { - addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true)); + addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true)); } void LLTabContainer::removeTabPanel(LLPanel* child) { - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - if (mIsVertical) - { - // Fix-up button sizes - S32 tab_count = 0; - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - LLRect rect; - rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor - (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)), - mMinTabWidth, - BTN_HEIGHT); - if (tuple->mPlaceholderText) - { - tuple->mPlaceholderText->setRect(rect); - } - else - { - tuple->mButton->setRect(rect); - } - tab_count++; - } - } - else - { - // Adjust the total tab width. - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - if( tuple->mTabPanel == child ) - { - mTotalTabWidth -= tuple->mButton->getRect().getWidth(); - break; - } - } - } - - BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); - - // If the tab being deleted is the selected one, select a different tab. - for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - if( tuple->mTabPanel == child ) - { - // update tab button images if removing the first or last tab - if ((tuple == mTabList.front()) && (mTabList.size() > 1)) - { - update_images(mTabList[1], mFirstTabParams, getTabPosition()); - } - else if ((tuple == mTabList.back()) && (mTabList.size() > 2)) - { - update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition()); - } - - if (!getTabsHidden()) - { - // We need to remove tab buttons only if the tabs are not hidden. - removeChild( tuple->mButton ); - } - delete tuple->mButton; + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + if (mIsVertical) + { + // Fix-up button sizes + S32 tab_count = 0; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + LLRect rect; + rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor + (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)), + mMinTabWidth, + BTN_HEIGHT); + if (tuple->mPlaceholderText) + { + tuple->mPlaceholderText->setRect(rect); + } + else + { + tuple->mButton->setRect(rect); + } + tab_count++; + } + } + else + { + // Adjust the total tab width. + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + if( tuple->mTabPanel == child ) + { + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + break; + } + } + } + + BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); + + // If the tab being deleted is the selected one, select a different tab. + for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + if( tuple->mTabPanel == child ) + { + // update tab button images if removing the first or last tab + if ((tuple == mTabList.front()) && (mTabList.size() > 1)) + { + update_images(mTabList[1], mFirstTabParams, getTabPosition()); + } + else if ((tuple == mTabList.back()) && (mTabList.size() > 2)) + { + update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition()); + } + + if (!getTabsHidden()) + { + // We need to remove tab buttons only if the tabs are not hidden. + removeChild( tuple->mButton ); + } + delete tuple->mButton; tuple->mButton = NULL; - removeChild( tuple->mTabPanel ); -// delete tuple->mTabPanel; + removeChild( tuple->mTabPanel ); +// delete tuple->mTabPanel; tuple->mTabPanel = NULL; - - mTabList.erase( iter ); - delete tuple; - - break; - } - } - - // make sure we don't have more locked tabs than we have tabs - mLockedTabCount = llmin(getTabCount(), mLockedTabCount); - - if (mCurrentTabIdx >= (S32)mTabList.size()) - { - mCurrentTabIdx = mTabList.size()-1; - } - selectTab(mCurrentTabIdx); - if (has_focus) - { - LLPanel* panelp = getPanelByIndex(mCurrentTabIdx); - if (panelp) - { - panelp->setFocus(TRUE); - } - } - - updateMaxScrollPos(); + + mTabList.erase( iter ); + delete tuple; + + break; + } + } + + // make sure we don't have more locked tabs than we have tabs + mLockedTabCount = llmin(getTabCount(), mLockedTabCount); + + if (mCurrentTabIdx >= (S32)mTabList.size()) + { + mCurrentTabIdx = mTabList.size()-1; + } + selectTab(mCurrentTabIdx); + if (has_focus) + { + LLPanel* panelp = getPanelByIndex(mCurrentTabIdx); + if (panelp) + { + panelp->setFocus(TRUE); + } + } + + updateMaxScrollPos(); } void LLTabContainer::lockTabs(S32 num_tabs) { - // count current tabs or use supplied value and ensure no new tabs get - // inserted between them - mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount(); + // count current tabs or use supplied value and ensure no new tabs get + // inserted between them + mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount(); } void LLTabContainer::unlockTabs() { - mLockedTabCount = 0; + mLockedTabCount = 0; } void LLTabContainer::enableTabButton(S32 which, BOOL enable) { - if (which >= 0 && which < (S32)mTabList.size()) - { - mTabList[which]->mButton->setEnabled(enable); - } - // Stop the DaD timer as it might run forever - // enableTabButton() is typically called on refresh and draw when anything changed - // in the tab container so it's a good time to reset that. - mDragAndDropDelayTimer.stop(); + if (which >= 0 && which < (S32)mTabList.size()) + { + mTabList[which]->mButton->setEnabled(enable); + } + // Stop the DaD timer as it might run forever + // enableTabButton() is typically called on refresh and draw when anything changed + // in the tab container so it's a good time to reset that. + mDragAndDropDelayTimer.stop(); } void LLTabContainer::deleteAllTabs() { - // Remove all the tab buttons and delete them. Also, unlink all the child panels. - for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; + // Remove all the tab buttons and delete them. Also, unlink all the child panels. + for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; - removeChild( tuple->mButton ); - delete tuple->mButton; + removeChild( tuple->mButton ); + delete tuple->mButton; tuple->mButton = NULL; - removeChild( tuple->mTabPanel ); -// delete tuple->mTabPanel; + removeChild( tuple->mTabPanel ); +// delete tuple->mTabPanel; tuple->mTabPanel = NULL; - } + } + + // Actually delete the tuples themselves + std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); + mTabList.clear(); - // Actually delete the tuples themselves - std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); - mTabList.clear(); - - // And there isn't a current tab any more - mCurrentTabIdx = -1; + // And there isn't a current tab any more + mCurrentTabIdx = -1; } LLPanel* LLTabContainer::getCurrentPanel() { - if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size()) - { - return mTabList[mCurrentTabIdx]->mTabPanel; - } - return NULL; + if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size()) + { + return mTabList[mCurrentTabIdx]->mTabPanel; + } + return NULL; } S32 LLTabContainer::getCurrentPanelIndex() { - return mCurrentTabIdx; + return mCurrentTabIdx; } S32 LLTabContainer::getTabCount() { - return mTabList.size(); + return mTabList.size(); } LLPanel* LLTabContainer::getPanelByIndex(S32 index) { - if (index >= 0 && index < (S32)mTabList.size()) - { - return mTabList[index]->mTabPanel; - } - return NULL; + if (index >= 0 && index < (S32)mTabList.size()) + { + return mTabList[index]->mTabPanel; + } + return NULL; } S32 LLTabContainer::getIndexForPanel(LLPanel* panel) { - for (S32 index = 0; index < (S32)mTabList.size(); index++) - { - if (mTabList[index]->mTabPanel == panel) - { - return index; - } - } - return -1; + for (S32 index = 0; index < (S32)mTabList.size(); index++) + { + if (mTabList[index]->mTabPanel == panel) + { + return index; + } + } + return -1; } S32 LLTabContainer::getPanelIndexByTitle(const std::string& title) { - for (S32 index = 0 ; index < (S32)mTabList.size(); index++) - { - if (title == mTabList[index]->mButton->getLabelSelected()) - { - return index; - } - } - return -1; + for (S32 index = 0 ; index < (S32)mTabList.size(); index++) + { + if (title == mTabList[index]->mButton->getLabelSelected()) + { + return index; + } + } + return -1; } LLPanel* LLTabContainer::getPanelByName(const std::string& name) { - for (S32 index = 0 ; index < (S32)mTabList.size(); index++) - { - LLPanel *panel = mTabList[index]->mTabPanel; - if (name == panel->getName()) - { - return panel; - } - } - return NULL; + for (S32 index = 0 ; index < (S32)mTabList.size(); index++) + { + LLPanel *panel = mTabList[index]->mTabPanel; + if (name == panel->getName()) + { + return panel; + } + } + return NULL; } // Change the name of the button for the current tab. void LLTabContainer::setCurrentTabName(const std::string& name) { - // Might not have a tab selected - if (mCurrentTabIdx < 0) return; + // Might not have a tab selected + if (mCurrentTabIdx < 0) return; - mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name); - mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name); + mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name); + mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name); } void LLTabContainer::selectFirstTab() { - selectTab( 0 ); + selectTab( 0 ); } void LLTabContainer::selectLastTab() { - selectTab( mTabList.size()-1 ); + selectTab( mTabList.size()-1 ); } void LLTabContainer::selectNextTab() @@ -1453,108 +1454,108 @@ void LLTabContainer::selectNextTab() return; } - BOOL tab_has_focus = FALSE; - if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) - { - tab_has_focus = TRUE; - } - S32 idx = mCurrentTabIdx+1; - if (idx >= (S32)mTabList.size()) - idx = 0; - while (!selectTab(idx) && idx != mCurrentTabIdx) - { - idx = (idx + 1 ) % (S32)mTabList.size(); - } + BOOL tab_has_focus = FALSE; + if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) + { + tab_has_focus = TRUE; + } + S32 idx = mCurrentTabIdx+1; + if (idx >= (S32)mTabList.size()) + idx = 0; + while (!selectTab(idx) && idx != mCurrentTabIdx) + { + idx = (idx + 1 ) % (S32)mTabList.size(); + } - if (tab_has_focus) - { - mTabList[idx]->mButton->setFocus(TRUE); - } + if (tab_has_focus) + { + mTabList[idx]->mButton->setFocus(TRUE); + } } void LLTabContainer::selectPrevTab() { - BOOL tab_has_focus = FALSE; - if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) - { - tab_has_focus = TRUE; - } - S32 idx = mCurrentTabIdx-1; - if (idx < 0) - idx = mTabList.size()-1; - while (!selectTab(idx) && idx != mCurrentTabIdx) - { - idx = idx - 1; - if (idx < 0) - idx = mTabList.size()-1; - } - if (tab_has_focus) - { - mTabList[idx]->mButton->setFocus(TRUE); - } -} + BOOL tab_has_focus = FALSE; + if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) + { + tab_has_focus = TRUE; + } + S32 idx = mCurrentTabIdx-1; + if (idx < 0) + idx = mTabList.size()-1; + while (!selectTab(idx) && idx != mCurrentTabIdx) + { + idx = idx - 1; + if (idx < 0) + idx = mTabList.size()-1; + } + if (tab_has_focus) + { + mTabList[idx]->mButton->setFocus(TRUE); + } +} BOOL LLTabContainer::selectTabPanel(LLPanel* child) { - S32 idx = 0; - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - if( tuple->mTabPanel == child ) - { - return selectTab( idx ); - } - idx++; - } - return FALSE; + S32 idx = 0; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + if( tuple->mTabPanel == child ) + { + return selectTab( idx ); + } + idx++; + } + return FALSE; } BOOL LLTabContainer::selectTab(S32 which) { - if (which >= getTabCount() || which < 0) - return FALSE; + if (which >= getTabCount() || which < 0) + return FALSE; - LLTabTuple* selected_tuple = getTab(which); - if (!selected_tuple) - return FALSE; + LLTabTuple* selected_tuple = getTab(which); + if (!selected_tuple) + return FALSE; - LLSD cbdata; - if (selected_tuple->mTabPanel) - cbdata = selected_tuple->mTabPanel->getName(); + LLSD cbdata; + if (selected_tuple->mTabPanel) + cbdata = selected_tuple->mTabPanel->getName(); - BOOL result = FALSE; - if (!mValidateSignal || (*mValidateSignal)(this, cbdata)) - { - result = setTab(which); - if (result && mCommitSignal) - { - (*mCommitSignal)(this, cbdata); - } - } + BOOL result = FALSE; + if (!mValidateSignal || (*mValidateSignal)(this, cbdata)) + { + result = setTab(which); + if (result && mCommitSignal) + { + (*mCommitSignal)(this, cbdata); + } + } - return result; + return result; } // private BOOL LLTabContainer::setTab(S32 which) { - static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); - LLTabTuple* selected_tuple = getTab(which); - if (!selected_tuple) - { - return FALSE; - } - - BOOL is_visible = FALSE; - if( selected_tuple->mButton->getEnabled() && selected_tuple->mVisible ) - { - setCurrentPanelIndex(which); - - S32 i = 0; - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - BOOL is_selected = ( tuple == selected_tuple ); + static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); + LLTabTuple* selected_tuple = getTab(which); + if (!selected_tuple) + { + return FALSE; + } + + BOOL is_visible = FALSE; + if( selected_tuple->mButton->getEnabled() && selected_tuple->mVisible ) + { + setCurrentPanelIndex(which); + + S32 i = 0; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + BOOL is_selected = ( tuple == selected_tuple ); // Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list if (tuple && tuple->mButton) { @@ -1569,464 +1570,464 @@ BOOL LLTabContainer::setTab(S32 which) tuple->mTabPanel->setVisible( is_selected ); //tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. } - - if (is_selected) - { - LLUIUsage::instance().logPanel(tuple->mTabPanel->getName()); - - // Make sure selected tab is within scroll region - if (mIsVertical) - { - S32 num_visible = getTabCount() - getMaxScrollPos(); - if( i >= getScrollPos() && i <= getScrollPos() + num_visible) - { - setCurrentPanelIndex(which); - is_visible = TRUE; - } - else - { - is_visible = FALSE; - } - } - else if (!mHideScrollArrows && getMaxScrollPos() > 0) - { - if( i < getScrollPos() ) - { - setScrollPos(i); - } - else - { - S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - S32 running_tab_width = (tuple && tuple->mButton ? tuple->mButton->getRect().getWidth() : 0); - S32 j = i - 1; - S32 min_scroll_pos = i; - if (running_tab_width < available_width_with_arrows) - { - while (j >= 0) - { - LLTabTuple* other_tuple = getTab(j); - running_tab_width += (other_tuple && other_tuple->mButton ? other_tuple->mButton->getRect().getWidth() : 0); - if (running_tab_width > available_width_with_arrows) - { - break; - } - j--; - } - min_scroll_pos = j + 1; - } - setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i)); - setScrollPos(llmin(getScrollPos(), getMaxScrollPos())); - } - is_visible = TRUE; - } - else - { - is_visible = TRUE; - } - } - i++; - } - } - if (mIsVertical && getCurrentPanelIndex() >= 0) - { - LLTabTuple* tuple = getTab(getCurrentPanelIndex()); - tuple->mTabPanel->setVisible( TRUE ); - tuple->mButton->setToggleState( TRUE ); - } - return is_visible; + + if (is_selected) + { + LLUIUsage::instance().logPanel(tuple->mTabPanel->getName()); + + // Make sure selected tab is within scroll region + if (mIsVertical) + { + S32 num_visible = getTabCount() - getMaxScrollPos(); + if( i >= getScrollPos() && i <= getScrollPos() + num_visible) + { + setCurrentPanelIndex(which); + is_visible = TRUE; + } + else + { + is_visible = FALSE; + } + } + else if (!mHideScrollArrows && getMaxScrollPos() > 0) + { + if( i < getScrollPos() ) + { + setScrollPos(i); + } + else + { + S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); + S32 running_tab_width = (tuple && tuple->mButton ? tuple->mButton->getRect().getWidth() : 0); + S32 j = i - 1; + S32 min_scroll_pos = i; + if (running_tab_width < available_width_with_arrows) + { + while (j >= 0) + { + LLTabTuple* other_tuple = getTab(j); + running_tab_width += (other_tuple && other_tuple->mButton ? other_tuple->mButton->getRect().getWidth() : 0); + if (running_tab_width > available_width_with_arrows) + { + break; + } + j--; + } + min_scroll_pos = j + 1; + } + setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i)); + setScrollPos(llmin(getScrollPos(), getMaxScrollPos())); + } + is_visible = TRUE; + } + else + { + is_visible = TRUE; + } + } + i++; + } + } + if (mIsVertical && getCurrentPanelIndex() >= 0) + { + LLTabTuple* tuple = getTab(getCurrentPanelIndex()); + tuple->mTabPanel->setVisible( TRUE ); + tuple->mButton->setToggleState( TRUE ); + } + return is_visible; } BOOL LLTabContainer::selectTabByName(const std::string& name) { - LLPanel* panel = getPanelByName(name); - if (!panel) - { - LL_WARNS() << "LLTabContainer::selectTabByName(" << name << ") failed" << LL_ENDL; - return FALSE; - } + LLPanel* panel = getPanelByName(name); + if (!panel) + { + LL_WARNS() << "LLTabContainer::selectTabByName(" << name << ") failed" << LL_ENDL; + return FALSE; + } - BOOL result = selectTabPanel(panel); - return result; + BOOL result = selectTabPanel(panel); + return result; } BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child) { - LLTabTuple* tuple = getTabByPanel(child); - if( tuple ) - { - return tuple->mButton->getFlashing(); - } - return FALSE; + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + return tuple->mButton->getFlashing(); + } + return FALSE; } void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state ) { - LLTabTuple* tuple = getTabByPanel(child); - if( tuple ) - { - tuple->mButton->setFlashing( state ); - } + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setFlashing( state ); + } } void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) { - LLTabTuple* tuple = getTabByPanel(child); - if( tuple ) - { - tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color); - reshapeTuple(tuple); - } + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color); + reshapeTuple(tuple); + } } void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color) { - LLTabTuple* tuple = getTabByPanel(child); - if( tuple ) - { - tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color); - reshapeTuple(tuple); - } + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color); + reshapeTuple(tuple); + } } void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon) { - LLTabTuple* tuple = getTabByPanel(child); - LLCustomButtonIconCtrl* button; - bool hasButton = false; - - if(tuple) - { - button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); - if(button) - { - hasButton = true; - button->setIcon(icon); - reshapeTuple(tuple); - } - } - - if (!hasButton && (icon != NULL)) - { - // It was assumed that the tab's button would take ownership of the icon pointer. - // But since the tab did not have a button, kill the icon to prevent the memory - // leak. - icon->die(); - } + LLTabTuple* tuple = getTabByPanel(child); + LLCustomButtonIconCtrl* button; + bool hasButton = false; + + if(tuple) + { + button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); + if(button) + { + hasButton = true; + button->setIcon(icon); + reshapeTuple(tuple); + } + } + + if (!hasButton && (icon != NULL)) + { + // It was assumed that the tab's button would take ownership of the icon pointer. + // But since the tab did not have a button, kill the icon to prevent the memory + // leak. + icon->die(); + } } void LLTabContainer::reshapeTuple(LLTabTuple* tuple) { - static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - - if (!mIsVertical) - { - S32 image_overlay_width = 0; + static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - if(mCustomIconCtrlUsed) - { - LLCustomButtonIconCtrl* button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); - LLIconCtrl* icon_ctrl = button ? button->getIconCtrl() : NULL; - image_overlay_width = icon_ctrl ? icon_ctrl->getRect().getWidth() : 0; - } - else - { - image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? - tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0; - } - // remove current width from total tab strip width - mTotalTabWidth -= tuple->mButton->getRect().getWidth(); - - tuple->mPadding = image_overlay_width; - - tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), - tuple->mButton->getRect().getHeight()); - // add back in button width to total tab strip width - mTotalTabWidth += tuple->mButton->getRect().getWidth(); - - // tabs have changed size, might need to scroll to see current tab - updateMaxScrollPos(); - } + if (!mIsVertical) + { + S32 image_overlay_width = 0; + + if(mCustomIconCtrlUsed) + { + LLCustomButtonIconCtrl* button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton); + LLIconCtrl* icon_ctrl = button ? button->getIconCtrl() : NULL; + image_overlay_width = icon_ctrl ? icon_ctrl->getRect().getWidth() : 0; + } + else + { + image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0; + } + // remove current width from total tab strip width + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); + + tuple->mPadding = image_overlay_width; + + tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), + tuple->mButton->getRect().getHeight()); + // add back in button width to total tab strip width + mTotalTabWidth += tuple->mButton->getRect().getWidth(); + + // tabs have changed size, might need to scroll to see current tab + updateMaxScrollPos(); + } } void LLTabContainer::setTitle(const std::string& title) -{ - if (mTitleBox) - { - mTitleBox->setText( title ); - } +{ + if (mTitleBox) + { + mTitleBox->setText( title ); + } } const std::string LLTabContainer::getPanelTitle(S32 index) { - if (index >= 0 && index < (S32)mTabList.size()) - { - LLButton* tab_button = mTabList[index]->mButton; - return tab_button->getLabelSelected(); - } - return LLStringUtil::null; + if (index >= 0 && index < (S32)mTabList.size()) + { + LLButton* tab_button = mTabList[index]->mButton; + return tab_button->getLabelSelected(); + } + return LLStringUtil::null; } void LLTabContainer::setTopBorderHeight(S32 height) { - mTopBorderHeight = height; + mTopBorderHeight = height; } S32 LLTabContainer::getTopBorderHeight() const { - return mTopBorderHeight; + return mTopBorderHeight; } void LLTabContainer::setRightTabBtnOffset(S32 offset) { - mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); - mRightTabBtnOffset = offset; - updateMaxScrollPos(); + mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); + mRightTabBtnOffset = offset; + updateMaxScrollPos(); } void LLTabContainer::setPanelTitle(S32 index, const std::string& title) { - static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); + static LLUICachedControl<S32> tab_padding ("UITabPadding", 0); - if (index >= 0 && index < getTabCount()) - { - LLTabTuple* tuple = getTab(index); - LLButton* tab_button = tuple->mButton; - const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); - mTotalTabWidth -= tab_button->getRect().getWidth(); - tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); - mTotalTabWidth += tab_button->getRect().getWidth(); - tab_button->setLabelSelected(title); - tab_button->setLabelUnselected(title); - } - updateMaxScrollPos(); + if (index >= 0 && index < getTabCount()) + { + LLTabTuple* tuple = getTab(index); + LLButton* tab_button = tuple->mButton; + const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); + mTotalTabWidth -= tab_button->getRect().getWidth(); + tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); + mTotalTabWidth += tab_button->getRect().getWidth(); + tab_button->setLabelSelected(title); + tab_button->setLabelUnselected(title); + } + updateMaxScrollPos(); } void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel ) { - LLTabTuple* tuple = getTabByPanel(panel); - selectTabPanel( panel ); + LLTabTuple* tuple = getTabByPanel(panel); + selectTabPanel( panel ); - if (tuple) - { - tuple->mTabPanel->setFocus(TRUE); - } + if (tuple) + { + tuple->mTabPanel->setFocus(TRUE); + } } void LLTabContainer::onNextBtn( const LLSD& data ) { - if (!mScrolled) - { - scrollNext(); - } - mScrolled = FALSE; + if (!mScrolled) + { + scrollNext(); + } + mScrolled = FALSE; - if(mCurrentTabIdx < mTabList.size()-1) - { - selectNextTab(); - } + if(mCurrentTabIdx < mTabList.size()-1) + { + selectNextTab(); + } } void LLTabContainer::onNextBtnHeld( const LLSD& data ) { - if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) - { - mScrollTimer.reset(); - scrollNext(); - - if(mCurrentTabIdx < mTabList.size()-1) - { - selectNextTab(); - } - mScrolled = TRUE; - } + if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) + { + mScrollTimer.reset(); + scrollNext(); + + if(mCurrentTabIdx < mTabList.size()-1) + { + selectNextTab(); + } + mScrolled = TRUE; + } } void LLTabContainer::onPrevBtn( const LLSD& data ) { - if (!mScrolled) - { - scrollPrev(); - } - mScrolled = FALSE; + if (!mScrolled) + { + scrollPrev(); + } + mScrolled = FALSE; - if(mCurrentTabIdx > 0) - { - selectPrevTab(); - } + if(mCurrentTabIdx > 0) + { + selectPrevTab(); + } } void LLTabContainer::onJumpFirstBtn( const LLSD& data ) { - mScrollPos = 0; + mScrollPos = 0; } void LLTabContainer::onJumpLastBtn( const LLSD& data ) { - mScrollPos = mMaxScrollPos; + mScrollPos = mMaxScrollPos; } void LLTabContainer::onPrevBtnHeld( const LLSD& data ) { - if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) - { - mScrollTimer.reset(); - scrollPrev(); - - if(mCurrentTabIdx > 0) - { - selectPrevTab(); - } - mScrolled = TRUE; - } + if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) + { + mScrollTimer.reset(); + scrollPrev(); + + if(mCurrentTabIdx > 0) + { + selectPrevTab(); + } + mScrolled = TRUE; + } } // private void LLTabContainer::initButtons() { - // Hack: - if (getRect().getHeight() == 0 || mPrevArrowBtn) - { - return; // Don't have a rect yet or already got called - } - - if (mIsVertical) - { - static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); - // Left and right scroll arrows (for when there are too many tabs to show all at once). - S32 btn_top = getRect().getHeight(); - S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size; - - LLRect up_arrow_btn_rect; - up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size ); - - LLRect down_arrow_btn_rect; - down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size ); - - LLButton::Params prev_btn_params; - prev_btn_params.name(std::string("Up Arrow")); - prev_btn_params.rect(up_arrow_btn_rect); - prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); - prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga"); - prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga"); - prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2)); - mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params); - - LLButton::Params next_btn_params; - next_btn_params.name(std::string("Down Arrow")); - next_btn_params.rect(down_arrow_btn_rect); - next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT); - next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga"); - next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga"); - next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2)); - mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params); - } - else // Horizontal - { - static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); - S32 arrow_fudge = 1; // match new art better - - // Left and right scroll arrows (for when there are too many tabs to show all at once). - S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1; - - LLRect left_arrow_btn_rect; - left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); - - LLRect jump_left_arrow_btn_rect; - jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); - - S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1; - - LLRect right_arrow_btn_rect; - right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size, - btn_top + arrow_fudge, - tabcntr_arrow_btn_size, mTabHeight ); - - - LLRect jump_right_arrow_btn_rect; - jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad, - btn_top + arrow_fudge, - tabcntr_arrow_btn_size, mTabHeight ); - - LLButton::Params p; - p.name(std::string("Jump Left Arrow")); - p.image_unselected.name("jump_left_out.tga"); - p.image_selected.name("jump_left_in.tga"); - p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2)); - p.rect(jump_left_arrow_btn_rect); - p.follows.flags(FOLLOWS_LEFT); - - mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p); - - p = LLButton::Params(); - p.name(std::string("Left Arrow")); - p.rect(left_arrow_btn_rect); - p.follows.flags(FOLLOWS_LEFT); - p.image_unselected.name("scrollbutton_left_out_blue.tga"); - p.image_selected.name("scrollbutton_left_in_blue.tga"); - p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2)); - p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); - - mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p); - - p = LLButton::Params(); - p.name(std::string("Jump Right Arrow")); - p.rect(jump_right_arrow_btn_rect); - p.follows.flags(FOLLOWS_RIGHT); - p.image_unselected.name("jump_right_out.tga"); - p.image_selected.name("jump_right_in.tga"); - p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2)); - - mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p); - - p = LLButton::Params(); - p.name(std::string("Right Arrow")); - p.rect(right_arrow_btn_rect); - p.follows.flags(FOLLOWS_RIGHT); - p.image_unselected.name("scrollbutton_right_out_blue.tga"); - p.image_selected.name("scrollbutton_right_in_blue.tga"); - p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2)); - p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2)); - - mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p); - - if( getTabPosition() == TOP ) - { - mNextArrowBtn->setFollowsTop(); - mPrevArrowBtn->setFollowsTop(); - mJumpPrevArrowBtn->setFollowsTop(); - mJumpNextArrowBtn->setFollowsTop(); - } - else - { - mNextArrowBtn->setFollowsBottom(); - mPrevArrowBtn->setFollowsBottom(); - mJumpPrevArrowBtn->setFollowsBottom(); - mJumpNextArrowBtn->setFollowsBottom(); - } - } - - mPrevArrowBtn->setTabStop(FALSE); - addChild(mPrevArrowBtn); - - mNextArrowBtn->setTabStop(FALSE); - addChild(mNextArrowBtn); - - if (mJumpPrevArrowBtn) - { - mJumpPrevArrowBtn->setTabStop(FALSE); - addChild(mJumpPrevArrowBtn); - } - - if (mJumpNextArrowBtn) - { - mJumpNextArrowBtn->setTabStop(FALSE); - addChild(mJumpNextArrowBtn); - } - - // set default tab group to be panel contents - setDefaultTabGroup(1); + // Hack: + if (getRect().getHeight() == 0 || mPrevArrowBtn) + { + return; // Don't have a rect yet or already got called + } + + if (mIsVertical) + { + static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); + // Left and right scroll arrows (for when there are too many tabs to show all at once). + S32 btn_top = getRect().getHeight(); + S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size; + + LLRect up_arrow_btn_rect; + up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size ); + + LLRect down_arrow_btn_rect; + down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size ); + + LLButton::Params prev_btn_params; + prev_btn_params.name(std::string("Up Arrow")); + prev_btn_params.rect(up_arrow_btn_rect); + prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); + prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga"); + prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga"); + prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2)); + mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params); + + LLButton::Params next_btn_params; + next_btn_params.name(std::string("Down Arrow")); + next_btn_params.rect(down_arrow_btn_rect); + next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT); + next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga"); + next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga"); + next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2)); + mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params); + } + else // Horizontal + { + static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); + S32 arrow_fudge = 1; // match new art better + + // Left and right scroll arrows (for when there are too many tabs to show all at once). + S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1; + + LLRect left_arrow_btn_rect; + left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); + + LLRect jump_left_arrow_btn_rect; + jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight ); + + S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1; + + LLRect right_arrow_btn_rect; + right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size, + btn_top + arrow_fudge, + tabcntr_arrow_btn_size, mTabHeight ); + + + LLRect jump_right_arrow_btn_rect; + jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad, + btn_top + arrow_fudge, + tabcntr_arrow_btn_size, mTabHeight ); + + LLButton::Params p; + p.name(std::string("Jump Left Arrow")); + p.image_unselected.name("jump_left_out.tga"); + p.image_selected.name("jump_left_in.tga"); + p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2)); + p.rect(jump_left_arrow_btn_rect); + p.follows.flags(FOLLOWS_LEFT); + + mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p); + + p = LLButton::Params(); + p.name(std::string("Left Arrow")); + p.rect(left_arrow_btn_rect); + p.follows.flags(FOLLOWS_LEFT); + p.image_unselected.name("scrollbutton_left_out_blue.tga"); + p.image_selected.name("scrollbutton_left_in_blue.tga"); + p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2)); + p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); + + mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p); + + p = LLButton::Params(); + p.name(std::string("Jump Right Arrow")); + p.rect(jump_right_arrow_btn_rect); + p.follows.flags(FOLLOWS_RIGHT); + p.image_unselected.name("jump_right_out.tga"); + p.image_selected.name("jump_right_in.tga"); + p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2)); + + mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p); + + p = LLButton::Params(); + p.name(std::string("Right Arrow")); + p.rect(right_arrow_btn_rect); + p.follows.flags(FOLLOWS_RIGHT); + p.image_unselected.name("scrollbutton_right_out_blue.tga"); + p.image_selected.name("scrollbutton_right_in_blue.tga"); + p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2)); + p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2)); + + mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p); + + if( getTabPosition() == TOP ) + { + mNextArrowBtn->setFollowsTop(); + mPrevArrowBtn->setFollowsTop(); + mJumpPrevArrowBtn->setFollowsTop(); + mJumpNextArrowBtn->setFollowsTop(); + } + else + { + mNextArrowBtn->setFollowsBottom(); + mPrevArrowBtn->setFollowsBottom(); + mJumpPrevArrowBtn->setFollowsBottom(); + mJumpNextArrowBtn->setFollowsBottom(); + } + } + + mPrevArrowBtn->setTabStop(FALSE); + addChild(mPrevArrowBtn); + + mNextArrowBtn->setTabStop(FALSE); + addChild(mNextArrowBtn); + + if (mJumpPrevArrowBtn) + { + mJumpPrevArrowBtn->setTabStop(FALSE); + addChild(mJumpPrevArrowBtn); + } + + if (mJumpNextArrowBtn) + { + mJumpNextArrowBtn->setTabStop(FALSE); + addChild(mJumpNextArrowBtn); + } + + // set default tab group to be panel contents + setDefaultTabGroup(1); } //this is a work around for the current LLPanel::initFromParams hack @@ -2034,135 +2035,135 @@ void LLTabContainer::initButtons() //will be removed when LLPanel is fixed soon. void LLTabContainer::initFromParams(const LLPanel::Params& p) { - LLPanel::initFromParams(p); + LLPanel::initFromParams(p); - setDefaultTabGroup(1); + setDefaultTabGroup(1); } LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) { - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - if( tuple->mTabPanel == child ) - { - return tuple; - } - } - return NULL; + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + if( tuple->mTabPanel == child ) + { + return tuple; + } + } + return NULL; } void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point) { - switch(insertion_point) - { - case START: - // insert the new tab in the front of the list - mTabList.insert(mTabList.begin() + mLockedTabCount, tuple); - break; - case LEFT_OF_CURRENT: - // insert the new tab before the current tab (but not before mLockedTabCount) - { - tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx); - mTabList.insert(current_iter, tuple); - } - break; - - case RIGHT_OF_CURRENT: - // insert the new tab after the current tab (but not before mLockedTabCount) - { - tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1); - mTabList.insert(current_iter, tuple); - } - break; - case END: - default: - mTabList.push_back( tuple ); - } + switch(insertion_point) + { + case START: + // insert the new tab in the front of the list + mTabList.insert(mTabList.begin() + mLockedTabCount, tuple); + break; + case LEFT_OF_CURRENT: + // insert the new tab before the current tab (but not before mLockedTabCount) + { + tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx); + mTabList.insert(current_iter, tuple); + } + break; + + case RIGHT_OF_CURRENT: + // insert the new tab after the current tab (but not before mLockedTabCount) + { + tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1); + mTabList.insert(current_iter, tuple); + } + break; + case END: + default: + mTabList.push_back( tuple ); + } } void LLTabContainer::updateMaxScrollPos() { - static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); - BOOL no_scroll = TRUE; - if (mIsVertical) - { - S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount(); - S32 available_height = getRect().getHeight() - getTopBorderHeight(); - if( tab_total_height > available_height ) - { - static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); - S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom; - S32 additional_needed = tab_total_height - available_height_with_arrows; - setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) ); - no_scroll = FALSE; - } - } - else - { - static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0); - static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); - static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0); - S32 tab_space = 0; - S32 available_space = 0; - tab_space = mTotalTabWidth; - available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad); - - if( tab_space > available_space ) - { - S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - // subtract off reserved portion on left - available_width_with_arrows -= tabcntr_tab_partial_width; - - S32 running_tab_width = 0; - setMaxScrollPos(getTabCount()); - for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it) - { - running_tab_width += (*tab_it)->mButton->getRect().getWidth(); - if (running_tab_width > available_width_with_arrows) - { - break; - } - setMaxScrollPos(getMaxScrollPos()-1); - } - // in case last tab doesn't actually fit on screen, make it the last scrolling position - setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1)); - no_scroll = FALSE; - } - } - if (no_scroll) - { - setMaxScrollPos(0); - setScrollPos(0); - } - if (getScrollPos() > getMaxScrollPos()) - { - setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead? - } + static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0); + BOOL no_scroll = TRUE; + if (mIsVertical) + { + S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount(); + S32 available_height = getRect().getHeight() - getTopBorderHeight(); + if( tab_total_height > available_height ) + { + static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); + S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom; + S32 additional_needed = tab_total_height - available_height_with_arrows; + setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) ); + no_scroll = FALSE; + } + } + else + { + static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0); + static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0); + static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0); + S32 tab_space = 0; + S32 available_space = 0; + tab_space = mTotalTabWidth; + available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad); + + if( tab_space > available_space ) + { + S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); + // subtract off reserved portion on left + available_width_with_arrows -= tabcntr_tab_partial_width; + + S32 running_tab_width = 0; + setMaxScrollPos(getTabCount()); + for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it) + { + running_tab_width += (*tab_it)->mButton->getRect().getWidth(); + if (running_tab_width > available_width_with_arrows) + { + break; + } + setMaxScrollPos(getMaxScrollPos()-1); + } + // in case last tab doesn't actually fit on screen, make it the last scrolling position + setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1)); + no_scroll = FALSE; + } + } + if (no_scroll) + { + setMaxScrollPos(0); + setScrollPos(0); + } + if (getScrollPos() > getMaxScrollPos()) + { + setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead? + } } void LLTabContainer::commitHoveredButton(S32 x, S32 y) { - if (!getTabsHidden() && hasMouseCapture()) - { - for (tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLButton* button = (*iter)->mButton; - LLPanel* panel = (*iter)->mTabPanel; - if (button->getEnabled() && button->getVisible() && !panel->getVisible()) - { - S32 local_x = x - button->getRect().mLeft; - S32 local_y = y - button->getRect().mBottom; - if (button->pointInView(local_x, local_y)) - { - button->onCommit(); - break; - } - } - } - } + if (!getTabsHidden() && hasMouseCapture()) + { + for (tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLButton* button = (*iter)->mButton; + LLPanel* panel = (*iter)->mTabPanel; + if (button->getEnabled() && button->getVisible() && !panel->getVisible()) + { + S32 local_x = x - button->getRect().mLeft; + S32 local_y = y - button->getRect().mBottom; + if (button->pointInView(local_x, local_y)) + { + button->onCommit(); + break; + } + } + } + } } S32 LLTabContainer::getTotalTabWidth() const @@ -2172,32 +2173,32 @@ S32 LLTabContainer::getTotalTabWidth() const void LLTabContainer::setTabVisibility( LLPanel const *aPanel, bool aVisible ) { - for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) - { - LLTabTuple const *pTT = *itr; - if( pTT->mTabPanel == aPanel ) - { - pTT->mVisible = aVisible; - break; - } - } - - bool foundTab( false ); - for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) - { - LLTabTuple const *pTT = *itr; - if( pTT->mVisible ) - { - this->selectTab( itr - mTabList.begin() ); - foundTab = true; - break; - } - } - - if( foundTab ) - this->setVisible( TRUE ); - else - this->setVisible( FALSE ); - - updateMaxScrollPos(); + for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) + { + LLTabTuple const *pTT = *itr; + if( pTT->mTabPanel == aPanel ) + { + pTT->mVisible = aVisible; + break; + } + } + + bool foundTab( false ); + for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) + { + LLTabTuple const *pTT = *itr; + if( pTT->mVisible ) + { + this->selectTab( itr - mTabList.begin() ); + foundTab = true; + break; + } + } + + if( foundTab ) + this->setVisible( TRUE ); + else + this->setVisible( FALSE ); + + updateMaxScrollPos(); } diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index aa4a08c4ff..626255be8c 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -1,25 +1,25 @@ -/** +/** * @file lltabcontainer.h * @brief LLTabContainer class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,289 +38,293 @@ class LLTabTuple; class LLTabContainer : public LLPanel { public: - enum TabPosition - { - TOP, - BOTTOM, - LEFT - }; - typedef enum e_insertion_point - { - START, - END, - LEFT_OF_CURRENT, - RIGHT_OF_CURRENT - } eInsertionPoint; - - struct TabPositions : public LLInitParam::TypeValuesHelper<LLTabContainer::TabPosition, TabPositions> - { - static void declareValues(); - }; - - struct TabParams : public LLInitParam::Block<TabParams> - { - Optional<LLUIImage*> tab_top_image_unselected, - tab_top_image_selected, - tab_top_image_flash, - tab_bottom_image_unselected, - tab_bottom_image_selected, - tab_bottom_image_flash, - tab_left_image_unselected, - tab_left_image_selected, - tab_left_image_flash; - TabParams(); - }; - - struct Params - : public LLInitParam::Block<Params, LLPanel::Params> - { - Optional<TabPosition, TabPositions> tab_position; - Optional<S32> tab_width, - tab_min_width, - tab_max_width, - tab_height, - label_pad_bottom, - label_pad_left; - - Optional<bool> hide_tabs; - Optional<bool> hide_scroll_arrows; - Optional<S32> tab_padding_right; - - Optional<TabParams> first_tab, - 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; - - /** - * Open tabs on hover in drag and drop situations - */ - Optional<bool> open_tabs_on_drag_and_drop; - - /** - * Enable tab flashing - */ - Optional<bool> enable_tabs_flashing; - Optional<LLUIColor> tabs_flashing_color; - - /** - * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) - */ - Optional<S32> tab_icon_ctrl_pad; - - Params(); - }; + enum TabPosition + { + TOP, + BOTTOM, + LEFT + }; + typedef enum e_insertion_point + { + START, + END, + LEFT_OF_CURRENT, + RIGHT_OF_CURRENT + } eInsertionPoint; + + struct TabPositions : public LLInitParam::TypeValuesHelper<LLTabContainer::TabPosition, TabPositions> + { + static void declareValues(); + }; + + struct TabParams : public LLInitParam::Block<TabParams> + { + Optional<LLUIImage*> tab_top_image_unselected, + tab_top_image_selected, + tab_top_image_flash, + tab_bottom_image_unselected, + tab_bottom_image_selected, + tab_bottom_image_flash, + tab_left_image_unselected, + tab_left_image_selected, + tab_left_image_flash; + TabParams(); + }; + + struct Params + : public LLInitParam::Block<Params, LLPanel::Params> + { + Optional<TabPosition, TabPositions> tab_position; + Optional<S32> tab_width, + tab_min_width, + tab_max_width, + tab_height, + label_pad_bottom, + label_pad_left; + + Optional<bool> hide_tabs; + Optional<bool> hide_scroll_arrows; + Optional<S32> tab_padding_right; + + Optional<TabParams> first_tab, + 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; + + /** + * Open tabs on hover in drag and drop situations + */ + Optional<bool> open_tabs_on_drag_and_drop; + + /** + * Enable tab flashing + */ + Optional<bool> enable_tabs_flashing; + Optional<LLUIColor> tabs_flashing_color; + + /** + * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) + */ + Optional<S32> tab_icon_ctrl_pad; + + Optional<bool> use_tab_offset; + + Params(); + }; protected: - LLTabContainer(const Params&); - friend class LLUICtrlFactory; + LLTabContainer(const Params&); + friend class LLUICtrlFactory; public: - //LLTabContainer( const std::string& name, const LLRect& rect, TabPosition pos, - // BOOL bordered, BOOL is_vertical); - - /*virtual*/ ~LLTabContainer(); - - // from LLView - /*virtual*/ void setValue(const LLSD& value); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void draw(); - /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType type, void* cargo_data, - EAcceptance* accept, std::string& tooltip); - /*virtual*/ LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - /*virtual*/ LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; - /*virtual*/ void initFromParams(const LLPanel::Params& p); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); - /*virtual*/ BOOL postBuild(); - - struct TabPanelParams : public LLInitParam::Block<TabPanelParams> - { - Mandatory<LLPanel*> panel; - - Optional<std::string> label; - Optional<bool> select_tab, - is_placeholder; - Optional<S32> indent; - Optional<eInsertionPoint> insert_at; - Optional<void*> user_data; - - TabPanelParams() - : panel("panel", NULL), - label("label"), - select_tab("select_tab"), - is_placeholder("is_placeholder"), - indent("indent"), - insert_at("insert_at", END) - {} - }; - - void addTabPanel(LLPanel* panel); - void addTabPanel(const TabPanelParams& panel); - void addPlaceholder(LLPanel* child, const std::string& label); - void removeTabPanel( LLPanel* child ); - void lockTabs(S32 num_tabs = 0); - void unlockTabs(); - S32 getNumLockedTabs() { return mLockedTabCount; } - void enableTabButton(S32 which, BOOL enable); - void deleteAllTabs(); - LLPanel* getCurrentPanel(); - S32 getCurrentPanelIndex(); - S32 getTabCount(); - LLPanel* getPanelByIndex(S32 index); - S32 getIndexForPanel(LLPanel* panel); - S32 getPanelIndexByTitle(const std::string& title); - LLPanel* getPanelByName(const std::string& name); + //LLTabContainer( const std::string& name, const LLRect& rect, TabPosition pos, + // BOOL bordered, BOOL is_vertical); + + /*virtual*/ ~LLTabContainer(); + + // from LLView + /*virtual*/ void setValue(const LLSD& value); + + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void draw(); + /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType type, void* cargo_data, + EAcceptance* accept, std::string& tooltip); + /*virtual*/ LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + /*virtual*/ LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + /*virtual*/ void initFromParams(const LLPanel::Params& p); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + /*virtual*/ BOOL postBuild(); + + struct TabPanelParams : public LLInitParam::Block<TabPanelParams> + { + Mandatory<LLPanel*> panel; + + Optional<std::string> label; + Optional<bool> select_tab, + is_placeholder; + Optional<S32> indent; + Optional<eInsertionPoint> insert_at; + Optional<void*> user_data; + + TabPanelParams() + : panel("panel", NULL), + label("label"), + select_tab("select_tab"), + is_placeholder("is_placeholder"), + indent("indent"), + insert_at("insert_at", END) + {} + }; + + void addTabPanel(LLPanel* panel); + void addTabPanel(const TabPanelParams& panel); + void addPlaceholder(LLPanel* child, const std::string& label); + void removeTabPanel( LLPanel* child ); + void lockTabs(S32 num_tabs = 0); + void unlockTabs(); + S32 getNumLockedTabs() { return mLockedTabCount; } + void enableTabButton(S32 which, BOOL enable); + void deleteAllTabs(); + LLPanel* getCurrentPanel(); + S32 getCurrentPanelIndex(); + S32 getTabCount(); + LLPanel* getPanelByIndex(S32 index); + S32 getIndexForPanel(LLPanel* panel); + S32 getPanelIndexByTitle(const std::string& title); + LLPanel* getPanelByName(const std::string& name); S32 getTotalTabWidth() const; - void setCurrentTabName(const std::string& name); - - void selectFirstTab(); - void selectLastTab(); - void selectNextTab(); - void selectPrevTab(); - BOOL selectTabPanel( LLPanel* child ); - BOOL selectTab(S32 which); - BOOL selectTabByName(const std::string& title); + void setCurrentTabName(const std::string& name); + + void selectFirstTab(); + void selectLastTab(); + void selectNextTab(); + void selectPrevTab(); + BOOL selectTabPanel( LLPanel* child ); + BOOL selectTab(S32 which); + BOOL selectTabByName(const std::string& title); void setCurrentPanelIndex(S32 index) { mCurrentTabIdx = index; } - BOOL getTabPanelFlashing(LLPanel* child); - 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); - - void setTopBorderHeight(S32 height); - S32 getTopBorderHeight() const; - - void setRightTabBtnOffset( S32 offset ); - void setPanelTitle(S32 index, const std::string& title); - - TabPosition getTabPosition() const { return mTabPosition; } - void setMinTabWidth(S32 width) { mMinTabWidth = width; } - void setMaxTabWidth(S32 width) { mMaxTabWidth = width; } - S32 getMinTabWidth() const { return mMinTabWidth; } - S32 getMaxTabWidth() const { return mMaxTabWidth; } - - void setTabVisibility( LLPanel const *aPanel, bool ); - - void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); } - - void onTabBtn( const LLSD& data, LLPanel* panel ); - void onNextBtn(const LLSD& data); - void onNextBtnHeld(const LLSD& data); - void onPrevBtn(const LLSD& data); - void onPrevBtnHeld(const LLSD& data); - void onJumpFirstBtn( const LLSD& data ); - void onJumpLastBtn( const LLSD& data ); + BOOL getTabPanelFlashing(LLPanel* child); + 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); + + void setTopBorderHeight(S32 height); + S32 getTopBorderHeight() const; + + void setRightTabBtnOffset( S32 offset ); + void setPanelTitle(S32 index, const std::string& title); + + TabPosition getTabPosition() const { return mTabPosition; } + void setMinTabWidth(S32 width) { mMinTabWidth = width; } + void setMaxTabWidth(S32 width) { mMaxTabWidth = width; } + S32 getMinTabWidth() const { return mMinTabWidth; } + S32 getMaxTabWidth() const { return mMaxTabWidth; } + + void setTabVisibility( LLPanel const *aPanel, bool ); + + void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); } + + void onTabBtn( const LLSD& data, LLPanel* panel ); + void onNextBtn(const LLSD& data); + void onNextBtnHeld(const LLSD& data); + void onPrevBtn(const LLSD& data); + void onPrevBtnHeld(const LLSD& data); + void onJumpFirstBtn( const LLSD& data ); + void onJumpLastBtn( const LLSD& data ); private: - void initButtons(); - - BOOL setTab(S32 which); - - LLTabTuple* getTab(S32 index) { return mTabList[index]; } - LLTabTuple* getTabByPanel(LLPanel* child); - void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point); - - S32 getScrollPos() const { return mScrollPos; } - void setScrollPos(S32 pos) { mScrollPos = pos; } - S32 getMaxScrollPos() const { return mMaxScrollPos; } - void setMaxScrollPos(S32 pos) { mMaxScrollPos = pos; } - S32 getScrollPosPixels() const { return mScrollPosPixels; } - void setScrollPosPixels(S32 pixels) { mScrollPosPixels = pixels; } - - void setTabsHidden(BOOL hidden) { mTabsHidden = hidden; } - BOOL getTabsHidden() const { return mTabsHidden; } - - void scrollPrev() { mScrollPos = llmax(0, mScrollPos-1); } // No wrap - void scrollNext() { mScrollPos = llmin(mScrollPos+1, mMaxScrollPos); } // No wrap - - void updateMaxScrollPos(); - void commitHoveredButton(S32 x, S32 y); - - // updates tab button images given the tuple, tab position and the corresponding params - void update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos); - void reshapeTuple(LLTabTuple* tuple); - - // Variables - - typedef std::vector<LLTabTuple*> tuple_list_t; - tuple_list_t mTabList; - - S32 mCurrentTabIdx; - BOOL mTabsHidden; - BOOL mHideScrollArrows; - - BOOL mScrolled; - LLFrameTimer mScrollTimer; - S32 mScrollPos; - S32 mScrollPosPixels; - S32 mMaxScrollPos; - - LLTextBox* mTitleBox; - - S32 mTopBorderHeight; - TabPosition mTabPosition; - S32 mLockedTabCount; - S32 mMinTabWidth; - LLButton* mPrevArrowBtn; - LLButton* mNextArrowBtn; - - BOOL mIsVertical; - - // Horizontal specific - LLButton* mJumpPrevArrowBtn; - LLButton* mJumpNextArrowBtn; - - S32 mRightTabBtnOffset; // Extra room to the right of the tab buttons. - - S32 mMaxTabWidth; - S32 mTotalTabWidth; - S32 mTabHeight; - - // Padding under the text labels of tab buttons - S32 mLabelPadBottom; - // Padding to the left of text labels of tab buttons - S32 mLabelPadLeft; - - LLFrameTimer mDragAndDropDelayTimer; - - LLFontGL::HAlign mFontHalign; - const LLFontGL* mFont; - - TabParams mFirstTabParams; - TabParams mMiddleTabParams; - TabParams mLastTabParams; - - bool mCustomIconCtrlUsed; - bool mOpenTabsOnDragAndDrop; - bool mEnableTabsFlashing; - LLUIColor mTabsFlashingColor; - S32 mTabIconCtrlPad; - bool mUseTabEllipses; - LLFrameTimer mMouseDownTimer; + void initButtons(); + + BOOL setTab(S32 which); + + LLTabTuple* getTab(S32 index) { return mTabList[index]; } + LLTabTuple* getTabByPanel(LLPanel* child); + void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point); + + S32 getScrollPos() const { return mScrollPos; } + void setScrollPos(S32 pos) { mScrollPos = pos; } + S32 getMaxScrollPos() const { return mMaxScrollPos; } + void setMaxScrollPos(S32 pos) { mMaxScrollPos = pos; } + S32 getScrollPosPixels() const { return mScrollPosPixels; } + void setScrollPosPixels(S32 pixels) { mScrollPosPixels = pixels; } + + void setTabsHidden(BOOL hidden) { mTabsHidden = hidden; } + BOOL getTabsHidden() const { return mTabsHidden; } + + void scrollPrev() { mScrollPos = llmax(0, mScrollPos-1); } // No wrap + void scrollNext() { mScrollPos = llmin(mScrollPos+1, mMaxScrollPos); } // No wrap + + void updateMaxScrollPos(); + void commitHoveredButton(S32 x, S32 y); + + // updates tab button images given the tuple, tab position and the corresponding params + void update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos); + void reshapeTuple(LLTabTuple* tuple); + + // Variables + + typedef std::vector<LLTabTuple*> tuple_list_t; + tuple_list_t mTabList; + + S32 mCurrentTabIdx; + BOOL mTabsHidden; + BOOL mHideScrollArrows; + + BOOL mScrolled; + LLFrameTimer mScrollTimer; + S32 mScrollPos; + S32 mScrollPosPixels; + S32 mMaxScrollPos; + + LLTextBox* mTitleBox; + + S32 mTopBorderHeight; + TabPosition mTabPosition; + S32 mLockedTabCount; + S32 mMinTabWidth; + LLButton* mPrevArrowBtn; + LLButton* mNextArrowBtn; + + BOOL mIsVertical; + + // Horizontal specific + LLButton* mJumpPrevArrowBtn; + LLButton* mJumpNextArrowBtn; + + S32 mRightTabBtnOffset; // Extra room to the right of the tab buttons. + + S32 mMaxTabWidth; + S32 mTotalTabWidth; + S32 mTabHeight; + + // Padding under the text labels of tab buttons + S32 mLabelPadBottom; + // Padding to the left of text labels of tab buttons + S32 mLabelPadLeft; + + LLFrameTimer mDragAndDropDelayTimer; + + LLFontGL::HAlign mFontHalign; + const LLFontGL* mFont; + + TabParams mFirstTabParams; + TabParams mMiddleTabParams; + TabParams mLastTabParams; + + bool mCustomIconCtrlUsed; + bool mOpenTabsOnDragAndDrop; + bool mEnableTabsFlashing; + LLUIColor mTabsFlashingColor; + S32 mTabIconCtrlPad; + bool mUseTabEllipses; + LLFrameTimer mMouseDownTimer; + + bool mUseTabOffset; }; #endif // LL_TABCONTAINER_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 50feee8a47..c1eedf93a7 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lltextbase.cpp * @author Martin Reddy * @brief The base class of text box/editor, providing Url handling support @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2009-2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,79 +47,79 @@ #include "llwindow.h" #include <boost/bind.hpp> -const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds -const S32 CURSOR_THICKNESS = 2; -const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. +const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds +const S32 CURSOR_THICKNESS = 2; +const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. -LLTextBase::line_info::line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num) -: mDocIndexStart(index_start), - mDocIndexEnd(index_end), - mRect(rect), - mLineNum(line_num) +LLTextBase::line_info::line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num) +: mDocIndexStart(index_start), + mDocIndexEnd(index_end), + mRect(rect), + mLineNum(line_num) {} bool LLTextBase::compare_segment_end::operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const { - // sort empty spans (e.g. 11-11) after previous non-empty spans (e.g. 5-11) - if (a->getEnd() == b->getEnd()) - { - return a->getStart() < b->getStart(); - } - else - { - return a->getEnd() < b->getEnd(); - } + // sort empty spans (e.g. 11-11) after previous non-empty spans (e.g. 5-11) + if (a->getEnd() == b->getEnd()) + { + return a->getStart() < b->getStart(); + } + else + { + return a->getEnd() < b->getEnd(); + } } // helper functors bool LLTextBase::compare_bottom::operator()(const S32& a, const LLTextBase::line_info& b) const { - return a > b.mRect.mBottom; // bottom of a is higher than bottom of b + return a > b.mRect.mBottom; // bottom of a is higher than bottom of b } bool LLTextBase::compare_bottom::operator()(const LLTextBase::line_info& a, const S32& b) const { - return a.mRect.mBottom > b; // bottom of a is higher than bottom of b + return a.mRect.mBottom > b; // bottom of a is higher than bottom of b } bool LLTextBase::compare_bottom::operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const { - return a.mRect.mBottom > b.mRect.mBottom; // bottom of a is higher than bottom of b + return a.mRect.mBottom > b.mRect.mBottom; // bottom of a is higher than bottom of b } // helper functors bool LLTextBase::compare_top::operator()(const S32& a, const LLTextBase::line_info& b) const { - return a > b.mRect.mTop; // top of a is higher than top of b + return a > b.mRect.mTop; // top of a is higher than top of b } bool LLTextBase::compare_top::operator()(const LLTextBase::line_info& a, const S32& b) const { - return a.mRect.mTop > b; // top of a is higher than top of b + return a.mRect.mTop > b; // top of a is higher than top of b } bool LLTextBase::compare_top::operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const { - return a.mRect.mTop > b.mRect.mTop; // top of a is higher than top of b + return a.mRect.mTop > b.mRect.mTop; // top of a is higher than top of b } struct LLTextBase::line_end_compare { - bool operator()(const S32& pos, const LLTextBase::line_info& info) const - { - return (pos < info.mDocIndexEnd); - } + bool operator()(const S32& pos, const LLTextBase::line_info& info) const + { + return (pos < info.mDocIndexEnd); + } - bool operator()(const LLTextBase::line_info& info, const S32& pos) const - { - return (info.mDocIndexEnd < pos); - } + bool operator()(const LLTextBase::line_info& info, const S32& pos) const + { + return (info.mDocIndexEnd < pos); + } - bool operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const - { - return (a.mDocIndexEnd < b.mDocIndexEnd); - } + bool operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const + { + return (a.mDocIndexEnd < b.mDocIndexEnd); + } }; @@ -132,230 +132,232 @@ struct LLTextBase::line_end_compare static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(&typeid(LLTextBase::Params), "textbase"); LLTextBase::LineSpacingParams::LineSpacingParams() -: multiple("multiple", 1.f), - pixels("pixels", 0) +: multiple("multiple", 1.f), + pixels("pixels", 0) { } LLTextBase::Params::Params() -: cursor_color("cursor_color"), - text_color("text_color"), - text_readonly_color("text_readonly_color"), - text_tentative_color("text_tentative_color"), - bg_visible("bg_visible", false), - border_visible("border_visible", false), - bg_readonly_color("bg_readonly_color"), - bg_writeable_color("bg_writeable_color"), - bg_focus_color("bg_focus_color"), - text_selected_color("text_selected_color"), - bg_selected_color("bg_selected_color"), - allow_scroll("allow_scroll", true), - plain_text("plain_text",false), - track_end("track_end", false), - read_only("read_only", false), - skip_link_underline("skip_link_underline", false), - spellcheck("spellcheck", false), - v_pad("v_pad", 0), - h_pad("h_pad", 0), - clip("clip", true), - clip_partial("clip_partial", true), - line_spacing("line_spacing"), - max_text_length("max_length", 255), - font_shadow("font_shadow"), - text_valign("text_valign"), - wrap("wrap"), - trusted_content("trusted_content", true), - always_show_icons("always_show_icons", false), - use_ellipses("use_ellipses", false), - use_color("use_color", true), - parse_urls("parse_urls", false), - force_urls_external("force_urls_external", false), - parse_highlights("parse_highlights", false) -{ - addSynonym(track_end, "track_bottom"); - addSynonym(wrap, "word_wrap"); - addSynonym(parse_urls, "allow_html"); -} - - -LLTextBase::LLTextBase(const LLTextBase::Params &p) -: LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)), - mURLClickSignal(NULL), - mIsFriendSignal(NULL), - mIsObjectBlockedSignal(NULL), - mMaxTextByteLength( p.max_text_length ), - mFont(p.font), - mFontShadow(p.font_shadow), - mPopupMenuHandle(), - mReadOnly(p.read_only), - mSkipTripleClick(false), - mSkipLinkUnderline(p.skip_link_underline), - mSpellCheck(p.spellcheck), - mSpellCheckStart(-1), - mSpellCheckEnd(-1), - mCursorColor(p.cursor_color), - mFgColor(p.text_color), - mBorderVisible( p.border_visible ), - mReadOnlyFgColor(p.text_readonly_color), - mTentativeFgColor(p.text_tentative_color()), - mWriteableBgColor(p.bg_writeable_color), - mReadOnlyBgColor(p.bg_readonly_color), - mFocusBgColor(p.bg_focus_color), - mTextSelectedColor(p.text_selected_color), - mSelectedBGColor(p.bg_selected_color), - mReflowIndex(S32_MAX), - mCursorPos( 0 ), - mScrollNeeded(FALSE), - mDesiredXPixel(-1), - mHPad(p.h_pad), - mVPad(p.v_pad), - mHAlign(p.font_halign), - mVAlign(p.font_valign), - mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()), - mLineSpacingMult(p.line_spacing.multiple), - mLineSpacingPixels(p.line_spacing.pixels), - mClip(p.clip), - mClipPartial(p.clip_partial && !p.allow_scroll), - mTrustedContent(p.trusted_content), - mAlwaysShowIcons(p.always_show_icons), - mTrackEnd( p.track_end ), - mScrollIndex(-1), - mSelectionStart( 0 ), - mSelectionEnd( 0 ), - mIsSelecting( FALSE ), - mPlainText ( p.plain_text ), - mWordWrap(p.wrap), - mUseEllipses( p.use_ellipses ), - mUseColor(p.use_color), - mParseHTML(p.parse_urls), - mForceUrlsExternal(p.force_urls_external), - mParseHighlights(p.parse_highlights), - mBGVisible(p.bg_visible), - mScroller(NULL), - mStyleDirty(true) -{ - if(p.allow_scroll) - { - LLScrollContainer::Params scroll_params; - scroll_params.name = "text scroller"; - scroll_params.rect = getLocalRect(); - scroll_params.follows.flags = FOLLOWS_ALL; - scroll_params.is_opaque = false; - scroll_params.mouse_opaque = false; - scroll_params.min_auto_scroll_rate = 200; - scroll_params.max_auto_scroll_rate = 800; - scroll_params.border_visible = p.border_visible; - mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params); - addChild(mScroller); - } - - LLView::Params view_params; - view_params.name = "text_contents"; - view_params.rect = LLRect(0, 500, 500, 0); - view_params.mouse_opaque = false; - - mDocumentView = LLUICtrlFactory::create<LLView>(view_params); - if (mScroller) - { - mScroller->addChild(mDocumentView); - } - else - { - addChild(mDocumentView); - } - - if (mSpellCheck) - { - LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLTextBase::onSpellCheckSettingsChange, this)); - } - mSpellCheckTimer.reset(); - - createDefaultSegment(); - - updateRects(); +: cursor_color("cursor_color"), + text_color("text_color"), + text_readonly_color("text_readonly_color"), + text_tentative_color("text_tentative_color"), + bg_visible("bg_visible", false), + border_visible("border_visible", false), + bg_readonly_color("bg_readonly_color"), + bg_writeable_color("bg_writeable_color"), + bg_focus_color("bg_focus_color"), + text_selected_color("text_selected_color"), + bg_selected_color("bg_selected_color"), + allow_scroll("allow_scroll", true), + plain_text("plain_text",false), + track_end("track_end", false), + read_only("read_only", false), + skip_link_underline("skip_link_underline", false), + spellcheck("spellcheck", false), + v_pad("v_pad", 0), + h_pad("h_pad", 0), + clip("clip", true), + clip_partial("clip_partial", true), + line_spacing("line_spacing"), + max_text_length("max_length", 255), + font_shadow("font_shadow"), + text_valign("text_valign"), + wrap("wrap"), + trusted_content("trusted_content", true), + always_show_icons("always_show_icons", false), + use_ellipses("use_ellipses", false), + use_emoji("use_emoji", true), + use_color("use_color", true), + parse_urls("parse_urls", false), + force_urls_external("force_urls_external", false), + parse_highlights("parse_highlights", false) +{ + addSynonym(track_end, "track_bottom"); + addSynonym(wrap, "word_wrap"); + addSynonym(parse_urls, "allow_html"); +} + + +LLTextBase::LLTextBase(const LLTextBase::Params &p) +: LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)), + mURLClickSignal(NULL), + mIsFriendSignal(NULL), + mIsObjectBlockedSignal(NULL), + mMaxTextByteLength( p.max_text_length ), + mFont(p.font), + mFontShadow(p.font_shadow), + mPopupMenuHandle(), + mReadOnly(p.read_only), + mSkipTripleClick(false), + mSkipLinkUnderline(p.skip_link_underline), + mSpellCheck(p.spellcheck), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), + mCursorColor(p.cursor_color), + mFgColor(p.text_color), + mBorderVisible( p.border_visible ), + mReadOnlyFgColor(p.text_readonly_color), + mTentativeFgColor(p.text_tentative_color()), + mWriteableBgColor(p.bg_writeable_color), + mReadOnlyBgColor(p.bg_readonly_color), + mFocusBgColor(p.bg_focus_color), + mTextSelectedColor(p.text_selected_color), + mSelectedBGColor(p.bg_selected_color), + mReflowIndex(S32_MAX), + mCursorPos( 0 ), + mScrollNeeded(FALSE), + mDesiredXPixel(-1), + mHPad(p.h_pad), + mVPad(p.v_pad), + mHAlign(p.font_halign), + mVAlign(p.font_valign), + mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()), + mLineSpacingMult(p.line_spacing.multiple), + mLineSpacingPixels(p.line_spacing.pixels), + mClip(p.clip), + mClipPartial(p.clip_partial && !p.allow_scroll), + mTrustedContent(p.trusted_content), + mAlwaysShowIcons(p.always_show_icons), + mTrackEnd( p.track_end ), + mScrollIndex(-1), + mSelectionStart( 0 ), + mSelectionEnd( 0 ), + mIsSelecting( FALSE ), + mPlainText ( p.plain_text ), + mWordWrap(p.wrap), + mUseEllipses( p.use_ellipses ), + mUseEmoji(p.use_emoji), + mUseColor(p.use_color), + mParseHTML(p.parse_urls), + mForceUrlsExternal(p.force_urls_external), + mParseHighlights(p.parse_highlights), + mBGVisible(p.bg_visible), + mScroller(NULL), + mStyleDirty(true) +{ + if(p.allow_scroll) + { + LLScrollContainer::Params scroll_params; + scroll_params.name = "text scroller"; + scroll_params.rect = getLocalRect(); + scroll_params.follows.flags = FOLLOWS_ALL; + scroll_params.is_opaque = false; + scroll_params.mouse_opaque = false; + scroll_params.min_auto_scroll_rate = 200; + scroll_params.max_auto_scroll_rate = 800; + scroll_params.border_visible = p.border_visible; + mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params); + addChild(mScroller); + } + + LLView::Params view_params; + view_params.name = "text_contents"; + view_params.rect = LLRect(0, 500, 500, 0); + view_params.mouse_opaque = false; + + mDocumentView = LLUICtrlFactory::create<LLView>(view_params); + if (mScroller) + { + mScroller->addChild(mDocumentView); + } + else + { + addChild(mDocumentView); + } + + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLTextBase::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); + + createDefaultSegment(); + + updateRects(); } LLTextBase::~LLTextBase() { - mSegments.clear(); - LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); - if (menu) - { - menu->die(); - mPopupMenuHandle.markDead(); - } - delete mURLClickSignal; - delete mIsFriendSignal; - delete mIsObjectBlockedSignal; + mSegments.clear(); + LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } + delete mURLClickSignal; + delete mIsFriendSignal; + delete mIsObjectBlockedSignal; } void LLTextBase::initFromParams(const LLTextBase::Params& p) { - LLUICtrl::initFromParams(p); - resetDirty(); // Update saved text state - updateSegments(); + LLUICtrl::initFromParams(p); + resetDirty(); // Update saved text state + updateSegments(); - // HACK: work around enabled == readonly design bug -- RN - // setEnabled will modify our read only status, so do this after - // LLTextBase::initFromParams - if (p.read_only.isProvided()) - { - mReadOnly = p.read_only; - } + // HACK: work around enabled == readonly design bug -- RN + // setEnabled will modify our read only status, so do this after + // LLTextBase::initFromParams + if (p.read_only.isProvided()) + { + mReadOnly = p.read_only; + } } bool LLTextBase::truncate() { - BOOL did_truncate = FALSE; - - // First rough check - if we're less than 1/4th the size, we're OK - if (getLength() >= S32(mMaxTextByteLength / 4)) - { - // Have to check actual byte size - S32 utf8_byte_size = 0; - LLSD value = getViewModel()->getValue(); - if (value.type() == LLSD::TypeString) - { - // save a copy for strings. - utf8_byte_size = value.size(); - } - else - { - // non string LLSDs need explicit conversion to string - utf8_byte_size = value.asString().size(); - } - - if ( utf8_byte_size > mMaxTextByteLength ) - { - // Truncate safely in UTF-8 - std::string temp_utf8_text = value.asString(); - temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength ); - LLWString text = utf8str_to_wstring( temp_utf8_text ); - // remove extra bit of current string, to preserve formatting, etc. - removeStringNoUndo(text.size(), getWText().size() - text.size()); - did_truncate = TRUE; - } - } - - return did_truncate; + BOOL did_truncate = FALSE; + + // First rough check - if we're less than 1/4th the size, we're OK + if (getLength() >= S32(mMaxTextByteLength / 4)) + { + // Have to check actual byte size + S32 utf8_byte_size = 0; + LLSD value = getViewModel()->getValue(); + if (value.type() == LLSD::TypeString) + { + // save a copy for strings. + utf8_byte_size = value.size(); + } + else + { + // non string LLSDs need explicit conversion to string + utf8_byte_size = value.asString().size(); + } + + if ( utf8_byte_size > mMaxTextByteLength ) + { + // Truncate safely in UTF-8 + std::string temp_utf8_text = value.asString(); + temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength ); + LLWString text = utf8str_to_wstring( temp_utf8_text ); + // remove extra bit of current string, to preserve formatting, etc. + removeStringNoUndo(text.size(), getWText().size() - text.size()); + did_truncate = TRUE; + } + } + + return did_truncate; } const LLStyle::Params& LLTextBase::getStyleParams() { - //FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html - //and eliminate color member values - if (mStyleDirty) - { - mStyle - .color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor - .readonly_color(LLUIColor(&mReadOnlyFgColor)) - .selected_color(LLUIColor(&mTextSelectedColor)) - .font(mFont) - .drop_shadow(mFontShadow); - mStyleDirty = false; - } - return mStyle; + //FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html + //and eliminate color member values + if (mStyleDirty) + { + mStyle + .color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor + .readonly_color(LLUIColor(&mReadOnlyFgColor)) + .selected_color(LLUIColor(&mTextSelectedColor)) + .font(mFont) + .drop_shadow(mFontShadow); + mStyleDirty = false; + } + return mStyle; } void LLTextBase::beforeValueChange() @@ -465,21 +467,21 @@ void LLTextBase::drawSelectionBackground() if (hasSelection() && !mLineInfoList.empty()) { std::vector<LLRect> selection_rects = getSelectionRects(); - - // Draw the selection box (we're using a box instead of reversing the colors on the selected text). - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - const LLColor4& color = mSelectedBGColor; - F32 alpha = hasFocus() ? 0.7f : 0.3f; - alpha *= getDrawContext().mAlpha; - - LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha); + + // Draw the selection box (we're using a box instead of reversing the colors on the selected text). + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + const LLColor4& color = mSelectedBGColor; + F32 alpha = hasFocus() ? 0.7f : 0.3f; + alpha *= getDrawContext().mAlpha; + + LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha); LLRect content_display_rect = getVisibleDocumentRect(); - for (std::vector<LLRect>::iterator rect_it = selection_rects.begin(); - rect_it != selection_rects.end(); - ++rect_it) - { - LLRect selection_rect = *rect_it; + for (std::vector<LLRect>::iterator rect_it = selection_rects.begin(); + rect_it != selection_rects.end(); + ++rect_it) + { + LLRect selection_rect = *rect_it; if (mScroller) { // If scroller is On content_display_rect has correct rect and safe to use as is @@ -522,317 +524,317 @@ void LLTextBase::drawSelectionBackground() } selection_rect.translate(h_delta, v_delta); } - gl_rect_2d(selection_rect, selection_color); - } - } + gl_rect_2d(selection_rect, selection_color); + } + } } void LLTextBase::drawCursor() { - F32 alpha = getDrawContext().mAlpha; - - if( hasFocus() - && gFocusMgr.getAppHasFocus() - && !mReadOnly) - { - const LLWString &wtext = getWText(); - const llwchar* text = wtext.c_str(); - - LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); - cursor_rect.translate(-1, 0); - segment_set_t::iterator seg_it = getSegIterContaining(mCursorPos); - - // take style from last segment - LLTextSegmentPtr segmentp; - - if (seg_it != mSegments.end()) - { - segmentp = *seg_it; - } - else - { - return; - } - - // Draw the cursor - // (Flash the cursor every half second starting a fixed time after the last keystroke) - F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32(); - if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) ) - { - - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) - { - S32 segment_width = 0; - S32 segment_height = 0; - segmentp->getDimensions(mCursorPos - segmentp->getStart(), 1, segment_width, segment_height); - S32 width = llmax(CURSOR_THICKNESS, segment_width); - cursor_rect.mRight = cursor_rect.mLeft + width; - } - else - { - cursor_rect.mRight = cursor_rect.mLeft + CURSOR_THICKNESS; - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLColor4 cursor_color = mCursorColor.get() % alpha; - gGL.color4fv( cursor_color.mV ); - - gl_rect_2d(cursor_rect); - - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n') - { - LLColor4 text_color; - const LLFontGL* fontp; - text_color = segmentp->getColor(); - fontp = segmentp->getStyle()->getFont(); - fontp->render(text, mCursorPos, cursor_rect, - LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha), - LLFontGL::LEFT, mTextVAlign, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - 1); - } - - // Make sure the IME is in the right place - LLRect screen_pos = calcScreenRect(); - LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) ); - - ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]); - ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]); - getWindow()->setLanguageTextInput( ime_pos ); - } - } + F32 alpha = getDrawContext().mAlpha; + + if( hasFocus() + && gFocusMgr.getAppHasFocus() + && !mReadOnly) + { + const LLWString &wtext = getWText(); + const llwchar* text = wtext.c_str(); + + LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); + cursor_rect.translate(-1, 0); + segment_set_t::iterator seg_it = getSegIterContaining(mCursorPos); + + // take style from last segment + LLTextSegmentPtr segmentp; + + if (seg_it != mSegments.end()) + { + segmentp = *seg_it; + } + else + { + return; + } + + // Draw the cursor + // (Flash the cursor every half second starting a fixed time after the last keystroke) + F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32(); + if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) ) + { + + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) + { + S32 segment_width = 0; + S32 segment_height = 0; + segmentp->getDimensions(mCursorPos - segmentp->getStart(), 1, segment_width, segment_height); + S32 width = llmax(CURSOR_THICKNESS, segment_width); + cursor_rect.mRight = cursor_rect.mLeft + width; + } + else + { + cursor_rect.mRight = cursor_rect.mLeft + CURSOR_THICKNESS; + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLColor4 cursor_color = mCursorColor.get() % alpha; + gGL.color4fv( cursor_color.mV ); + + gl_rect_2d(cursor_rect); + + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n') + { + LLColor4 text_color; + const LLFontGL* fontp; + text_color = segmentp->getColor(); + fontp = segmentp->getStyle()->getFont(); + fontp->render(text, mCursorPos, cursor_rect, + LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha), + LLFontGL::LEFT, mTextVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + 1); + } + + // Make sure the IME is in the right place + LLRect screen_pos = calcScreenRect(); + LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) ); + + ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]); + ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]); + getWindow()->setLanguageTextInput( ime_pos ); + } + } } void LLTextBase::drawText() { - S32 text_len = getLength(); - - if (text_len <= 0 && mLabel.empty()) - { - return; - } - else if (useLabel()) - { - text_len = mLabel.getWString().length(); - } - - S32 selection_left = -1; - S32 selection_right = -1; - // Draw selection even if we don't have keyboard focus for search/replace - if( hasSelection()) - { - selection_left = llmin( mSelectionStart, mSelectionEnd ); - selection_right = llmax( mSelectionStart, mSelectionEnd ); - } - - std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); - S32 first_line = line_range.first; - S32 last_line = line_range.second; - if (first_line >= last_line) - { - return; - } - - S32 line_start = getLineStart(first_line); - // find first text segment that spans top of visible portion of text buffer - segment_set_t::iterator seg_iter = getSegIterContaining(line_start); - if (seg_iter == mSegments.end()) - { - return; - } - - // Perform spell check if needed - if ( (getSpellCheck()) && (getWText().length() > 2) ) - { - // Calculate start and end indices for the spell checking range - S32 start = line_start; - S32 end = getLineEnd(last_line); - - if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) - { - const LLWString& wstrText = getWText(); - mMisspellRanges.clear(); - - segment_set_t::const_iterator seg_it = getSegIterContaining(start); - while (mSegments.end() != seg_it) - { - LLTextSegmentPtr text_segment = *seg_it; - if ( (text_segment.isNull()) || (text_segment->getStart() >= end) ) - { - break; - } - - if (!text_segment->canEdit()) - { - ++seg_it; - continue; - } - - // Combine adjoining text segments into one - U32 seg_start = text_segment->getStart(), seg_end = llmin(text_segment->getEnd(), end); - while (mSegments.end() != ++seg_it) - { - text_segment = *seg_it; - if ( (text_segment.isNull()) || (!text_segment->canEdit()) || (text_segment->getStart() >= end) ) - { - break; - } - seg_end = llmin(text_segment->getEnd(), end); - } - - // Find the start of the first word - U32 word_start = seg_start, word_end = -1; - U32 text_length = wstrText.length(); - while ( (word_start < text_length) && (!LLStringOps::isAlpha(wstrText[word_start])) ) - { - word_start++; - } - - // Iterate over all words in the text block and check them one by one - while (word_start < seg_end) - { - // Find the end of the current word (special case handling for "'" when it's used as a contraction) - word_end = word_start + 1; - while ( (word_end < seg_end) && - ((LLWStringUtil::isPartOfWord(wstrText[word_end])) || - ((L'\'' == wstrText[word_end]) && - (LLStringOps::isAlnum(wstrText[word_end - 1])) && (LLStringOps::isAlnum(wstrText[word_end + 1])))) ) - { - word_end++; - } - if (word_end > seg_end) - { - break; - } - - if (word_start < text_length && word_end <= text_length && word_end > word_start) - { - std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start)); - - // Don't process words shorter than 3 characters - if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) - { - mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end)); - } - } - - // Find the start of the next word - word_start = word_end + 1; - while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) ) - { - word_start++; - } - } - } - - mSpellCheckStart = start; - mSpellCheckEnd = end; - } - } - else - { - mMisspellRanges.clear(); - } - - LLTextSegmentPtr cur_segment = *seg_iter; - - std::list<std::pair<U32, U32> >::const_iterator misspell_it = std::lower_bound(mMisspellRanges.begin(), mMisspellRanges.end(), std::pair<U32, U32>(line_start, 0)); - for (S32 cur_line = first_line; cur_line < last_line; cur_line++) - { - S32 next_line = cur_line + 1; - line_info& line = mLineInfoList[cur_line]; - - S32 next_start = -1; - S32 line_end = text_len; - - if (next_line < getLineCount()) - { - next_start = getLineStart(next_line); - line_end = next_start; - } + S32 text_len = getLength(); + + if (text_len <= 0 && mLabel.empty()) + { + return; + } + else if (useLabel()) + { + text_len = mLabel.getWString().length(); + } + + S32 selection_left = -1; + S32 selection_right = -1; + // Draw selection even if we don't have keyboard focus for search/replace + if( hasSelection()) + { + selection_left = llmin( mSelectionStart, mSelectionEnd ); + selection_right = llmax( mSelectionStart, mSelectionEnd ); + } + + std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); + S32 first_line = line_range.first; + S32 last_line = line_range.second; + if (first_line >= last_line) + { + return; + } + + S32 line_start = getLineStart(first_line); + // find first text segment that spans top of visible portion of text buffer + segment_set_t::iterator seg_iter = getSegIterContaining(line_start); + if (seg_iter == mSegments.end()) + { + return; + } + + // Perform spell check if needed + if ( (getSpellCheck()) && (getWText().length() > 2) ) + { + // Calculate start and end indices for the spell checking range + S32 start = line_start; + S32 end = getLineEnd(last_line); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) + { + const LLWString& wstrText = getWText(); + mMisspellRanges.clear(); + + segment_set_t::const_iterator seg_it = getSegIterContaining(start); + while (mSegments.end() != seg_it) + { + LLTextSegmentPtr text_segment = *seg_it; + if ( (text_segment.isNull()) || (text_segment->getStart() >= end) ) + { + break; + } + + if (!text_segment->canEdit()) + { + ++seg_it; + continue; + } + + // Combine adjoining text segments into one + U32 seg_start = text_segment->getStart(), seg_end = llmin(text_segment->getEnd(), end); + while (mSegments.end() != ++seg_it) + { + text_segment = *seg_it; + if ( (text_segment.isNull()) || (!text_segment->canEdit()) || (text_segment->getStart() >= end) ) + { + break; + } + seg_end = llmin(text_segment->getEnd(), end); + } + + // Find the start of the first word + U32 word_start = seg_start, word_end = -1; + U32 text_length = wstrText.length(); + while ( (word_start < text_length) && (!LLStringOps::isAlpha(wstrText[word_start])) ) + { + word_start++; + } + + // Iterate over all words in the text block and check them one by one + while (word_start < seg_end) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < seg_end) && + ((LLWStringUtil::isPartOfWord(wstrText[word_end])) || + ((L'\'' == wstrText[word_end]) && + (LLStringOps::isAlnum(wstrText[word_end - 1])) && (LLStringOps::isAlnum(wstrText[word_end + 1])))) ) + { + word_end++; + } + if (word_end > seg_end) + { + break; + } + + if (word_start < text_length && word_end <= text_length && word_end > word_start) + { + std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start)); + + // Don't process words shorter than 3 characters + if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { + mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end)); + } + } + + // Find the start of the next word + word_start = word_end + 1; + while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) ) + { + word_start++; + } + } + } + + mSpellCheckStart = start; + mSpellCheckEnd = end; + } + } + else + { + mMisspellRanges.clear(); + } + + LLTextSegmentPtr cur_segment = *seg_iter; + + std::list<std::pair<U32, U32> >::const_iterator misspell_it = std::lower_bound(mMisspellRanges.begin(), mMisspellRanges.end(), std::pair<U32, U32>(line_start, 0)); + for (S32 cur_line = first_line; cur_line < last_line; cur_line++) + { + S32 next_line = cur_line + 1; + line_info& line = mLineInfoList[cur_line]; + + S32 next_start = -1; + S32 line_end = text_len; + + if (next_line < getLineCount()) + { + next_start = getLineStart(next_line); + line_end = next_start; + } LLRectf text_rect(line.mRect.mLeft, line.mRect.mTop, line.mRect.mRight, line.mRect.mBottom); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - // draw a single line of text - S32 seg_start = line_start; - while( seg_start < line_end ) - { - while( cur_segment->getEnd() <= seg_start ) - { - seg_iter++; - if (seg_iter == mSegments.end()) - { - LL_WARNS() << "Ran off the segmentation end!" << LL_ENDL; - - return; - } - cur_segment = *seg_iter; - } - - S32 seg_end = llmin(line_end, cur_segment->getEnd()); - S32 clipped_end = seg_end - cur_segment->getStart(); - - if (mUseEllipses // using ellipses - && clipped_end == line_end // last segment on line - && next_line == last_line // this is the last visible line - && last_line < (S32)mLineInfoList.size()) // and there is more text to display - { - // more lines of text to go, but we can't fit them - // so shrink text rect to force ellipses - text_rect.mRight -= 2; - } - - // Draw squiggly lines under any visible misspelled words - while ( (mMisspellRanges.end() != misspell_it) && (misspell_it->first < seg_end) && (misspell_it->second > seg_start) ) - { - // Skip the current word if the user is still busy editing it - if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) - { - ++misspell_it; - continue; - } - - U32 misspell_start = llmax<U32>(misspell_it->first, seg_start), misspell_end = llmin<U32>(misspell_it->second, seg_end); - S32 squiggle_start = 0, squiggle_end = 0, pony = 0; - cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony); - cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony); - squiggle_start += text_rect.mLeft; - - pony = (squiggle_end + 3) / 6; - squiggle_start += squiggle_end / 2 - pony * 3; - squiggle_end = squiggle_start + pony * 6; - - S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight(); - - gGL.color4ub(255, 0, 0, 200); - while (squiggle_start + 1 < squiggle_end) - { - gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2); - if (squiggle_start + 3 < squiggle_end) - { - gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1); - } - squiggle_start += 4; - } - - if (misspell_it->second > seg_end) - { - break; - } - ++misspell_it; - } - - text_rect.mLeft = cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect); - - seg_start = clipped_end + cur_segment->getStart(); - } - - line_start = next_start; - } + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + // draw a single line of text + S32 seg_start = line_start; + while( seg_start < line_end ) + { + while( cur_segment->getEnd() <= seg_start ) + { + seg_iter++; + if (seg_iter == mSegments.end()) + { + LL_WARNS() << "Ran off the segmentation end!" << LL_ENDL; + + return; + } + cur_segment = *seg_iter; + } + + S32 seg_end = llmin(line_end, cur_segment->getEnd()); + S32 clipped_end = seg_end - cur_segment->getStart(); + + if (mUseEllipses // using ellipses + && clipped_end == line_end // last segment on line + && next_line == last_line // this is the last visible line + && last_line < (S32)mLineInfoList.size()) // and there is more text to display + { + // more lines of text to go, but we can't fit them + // so shrink text rect to force ellipses + text_rect.mRight -= 2; + } + + // Draw squiggly lines under any visible misspelled words + while ( (mMisspellRanges.end() != misspell_it) && (misspell_it->first < seg_end) && (misspell_it->second > seg_start) ) + { + // Skip the current word if the user is still busy editing it + if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) + { + ++misspell_it; + continue; + } + + U32 misspell_start = llmax<U32>(misspell_it->first, seg_start), misspell_end = llmin<U32>(misspell_it->second, seg_end); + S32 squiggle_start = 0, squiggle_end = 0, pony = 0; + cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony); + cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony); + squiggle_start += text_rect.mLeft; + + pony = (squiggle_end + 3) / 6; + squiggle_start += squiggle_end / 2 - pony * 3; + squiggle_end = squiggle_start + pony * 6; + + S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight(); + + gGL.color4ub(255, 0, 0, 200); + while (squiggle_start + 1 < squiggle_end) + { + gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2); + if (squiggle_start + 3 < squiggle_end) + { + gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1); + } + squiggle_start += 4; + } + + if (misspell_it->second > seg_end) + { + break; + } + ++misspell_it; + } + + text_rect.mLeft = cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect); + + seg_start = clipped_end + cur_segment->getStart(); + } + + line_start = next_start; + } } /////////////////////////////////////////////////////////////////// @@ -842,766 +844,754 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s { beforeValueChange(); - S32 old_len = getLength(); // length() returns character length - S32 insert_len = wstr.length(); - - pos = getEditableIndex(pos, true); - - segment_set_t::iterator seg_iter = getEditableSegIterContaining(pos); - - LLTextSegmentPtr default_segment; - - LLTextSegmentPtr segmentp; - if (seg_iter != mSegments.end()) - { - segmentp = *seg_iter; - } - else - { - //segmentp = mSegments.back(); - return pos; - } - - if (segmentp->canEdit()) - { - segmentp->setEnd(segmentp->getEnd() + insert_len); - if (seg_iter != mSegments.end()) - { - ++seg_iter; - } - } - else - { - // create default editable segment to hold new text - LLStyleConstSP sp(new LLStyle(getStyleParams())); - default_segment = new LLNormalTextSegment( sp, pos, pos + insert_len, *this); - } - - // shift remaining segments to right - for(;seg_iter != mSegments.end(); ++seg_iter) - { - LLTextSegmentPtr segmentp = *seg_iter; - segmentp->setStart(segmentp->getStart() + insert_len); - segmentp->setEnd(segmentp->getEnd() + insert_len); - } - - // insert new segments - if (segments) - { - if (default_segment.notNull()) - { - // potentially overwritten by segments passed in - insertSegment(default_segment); - } - for (segment_vec_t::iterator seg_iter = segments->begin(); - seg_iter != segments->end(); - ++seg_iter) - { - LLTextSegment* segmentp = *seg_iter; - insertSegment(segmentp); - } - } - - // Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) - { - LLStyleSP emoji_style; - LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; - for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++) - { - llwchar code = wstr[text_kitty]; - bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); - if (isEmoji) - { - if (!emoji_style) - { - emoji_style = new LLStyle(getStyleParams()); - emoji_style->setFont(LLFontGL::getFontEmoji()); - } - - S32 new_seg_start = pos + text_kitty; - insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this)); - } - } - } - - getViewModel()->getEditableDisplay().insert(pos, wstr); - - if ( truncate() ) - { - insert_len = getLength() - old_len; - } - - onValueChange(pos, pos + insert_len); - needsReflow(pos); - - return insert_len; + S32 old_len = getLength(); // length() returns character length + S32 insert_len = wstr.length(); + + pos = getEditableIndex(pos, true); + + segment_set_t::iterator seg_iter = getEditableSegIterContaining(pos); + + LLTextSegmentPtr default_segment; + + LLTextSegmentPtr segmentp; + if (seg_iter != mSegments.end()) + { + segmentp = *seg_iter; + } + else + { + //segmentp = mSegments.back(); + return pos; + } + + if (segmentp->canEdit()) + { + segmentp->setEnd(segmentp->getEnd() + insert_len); + if (seg_iter != mSegments.end()) + { + ++seg_iter; + } + } + else + { + // create default editable segment to hold new text + LLStyleConstSP sp(new LLStyle(getStyleParams())); + default_segment = new LLNormalTextSegment( sp, pos, pos + insert_len, *this); + } + + // shift remaining segments to right + for(;seg_iter != mSegments.end(); ++seg_iter) + { + LLTextSegmentPtr segmentp = *seg_iter; + segmentp->setStart(segmentp->getStart() + insert_len); + segmentp->setEnd(segmentp->getEnd() + insert_len); + } + + // insert new segments + if (segments) + { + if (default_segment.notNull()) + { + // potentially overwritten by segments passed in + insertSegment(default_segment); + } + for (segment_vec_t::iterator seg_iter = segments->begin(); + seg_iter != segments->end(); + ++seg_iter) + { + LLTextSegment* segmentp = *seg_iter; + insertSegment(segmentp); + } + } + + // Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) + if (mUseEmoji) + { + LLStyleSP emoji_style; + LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; + for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++) + { + llwchar code = wstr[text_kitty]; + bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); + if (isEmoji) + { + if (!emoji_style) + { + emoji_style = new LLStyle(getStyleParams()); + emoji_style->setFont(LLFontGL::getFontEmojiLarge()); + } + + S32 new_seg_start = pos + text_kitty; + insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this)); + } + } + } + + getViewModel()->getEditableDisplay().insert(pos, wstr); + + if ( truncate() ) + { + insert_len = getLength() - old_len; + } + + onValueChange(pos, pos + insert_len); + needsReflow(pos); + + return insert_len; } S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { beforeValueChange(); - segment_set_t::iterator seg_iter = getSegIterContaining(pos); - while(seg_iter != mSegments.end()) - { - LLTextSegmentPtr segmentp = *seg_iter; - S32 end = pos + length; - if (segmentp->getStart() < pos) - { - // deleting from middle of segment - if (segmentp->getEnd() > end) - { - segmentp->setEnd(segmentp->getEnd() - length); - } - // truncating segment - else - { - segmentp->setEnd(pos); - } - } - else if (segmentp->getStart() < end) - { - // deleting entire segment - if (segmentp->getEnd() <= end) - { - // remove segment - segmentp->unlinkFromDocument(this); - segment_set_t::iterator seg_to_erase(seg_iter++); - mSegments.erase(seg_to_erase); - continue; - } - // deleting head of segment - else - { - segmentp->setStart(pos); - segmentp->setEnd(segmentp->getEnd() - length); - } - } - else - { - // shifting segments backward to fill deleted portion - segmentp->setStart(segmentp->getStart() - length); - segmentp->setEnd(segmentp->getEnd() - length); - } - ++seg_iter; - } - - getViewModel()->getEditableDisplay().erase(pos, length); - - // recreate default segment in case we erased everything - createDefaultSegment(); - - onValueChange(pos, pos); - needsReflow(pos); - - return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length + segment_set_t::iterator seg_iter = getSegIterContaining(pos); + while(seg_iter != mSegments.end()) + { + LLTextSegmentPtr segmentp = *seg_iter; + S32 end = pos + length; + if (segmentp->getStart() < pos) + { + // deleting from middle of segment + if (segmentp->getEnd() > end) + { + segmentp->setEnd(segmentp->getEnd() - length); + } + // truncating segment + else + { + segmentp->setEnd(pos); + } + } + else if (segmentp->getStart() < end) + { + // deleting entire segment + if (segmentp->getEnd() <= end) + { + // remove segment + segmentp->unlinkFromDocument(this); + segment_set_t::iterator seg_to_erase(seg_iter++); + mSegments.erase(seg_to_erase); + continue; + } + // deleting head of segment + else + { + segmentp->setStart(pos); + segmentp->setEnd(segmentp->getEnd() - length); + } + } + else + { + // shifting segments backward to fill deleted portion + segmentp->setStart(segmentp->getStart() - length); + segmentp->setEnd(segmentp->getEnd() - length); + } + ++seg_iter; + } + + getViewModel()->getEditableDisplay().erase(pos, length); + + // recreate default segment in case we erased everything + createDefaultSegment(); + + onValueChange(pos, pos); + needsReflow(pos); + + return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length } S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc) { beforeValueChange(); - if (pos > (S32)getLength()) - { - return 0; - } - getViewModel()->getEditableDisplay()[pos] = wc; + if (pos > (S32)getLength()) + { + return 0; + } + getViewModel()->getEditableDisplay()[pos] = wc; - onValueChange(pos, pos + 1); - needsReflow(pos); + onValueChange(pos, pos + 1); + needsReflow(pos); - return 1; + return 1; } void LLTextBase::createDefaultSegment() { - // ensures that there is always at least one segment - if (mSegments.empty()) - { - LLStyleConstSP sp(new LLStyle(getStyleParams())); - LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this); - mSegments.insert(default_segment); - default_segment->linkToDocument(this); - } + // ensures that there is always at least one segment + if (mSegments.empty()) + { + LLStyleConstSP sp(new LLStyle(getStyleParams())); + LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this); + mSegments.insert(default_segment); + default_segment->linkToDocument(this); + } } void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) { - if (segment_to_insert.isNull()) - { - return; - } - - 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(); - // split old at start point for new segment - cur_segmentp->setEnd(segment_to_insert->getStart()); - // advance to next segment - // insert remainder of old segment - LLStyleConstSP sp = cur_segmentp->getStyle(); - LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( sp, segment_to_insert->getStart(), old_segment_end, *this); - mSegments.insert(cur_seg_iter, remainder_segment); - remainder_segment->linkToDocument(this); - // insert new segment before remainder of old segment - mSegments.insert(cur_seg_iter, segment_to_insert); - - segment_to_insert->linkToDocument(this); - // at this point, there will be two overlapping segments owning the text - // associated with the incoming segment - } - else - { - mSegments.insert(cur_seg_iter, segment_to_insert); - segment_to_insert->linkToDocument(this); - } - - // now delete/truncate remaining segments as necessary - // cur_seg_iter points to segment before incoming segment - while(cur_seg_iter != mSegments.end()) - { - cur_segmentp = *cur_seg_iter; - if (cur_segmentp == segment_to_insert) - { - ++cur_seg_iter; - continue; - } - - if (cur_segmentp->getStart() >= segment_to_insert->getStart()) - { - if(cur_segmentp->getEnd() <= segment_to_insert->getEnd()) - { - cur_segmentp->unlinkFromDocument(this); - // grab copy of iterator to erase, and bump it - segment_set_t::iterator seg_to_erase(cur_seg_iter++); - mSegments.erase(seg_to_erase); - continue; - } - else - { - // last overlapping segment, clip to end of incoming segment - // and stop traversal - cur_segmentp->setStart(segment_to_insert->getEnd()); - break; - } - } - ++cur_seg_iter; - } - } - - // layout potentially changed - needsReflow(reflow_start_index); -} - -//virtual + if (segment_to_insert.isNull()) + { + return; + } + + 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(); + // split old at start point for new segment + cur_segmentp->setEnd(segment_to_insert->getStart()); + // advance to next segment + // insert remainder of old segment + LLStyleConstSP sp = cur_segmentp->getStyle(); + LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( sp, segment_to_insert->getStart(), old_segment_end, *this); + mSegments.insert(cur_seg_iter, remainder_segment); + remainder_segment->linkToDocument(this); + // insert new segment before remainder of old segment + mSegments.insert(cur_seg_iter, segment_to_insert); + + segment_to_insert->linkToDocument(this); + // at this point, there will be two overlapping segments owning the text + // associated with the incoming segment + } + else + { + mSegments.insert(cur_seg_iter, segment_to_insert); + segment_to_insert->linkToDocument(this); + } + + // now delete/truncate remaining segments as necessary + // cur_seg_iter points to segment before incoming segment + while(cur_seg_iter != mSegments.end()) + { + cur_segmentp = *cur_seg_iter; + if (cur_segmentp == segment_to_insert) + { + ++cur_seg_iter; + continue; + } + + if (cur_segmentp->getStart() >= segment_to_insert->getStart()) + { + if(cur_segmentp->getEnd() <= segment_to_insert->getEnd()) + { + cur_segmentp->unlinkFromDocument(this); + // grab copy of iterator to erase, and bump it + segment_set_t::iterator seg_to_erase(cur_seg_iter++); + mSegments.erase(seg_to_erase); + continue; + } + else + { + // last overlapping segment, clip to end of incoming segment + // and stop traversal + cur_segmentp->setStart(segment_to_insert->getEnd()); + break; + } + } + ++cur_seg_iter; + } + } + + // layout potentially changed + needsReflow(reflow_start_index); +} + +//virtual BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) { - // handle triple click - if (!mTripleClickTimer.hasExpired()) - { - if (mSkipTripleClick) - { - return TRUE; - } - - S32 real_line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = -1; - S32 line_end = -1; - for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); - it != end_it; - ++it) - { - if (it->mLineNum < real_line) - { - continue; - } - if (it->mLineNum > real_line) - { - break; - } - if (line_start == -1) - { - line_start = it->mDocIndexStart; - } - line_end = it->mDocIndexEnd; - line_end = llclamp(line_end, 0, getLength()); - } - - if (line_start == -1) - { - return TRUE; - } - - mSelectionEnd = line_start; - mSelectionStart = line_end; - setCursorPos(line_start); - - return TRUE; - } - - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleMouseDown(x, y, mask)) - { - return TRUE; - } - - return LLUICtrl::handleMouseDown(x, y, mask); -} - -//virtual + // handle triple click + if (!mTripleClickTimer.hasExpired()) + { + if (mSkipTripleClick) + { + return TRUE; + } + + S32 real_line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = -1; + S32 line_end = -1; + for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); + it != end_it; + ++it) + { + if (it->mLineNum < real_line) + { + continue; + } + if (it->mLineNum > real_line) + { + break; + } + if (line_start == -1) + { + line_start = it->mDocIndexStart; + } + line_end = it->mDocIndexEnd; + line_end = llclamp(line_end, 0, getLength()); + } + + if (line_start == -1) + { + return TRUE; + } + + mSelectionEnd = line_start; + mSelectionStart = line_end; + setCursorPos(line_start); + + return TRUE; + } + + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleMouseDown(x, y, mask)) + { + return TRUE; + } + + return LLUICtrl::handleMouseDown(x, y, mask); +} + +//virtual BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (hasMouseCapture() && cur_segment && cur_segment->handleMouseUp(x, y, mask)) - { - // Did we just click on a link? - if (mURLClickSignal - && cur_segment->getStyle() - && cur_segment->getStyle()->isLink()) - { - // *TODO: send URL here? - (*mURLClickSignal)(this, LLSD() ); - } - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (hasMouseCapture() && cur_segment && cur_segment->handleMouseUp(x, y, mask)) + { + // Did we just click on a link? + if (mURLClickSignal + && cur_segment->getStyle() + && cur_segment->getStyle()->isLink()) + { + // *TODO: send URL here? + (*mURLClickSignal)(this, LLSD() ); + } + return TRUE; + } - return LLUICtrl::handleMouseUp(x, y, mask); + return LLUICtrl::handleMouseUp(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleMiddleMouseDown(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleMiddleMouseDown(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleMiddleMouseDown(x, y, mask); + return LLUICtrl::handleMiddleMouseDown(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleMiddleMouseUp(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleMiddleMouseUp(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleMiddleMouseUp(x, y, mask); + return LLUICtrl::handleMiddleMouseUp(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleRightMouseDown(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleRightMouseDown(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleRightMouseDown(x, y, mask); + return LLUICtrl::handleRightMouseDown(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleRightMouseUp(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleRightMouseUp(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleRightMouseUp(x, y, mask); + return LLUICtrl::handleRightMouseUp(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) { - //Don't start triple click timer if user have clicked on scrollbar - mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); - if (x >= mVisibleTextRect.mLeft && x <= mVisibleTextRect.mRight - && y >= mVisibleTextRect.mBottom && y <= mVisibleTextRect.mTop) - { - mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); - } + //Don't start triple click timer if user have clicked on scrollbar + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + if (x >= mVisibleTextRect.mLeft && x <= mVisibleTextRect.mRight + && y >= mVisibleTextRect.mBottom && y <= mVisibleTextRect.mTop) + { + mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + } - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleDoubleClick(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleDoubleClick(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleDoubleClick(x, y, mask); + return LLUICtrl::handleDoubleClick(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleHover(x, y, mask)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleHover(x, y, mask)) + { + return TRUE; + } - return LLUICtrl::handleHover(x, y, mask); + return LLUICtrl::handleHover(x, y, mask); } -//virtual +//virtual BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleScrollWheel(x, y, clicks)) - { - return TRUE; - } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleScrollWheel(x, y, clicks)) + { + return TRUE; + } - return LLUICtrl::handleScrollWheel(x, y, clicks); + return LLUICtrl::handleScrollWheel(x, y, clicks); } -//virtual +//virtual BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) { - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); - if (cur_segment && cur_segment->handleToolTip(x, y, mask)) - { - return TRUE; - } - - return LLUICtrl::handleToolTip(x, y, mask); -} - -//virtual -const std::string LLTextBase::getToolTip() const -{ - if (sDebugUnicode) + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->handleToolTip(x, y, mask)) { - std::string text = getText(); - std::string tooltip = utf8str_showBytesUTF8(text); - return tooltip; + return TRUE; } - return LLUICtrl::getToolTip(); + return LLUICtrl::handleToolTip(x, y, mask); } -//virtual +//virtual void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) { - if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape) - { - bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; + if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape) + { + bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; + + LLUICtrl::reshape( width, height, called_from_parent ); - LLUICtrl::reshape( width, height, called_from_parent ); + if (mScroller && scrolled_to_bottom && mTrackEnd) + { + // keep bottom of text buffer visible + // do this here as well as in reflow to handle case + // where shrinking from top, which causes buffer to temporarily + // not be scrolled to the bottom, since the scroll index + // specified the _top_ of the visible document region + mScroller->goToBottom(); + } - if (mScroller && scrolled_to_bottom && mTrackEnd) - { - // keep bottom of text buffer visible - // do this here as well as in reflow to handle case - // where shrinking from top, which causes buffer to temporarily - // not be scrolled to the bottom, since the scroll index - // specified the _top_ of the visible document region - mScroller->goToBottom(); - } + // do this first after reshape, because other things depend on + // up-to-date mVisibleTextRect + updateRects(); - // do this first after reshape, because other things depend on - // up-to-date mVisibleTextRect - updateRects(); - - needsReflow(); - } + needsReflow(); + } } -//virtual +//virtual void LLTextBase::draw() { - // reflow if needed, on demand - reflow(); - - // then update scroll position, as cursor may have moved - if (!mReadOnly) - { - updateScrollFromCursor(); - } - - LLRect text_rect; - if (mScroller) - { - mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &text_rect, this); - } - else - { - LLRect visible_lines_rect; - std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); - for (S32 i = line_range.first; i < line_range.second; i++) - { - if (visible_lines_rect.isEmpty()) - { - visible_lines_rect = mLineInfoList[i].mRect; - } - else - { - visible_lines_rect.unionWith(mLineInfoList[i].mRect); - } - } - text_rect = visible_lines_rect; - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); - } - - if (mBGVisible) - { - F32 alpha = getCurrentTransparency(); - // clip background rect against extents, if we support scrolling - LLRect bg_rect = mVisibleTextRect; - if (mScroller) - { - bg_rect.intersectWith(text_rect); - } - LLColor4 bg_color = mReadOnly - ? mReadOnlyBgColor.get() - : hasFocus() - ? mFocusBgColor.get() - : mWriteableBgColor.get(); - gl_rect_2d(text_rect, bg_color % alpha, TRUE); - } - - // Draw highlighted if needed - if( ll::ui::SearchableControl::getHighlighted() ) - { - LLColor4 bg_color = ll::ui::SearchableControl::getHighlightColor(); - LLRect bg_rect = mVisibleTextRect; - if( mScroller ) - bg_rect.intersectWith( text_rect ); - - gl_rect_2d( text_rect, bg_color, TRUE ); - } - - bool should_clip = mClip || mScroller != NULL; - { LLLocalClipRect clip(text_rect, should_clip); - - // draw document view - if (mScroller) - { - drawChild(mScroller); - } - else - { - drawChild(mDocumentView); - } - - drawSelectionBackground(); - drawText(); - drawCursor(); - } - - mDocumentView->setVisibleDirect(FALSE); - LLUICtrl::draw(); - mDocumentView->setVisibleDirect(TRUE); + // reflow if needed, on demand + reflow(); + + // then update scroll position, as cursor may have moved + if (!mReadOnly) + { + updateScrollFromCursor(); + } + + LLRect text_rect; + if (mScroller) + { + mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &text_rect, this); + } + else + { + LLRect visible_lines_rect; + std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); + for (S32 i = line_range.first; i < line_range.second; i++) + { + if (visible_lines_rect.isEmpty()) + { + visible_lines_rect = mLineInfoList[i].mRect; + } + else + { + visible_lines_rect.unionWith(mLineInfoList[i].mRect); + } + } + text_rect = visible_lines_rect; + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); + } + + if (mBGVisible) + { + F32 alpha = getCurrentTransparency(); + // clip background rect against extents, if we support scrolling + LLRect bg_rect = mVisibleTextRect; + if (mScroller) + { + bg_rect.intersectWith(text_rect); + } + LLColor4 bg_color = mReadOnly + ? mReadOnlyBgColor.get() + : hasFocus() + ? mFocusBgColor.get() + : mWriteableBgColor.get(); + gl_rect_2d(text_rect, bg_color % alpha, TRUE); + } + + // Draw highlighted if needed + if( ll::ui::SearchableControl::getHighlighted() ) + { + LLColor4 bg_color = ll::ui::SearchableControl::getHighlightColor(); + LLRect bg_rect = mVisibleTextRect; + if( mScroller ) + bg_rect.intersectWith( text_rect ); + + gl_rect_2d( text_rect, bg_color, TRUE ); + } + + bool should_clip = mClip || mScroller != NULL; + { LLLocalClipRect clip(text_rect, should_clip); + + // draw document view + if (mScroller) + { + drawChild(mScroller); + } + else + { + drawChild(mDocumentView); + } + + drawSelectionBackground(); + drawText(); + drawCursor(); + } + + mDocumentView->setVisibleDirect(FALSE); + LLUICtrl::draw(); + mDocumentView->setVisibleDirect(TRUE); } //virtual void LLTextBase::setColor( const LLColor4& c ) { - mFgColor = c; - mStyleDirty = true; + mFgColor = c; + mStyleDirty = true; } -//virtual +//virtual void LLTextBase::setReadOnlyColor(const LLColor4 &c) { - mReadOnlyFgColor = c; - mStyleDirty = true; + mReadOnlyFgColor = c; + mStyleDirty = true; } //virtual void LLTextBase::onVisibilityChange( BOOL new_visibility ) { - LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); - if(!new_visibility && menu) - { - menu->hide(); - } - LLUICtrl::onVisibilityChange(new_visibility); + LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); + if(!new_visibility && menu) + { + menu->hide(); + } + LLUICtrl::onVisibilityChange(new_visibility); } //virtual void LLTextBase::setValue(const LLSD& value ) { - setText(value.asString()); + setText(value.asString()); } //virtual -BOOL LLTextBase::canDeselect() const -{ - return hasSelection(); +BOOL LLTextBase::canDeselect() const +{ + return hasSelection(); } //virtual void LLTextBase::deselect() { - mSelectionStart = 0; - mSelectionEnd = 0; - mIsSelecting = FALSE; + mSelectionStart = 0; + mSelectionEnd = 0; + mIsSelecting = FALSE; } bool LLTextBase::getSpellCheck() const { - return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); } const std::string& LLTextBase::getSuggestion(U32 index) const { - return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; } U32 LLTextBase::getSuggestionCount() const { - return mSuggestionList.size(); + return mSuggestionList.size(); } void LLTextBase::replaceWithSuggestion(U32 index) { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) - { - deselect(); - // Insert the suggestion in its place - LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); - insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index])); + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + deselect(); + // Insert the suggestion in its place + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index])); - // Delete the misspelled word - removeStringNoUndo(it->first + (S32)suggestion.length(), it->second - it->first); + // Delete the misspelled word + removeStringNoUndo(it->first + (S32)suggestion.length(), it->second - it->first); - setCursorPos(it->first + (S32)suggestion.length()); - onSpellCheckPerformed(); + setCursorPos(it->first + (S32)suggestion.length()); + onSpellCheckPerformed(); - break; - } - } - mSpellCheckStart = mSpellCheckEnd = -1; + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; } void LLTextBase::addToDictionary() { - if (canAddToDictionary()) - { - LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); - } + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } } bool LLTextBase::canAddToDictionary() const { - return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); } void LLTextBase::addToIgnore() { - if (canAddToIgnore()) - { - LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); - } + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } } bool LLTextBase::canAddToIgnore() const { - return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); } std::string LLTextBase::getMisspelledWord(U32 pos) const { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= pos) && (it->second >= pos) ) - { - return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first)); - } - } - return LLStringUtil::null; + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first)); + } + } + return LLStringUtil::null; } bool LLTextBase::isMisspelledWord(U32 pos) const { - for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) - { - if ( (it->first <= pos) && (it->second >= pos) ) - { - return true; - } - } - return false; + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return true; + } + } + return false; } void LLTextBase::onSpellCheckSettingsChange() { - // Recheck the spelling on every change - mMisspellRanges.clear(); - mSpellCheckStart = mSpellCheckEnd = -1; + // Recheck the spelling on every change + mMisspellRanges.clear(); + mSpellCheckStart = mSpellCheckEnd = -1; } void LLTextBase::onFocusReceived() { - LLUICtrl::onFocusReceived(); - if (!getLength() && !mLabel.empty()) - { - // delete label which is LLLabelTextSegment - clearSegments(); - } + LLUICtrl::onFocusReceived(); + if (!getLength() && !mLabel.empty()) + { + // delete label which is LLLabelTextSegment + clearSegments(); + } } void LLTextBase::onFocusLost() { - LLUICtrl::onFocusLost(); - if (!getLength() && !mLabel.empty()) - { - resetLabel(); - } + LLUICtrl::onFocusLost(); + if (!getLength() && !mLabel.empty()) + { + resetLabel(); + } } // Sets the scrollbar from the cursor position void LLTextBase::updateScrollFromCursor() { - // Update scroll position even in read-only mode (when there's no cursor displayed) - // because startOfDoc()/endOfDoc() modify cursor position. See EXT-736. + // Update scroll position even in read-only mode (when there's no cursor displayed) + // because startOfDoc()/endOfDoc() modify cursor position. See EXT-736. - if (!mScrollNeeded || !mScroller) - { - return; - } - mScrollNeeded = FALSE; + if (!mScrollNeeded || !mScroller) + { + return; + } + mScrollNeeded = FALSE; - // scroll so that the cursor is at the top of the page - LLRect scroller_doc_window = getVisibleDocumentRect(); - LLRect cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); - mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5)); + // scroll so that the cursor is at the top of the page + LLRect scroller_doc_window = getVisibleDocumentRect(); + LLRect cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); + mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5)); } S32 LLTextBase::getLeftOffset(S32 width) { - switch (mHAlign) - { - case LLFontGL::LEFT: - return mHPad; - case LLFontGL::HCENTER: - return mHPad + llmax(0, (mVisibleTextRect.getWidth() - width - mHPad) / 2); - case LLFontGL::RIGHT: + switch (mHAlign) + { + case LLFontGL::LEFT: + return mHPad; + case LLFontGL::HCENTER: + return mHPad + llmax(0, (mVisibleTextRect.getWidth() - width - mHPad) / 2); + case LLFontGL::RIGHT: { // Font's rendering rounds string size, if value gets rounded // down last symbol might not have enough space to render, @@ -1609,83 +1599,83 @@ S32 LLTextBase::getLeftOffset(S32 width) const S32 right_padding = 1; return llmax(mHPad, mVisibleTextRect.getWidth() - width - right_padding); } - default: - return mHPad; - } + default: + return mHPad; + } } void LLTextBase::reflow() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - updateSegments(); - - if (mReflowIndex == S32_MAX) - { - return; - } - - bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; - - LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); - bool follow_selection = getLocalRect().overlaps(cursor_rect); // cursor is (potentially) visible - - // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing - cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop; - cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom; - - S32 first_line = getFirstVisibleLine(); - - // if scroll anchor not on first line, update it to first character of first line - if ((first_line < mLineInfoList.size()) - && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart - || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd)) - { - mScrollIndex = mLineInfoList[first_line].mDocIndexStart; - } - LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex); - // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing - first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop; - first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom; - - S32 reflow_count = 0; - while(mReflowIndex < S32_MAX) - { - // we can get into an infinite loop if the document height does not monotonically increase - // with decreasing width (embedded ui elements with alternate layouts). In that case, - // we want to stop reflowing after 2 iterations. We use 2, since we need to handle the case - // of introducing a vertical scrollbar causing a reflow with less width. We should also always - // use an even number of iterations to avoid user visible oscillation of the layout - if(++reflow_count > 2) - { - LL_DEBUGS() << "Breaking out of reflow due to possible infinite loop in " << getName() << LL_ENDL; - break; - } - - 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 - if (mWordWrap) - { - mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); - } - - S32 cur_top = 0; - - segment_set_t::iterator seg_iter = mSegments.begin(); - S32 seg_offset = 0; - S32 line_start_index = 0; - const F32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin - F32 remaining_pixels = text_available_width; - S32 line_count = 0; - - // find and erase line info structs starting at start_index and going to end of document - if (!mLineInfoList.empty()) - { - // find first element whose end comes after start_index - line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare()); + updateSegments(); + + if (mReflowIndex == S32_MAX) + { + return; + } + + bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; + + LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); + bool follow_selection = getLocalRect().overlaps(cursor_rect); // cursor is (potentially) visible + + // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing + cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop; + cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom; + + S32 first_line = getFirstVisibleLine(); + + // if scroll anchor not on first line, update it to first character of first line + if ((first_line < mLineInfoList.size()) + && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart + || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd)) + { + mScrollIndex = mLineInfoList[first_line].mDocIndexStart; + } + LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex); + // store in top-left relative coordinates to avoid issues with horizontal scrollbar appearing and disappearing + first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop; + first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom; + + S32 reflow_count = 0; + while(mReflowIndex < S32_MAX) + { + // we can get into an infinite loop if the document height does not monotonically increase + // with decreasing width (embedded ui elements with alternate layouts). In that case, + // we want to stop reflowing after 2 iterations. We use 2, since we need to handle the case + // of introducing a vertical scrollbar causing a reflow with less width. We should also always + // use an even number of iterations to avoid user visible oscillation of the layout + if(++reflow_count > 2) + { + LL_DEBUGS() << "Breaking out of reflow due to possible infinite loop in " << getName() << LL_ENDL; + break; + } + + 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 + if (mWordWrap) + { + mDocumentView->reshape(mVisibleTextRect.getWidth(), mDocumentView->getRect().getHeight()); + } + + S32 cur_top = 0; + + segment_set_t::iterator seg_iter = mSegments.begin(); + S32 seg_offset = 0; + S32 line_start_index = 0; + const F32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin + F32 remaining_pixels = text_available_width; + S32 line_count = 0; + + // find and erase line info structs starting at start_index and going to end of document + if (!mLineInfoList.empty()) + { + // find first element whose end comes after start_index + line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare()); if (iter != mLineInfoList.end()) { line_start_index = iter->mDocIndexStart; @@ -1694,425 +1684,425 @@ void LLTextBase::reflow() getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); mLineInfoList.erase(iter, mLineInfoList.end()); } - } - - S32 line_height = 0; - S32 seg_line_offset = line_count + 1; - - while(seg_iter != mSegments.end()) - { - LLTextSegmentPtr segment = *seg_iter; - - // track maximum height of any segment on this line - S32 cur_index = segment->getStart() + seg_offset; - - // ask segment how many character fit in remaining space - S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, ll_round(remaining_pixels)) : S32_MAX, - seg_offset, - cur_index - line_start_index, - S32_MAX, - line_count - seg_line_offset); - - F32 segment_width; - S32 segment_height; - bool force_newline = segment->getDimensionsF32(seg_offset, character_count, segment_width, segment_height); - // grow line height as necessary based on reported height of this segment - line_height = llmax(line_height, segment_height); - remaining_pixels -= segment_width; - - seg_offset += character_count; - - S32 last_segment_char_on_line = segment->getStart() + seg_offset; - - // Note: make sure text will fit in width - use ceil, but also make sure - // ceil is used only once per line - S32 text_actual_width = llceil(text_available_width - remaining_pixels); - S32 text_left = getLeftOffset(text_actual_width); - LLRect line_rect(text_left, - cur_top, - text_left + text_actual_width, - cur_top - line_height); - - // if we didn't finish the current segment... - if (last_segment_char_on_line < segment->getEnd()) - { - // add line info and keep going - mLineInfoList.push_back(line_info( - line_start_index, - last_segment_char_on_line, - line_rect, - line_count)); - - line_start_index = segment->getStart() + seg_offset; - cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - remaining_pixels = text_available_width; - line_height = 0; - } - // ...just consumed last segment.. - else if (++segment_set_t::iterator(seg_iter) == mSegments.end()) - { - mLineInfoList.push_back(line_info( - line_start_index, - last_segment_char_on_line, - line_rect, - line_count)); - cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - break; - } - // ...or finished a segment and there are segments remaining on this line - else - { - // subtract pixels used and increment segment - if (force_newline) - { - mLineInfoList.push_back(line_info( - line_start_index, - last_segment_char_on_line, - line_rect, - line_count)); - line_start_index = segment->getStart() + seg_offset; - cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - line_height = 0; - remaining_pixels = text_available_width; - } - ++seg_iter; - seg_offset = 0; - seg_line_offset = force_newline ? line_count + 1 : line_count; - } - if (force_newline) - { - line_count++; - } - } - - // calculate visible region for diplaying text - updateRects(); - - for (segment_set_t::iterator segment_it = mSegments.begin(); - segment_it != mSegments.end(); - ++segment_it) - { - LLTextSegmentPtr segmentp = *segment_it; - segmentp->updateLayout(*this); - - } - } - - // apply scroll constraints after reflowing text - if (!hasMouseCapture() && mScroller) - { - if (scrolled_to_bottom && mTrackEnd) - { - // keep bottom of text buffer visible - endOfDoc(); - } - else if (hasSelection() && follow_selection) - { - // keep cursor in same vertical position on screen when selecting text - LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); - LLRect old_cursor_rect = cursor_rect; - old_cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop; - old_cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom; - - mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect); - } - else - { - // keep first line of text visible - LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex); - - // pass in desired rect in the coordinate frame of the document viewport - LLRect old_first_char_rect = first_char_rect; - old_first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop; - old_first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom; - - mScroller->scrollToShowRect(new_first_char_rect, old_first_char_rect); - } - } - - // reset desired x cursor position - updateCursorXPos(); + } + + S32 line_height = 0; + S32 seg_line_offset = line_count + 1; + + while(seg_iter != mSegments.end()) + { + LLTextSegmentPtr segment = *seg_iter; + + // track maximum height of any segment on this line + S32 cur_index = segment->getStart() + seg_offset; + + // ask segment how many character fit in remaining space + S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, ll_round(remaining_pixels)) : S32_MAX, + seg_offset, + cur_index - line_start_index, + S32_MAX, + line_count - seg_line_offset); + + F32 segment_width; + S32 segment_height; + bool force_newline = segment->getDimensionsF32(seg_offset, character_count, segment_width, segment_height); + // grow line height as necessary based on reported height of this segment + line_height = llmax(line_height, segment_height); + remaining_pixels -= segment_width; + + seg_offset += character_count; + + S32 last_segment_char_on_line = segment->getStart() + seg_offset; + + // Note: make sure text will fit in width - use ceil, but also make sure + // ceil is used only once per line + S32 text_actual_width = llceil(text_available_width - remaining_pixels); + S32 text_left = getLeftOffset(text_actual_width); + LLRect line_rect(text_left, + cur_top, + text_left + text_actual_width, + cur_top - line_height); + + // if we didn't finish the current segment... + if (last_segment_char_on_line < segment->getEnd()) + { + // add line info and keep going + mLineInfoList.push_back(line_info( + line_start_index, + last_segment_char_on_line, + line_rect, + line_count)); + + line_start_index = segment->getStart() + seg_offset; + cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; + remaining_pixels = text_available_width; + line_height = 0; + } + // ...just consumed last segment.. + else if (++segment_set_t::iterator(seg_iter) == mSegments.end()) + { + mLineInfoList.push_back(line_info( + line_start_index, + last_segment_char_on_line, + line_rect, + line_count)); + cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; + break; + } + // ...or finished a segment and there are segments remaining on this line + else + { + // subtract pixels used and increment segment + if (force_newline) + { + mLineInfoList.push_back(line_info( + line_start_index, + last_segment_char_on_line, + line_rect, + line_count)); + line_start_index = segment->getStart() + seg_offset; + cur_top -= ll_round((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; + line_height = 0; + remaining_pixels = text_available_width; + } + ++seg_iter; + seg_offset = 0; + seg_line_offset = force_newline ? line_count + 1 : line_count; + } + if (force_newline) + { + line_count++; + } + } + + // calculate visible region for diplaying text + updateRects(); + + for (segment_set_t::iterator segment_it = mSegments.begin(); + segment_it != mSegments.end(); + ++segment_it) + { + LLTextSegmentPtr segmentp = *segment_it; + segmentp->updateLayout(*this); + + } + } + + // apply scroll constraints after reflowing text + if (!hasMouseCapture() && mScroller) + { + if (scrolled_to_bottom && mTrackEnd) + { + // keep bottom of text buffer visible + endOfDoc(); + } + else if (hasSelection() && follow_selection) + { + // keep cursor in same vertical position on screen when selecting text + LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); + LLRect old_cursor_rect = cursor_rect; + old_cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop; + old_cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom; + + mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect); + } + else + { + // keep first line of text visible + LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex); + + // pass in desired rect in the coordinate frame of the document viewport + LLRect old_first_char_rect = first_char_rect; + old_first_char_rect.mTop = mVisibleTextRect.mTop - first_char_rect.mTop; + old_first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom; + + mScroller->scrollToShowRect(new_first_char_rect, old_first_char_rect); + } + } + + // reset desired x cursor position + updateCursorXPos(); } LLRect LLTextBase::getTextBoundingRect() { - reflow(); - return mTextBoundingRect; + reflow(); + return mTextBoundingRect; } void LLTextBase::clearSegments() { - mSegments.clear(); - createDefaultSegment(); + mSegments.clear(); + createDefaultSegment(); } S32 LLTextBase::getLineStart( S32 line ) const { - S32 num_lines = getLineCount(); - if (num_lines == 0) - { - return 0; - } + S32 num_lines = getLineCount(); + if (num_lines == 0) + { + return 0; + } - line = llclamp(line, 0, num_lines-1); - return mLineInfoList[line].mDocIndexStart; + line = llclamp(line, 0, num_lines-1); + return mLineInfoList[line].mDocIndexStart; } S32 LLTextBase::getLineEnd( S32 line ) const { - S32 num_lines = getLineCount(); - if (num_lines == 0) - { - return 0; - } + S32 num_lines = getLineCount(); + if (num_lines == 0) + { + return 0; + } - line = llclamp(line, 0, num_lines-1); - return mLineInfoList[line].mDocIndexEnd; + line = llclamp(line, 0, num_lines-1); + return mLineInfoList[line].mDocIndexEnd; } S32 LLTextBase::getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap) const { - if (mLineInfoList.empty()) - { - return 0; - } - else - { - line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_index, line_end_compare()); - if (include_wordwrap) - { - return iter - mLineInfoList.begin(); - } - else - { - if (iter == mLineInfoList.end()) - { - return mLineInfoList.back().mLineNum; - } - else - { - return iter->mLineNum; - } - } - } + if (mLineInfoList.empty()) + { + return 0; + } + else + { + line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_index, line_end_compare()); + if (include_wordwrap) + { + return iter - mLineInfoList.begin(); + } + else + { + if (iter == mLineInfoList.end()) + { + return mLineInfoList.back().mLineNum; + } + else + { + return iter->mLineNum; + } + } + } } // Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line. S32 LLTextBase::getLineOffsetFromDocIndex( S32 startpos, bool include_wordwrap) const { - if (mLineInfoList.empty()) - { - return startpos; - } - else - { - line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), startpos, line_end_compare()); - return startpos - iter->mDocIndexStart; - } + if (mLineInfoList.empty()) + { + return startpos; + } + else + { + line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), startpos, line_end_compare()); + return startpos - iter->mDocIndexStart; + } } -S32 LLTextBase::getFirstVisibleLine() const +S32 LLTextBase::getFirstVisibleLine() const { - LLRect visible_region = getVisibleDocumentRect(); + LLRect visible_region = getVisibleDocumentRect(); - // binary search for line that starts before top of visible buffer - line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); + // binary search for line that starts before top of visible buffer + line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); - return iter - mLineInfoList.begin(); + return iter - mLineInfoList.begin(); } -std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible) +std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible) { - LLRect visible_region = getVisibleDocumentRect(); - line_list_t::const_iterator first_iter; - line_list_t::const_iterator last_iter; + LLRect visible_region = getVisibleDocumentRect(); + line_list_t::const_iterator first_iter; + line_list_t::const_iterator last_iter; - // make sure we have an up-to-date mLineInfoList - reflow(); + // make sure we have an up-to-date mLineInfoList + reflow(); - if (require_fully_visible) - { - first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top()); - last_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom()); - } - else - { - first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); - last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top()); - } - return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin()); + if (require_fully_visible) + { + first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top()); + last_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom()); + } + else + { + first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); + last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top()); + } + return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin()); } LLTextViewModel* LLTextBase::getViewModel() const { - return (LLTextViewModel*)mViewModel.get(); + return (LLTextViewModel*)mViewModel.get(); } -void LLTextBase::addDocumentChild(LLView* view) -{ - mDocumentView->addChild(view); +void LLTextBase::addDocumentChild(LLView* view) +{ + mDocumentView->addChild(view); } -void LLTextBase::removeDocumentChild(LLView* view) -{ - mDocumentView->removeChild(view); +void LLTextBase::removeDocumentChild(LLView* view) +{ + mDocumentView->removeChild(view); } void LLTextBase::updateSegments() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - createDefaultSegment(); + createDefaultSegment(); } void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const { - *seg_iter = getSegIterContaining(startpos); - if (*seg_iter == mSegments.end()) - { - *offsetp = 0; - } - else - { - *offsetp = startpos - (**seg_iter)->getStart(); - } + *seg_iter = getSegIterContaining(startpos); + if (*seg_iter == mSegments.end()) + { + *offsetp = 0; + } + else + { + *offsetp = startpos - (**seg_iter)->getStart(); + } } void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ) { - *seg_iter = getSegIterContaining(startpos); - if (*seg_iter == mSegments.end()) - { - *offsetp = 0; - } - else - { - *offsetp = startpos - (**seg_iter)->getStart(); - } + *seg_iter = getSegIterContaining(startpos); + if (*seg_iter == mSegments.end()) + { + *offsetp = 0; + } + else + { + *offsetp = startpos - (**seg_iter)->getStart(); + } } LLTextBase::segment_set_t::iterator LLTextBase::getEditableSegIterContaining(S32 index) { - segment_set_t::iterator it = getSegIterContaining(index); - segment_set_t::iterator orig_it = it; + segment_set_t::iterator it = getSegIterContaining(index); + segment_set_t::iterator orig_it = it; - if (it == mSegments.end()) return it; + if (it == mSegments.end()) return it; - if (!(*it)->canEdit() - && index == (*it)->getStart() - && it != mSegments.begin()) - { - it--; - if ((*it)->canEdit()) - { - return it; - } - } - return orig_it; + if (!(*it)->canEdit() + && index == (*it)->getStart() + && it != mSegments.begin()) + { + it--; + if ((*it)->canEdit()) + { + return it; + } + } + return orig_it; } LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaining(S32 index) const { - segment_set_t::const_iterator it = getSegIterContaining(index); - segment_set_t::const_iterator orig_it = it; - if (it == mSegments.end()) return it; + segment_set_t::const_iterator it = getSegIterContaining(index); + segment_set_t::const_iterator orig_it = it; + if (it == mSegments.end()) return it; - if (!(*it)->canEdit() - && index == (*it)->getStart() - && it != mSegments.begin()) - { - it--; - if ((*it)->canEdit()) - { - return it; - } - } - return orig_it; + if (!(*it)->canEdit() + && index == (*it)->getStart() + && it != mSegments.begin()) + { + it--; + if ((*it)->canEdit()) + { + return it; + } + } + return orig_it; } LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) { - static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); + static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); - // when there are no segments, we return the end iterator, which must be checked by caller - if (mSegments.size() <= 1) { return mSegments.begin(); } + // when there are no segments, we return the end iterator, which must be checked by caller + if (mSegments.size() <= 1) { return mSegments.begin(); } - index_segment->setStart(index); - index_segment->setEnd(index); - segment_set_t::iterator it = mSegments.upper_bound(index_segment); - return it; + index_segment->setStart(index); + index_segment->setEnd(index); + segment_set_t::iterator it = mSegments.upper_bound(index_segment); + return it; } LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const { - static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); + static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); - // when there are no segments, we return the end iterator, which must be checked by caller - if (mSegments.size() <= 1) { return mSegments.begin(); } + // when there are no segments, we return the end iterator, which must be checked by caller + if (mSegments.size() <= 1) { return mSegments.begin(); } - index_segment->setStart(index); - index_segment->setEnd(index); - LLTextBase::segment_set_t::const_iterator it = mSegments.upper_bound(index_segment); - return it; + index_segment->setStart(index); + index_segment->setEnd(index); + LLTextBase::segment_set_t::const_iterator it = mSegments.upper_bound(index_segment); + return it; } // Finds the text segment (if any) at the give local screen position LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line) { - // Find the cursor position at the requested local screen position - S32 offset = getDocIndexFromLocalCoord( x, y, FALSE, hit_past_end_of_line); - segment_set_t::iterator seg_iter = getSegIterContaining(offset); - if (seg_iter != mSegments.end()) - { - return *seg_iter; - } - else - { - return LLTextSegmentPtr(); - } + // Find the cursor position at the requested local screen position + S32 offset = getDocIndexFromLocalCoord( x, y, FALSE, hit_past_end_of_line); + segment_set_t::iterator seg_iter = getSegIterContaining(offset); + if (seg_iter != mSegments.end()) + { + return *seg_iter; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) { - // work out the XUI menu file to use for this url - LLUrlMatch match; - std::string url = in_url; - if (! LLUrlRegistry::instance().findUrl(url, match)) - { - return; - } - - std::string xui_file = match.getMenuName(); - if (xui_file.empty()) - { - return; - } - - // set up the callbacks for all of the potential menu items, N.B. we - // don't use const ref strings in callbacks in case url goes out of scope - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url)); - registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url)); - registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); - registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url, true)); - registrar.add("Url.Block", boost::bind(&LLUrlAction::blockObject, url)); - registrar.add("Url.Unblock", boost::bind(&LLUrlAction::unblockObject, url)); - registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); - registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); - registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url)); - registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url)); + // work out the XUI menu file to use for this url + LLUrlMatch match; + std::string url = in_url; + if (! LLUrlRegistry::instance().findUrl(url, match)) + { + return; + } + + std::string xui_file = match.getMenuName(); + if (xui_file.empty()) + { + return; + } + + // set up the callbacks for all of the potential menu items, N.B. we + // don't use const ref strings in callbacks in case url goes out of scope + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url)); + registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url)); + registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); + registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url, true)); + registrar.add("Url.Block", boost::bind(&LLUrlAction::blockObject, url)); + registrar.add("Url.Unblock", boost::bind(&LLUrlAction::unblockObject, url)); + registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); + registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); + registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url)); + registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url)); registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url)); - registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url)); - registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); - registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); - registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); + registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url)); + registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); + registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); + registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); - // create and return the context menu from the XUI file + // create and return the context menu from the XUI file LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); if (menu) @@ -2120,9 +2110,9 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) menu->die(); mPopupMenuHandle.markDead(); } - llassert(LLMenuGL::sMenuContainer != NULL); + llassert(LLMenuGL::sMenuContainer != NULL); menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLMenuHolderGL::child_registry_t::instance()); if (menu) { mPopupMenuHandle = menu->getHandle(); @@ -2159,188 +2149,188 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params) { - // clear out the existing text and segments - getViewModel()->setDisplay(LLWStringUtil::null); + // clear out the existing text and segments + getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); -// createDefaultSegment(); + clearSegments(); +// createDefaultSegment(); - deselect(); + deselect(); - // append the new text (supports Url linking) - std::string text(utf8str); - LLStringUtil::removeCRLF(text); + // append the new text (supports Url linking) + std::string text(utf8str); + LLStringUtil::removeCRLF(text); - // appendText modifies mCursorPos... - appendText(text, false, input_params); - // ...so move cursor to top after appending text - if (!mTrackEnd) - { - startOfDoc(); - } + // appendText modifies mCursorPos... + appendText(text, false, input_params); + // ...so move cursor to top after appending text + if (!mTrackEnd) + { + startOfDoc(); + } - onValueChange(0, getLength()); + onValueChange(0, getLength()); } -//virtual -std::string LLTextBase::getText() const +// virtual +const std::string& LLTextBase::getText() const { - return getViewModel()->getValue().asString(); + return getViewModel()->getStringValue(); } // IDEVO - icons can be UI image names or UUID sent from // server with avatar display name static LLUIImagePtr image_from_icon_name(const std::string& icon_name) { - if (LLUUID::validate(icon_name)) - { - return LLUI::getUIImageByID( LLUUID(icon_name) ); - } - else - { - return LLUI::getUIImage(icon_name); - } + if (LLUUID::validate(icon_name)) + { + return LLUI::getUIImageByID( LLUUID(icon_name) ); + } + else + { + return LLUI::getUIImage(icon_name); + } } void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - LLStyle::Params style_params(input_params); - style_params.fillFrom(getStyleParams()); - - S32 part = (S32)LLTextParser::WHOLE; - if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). - { - S32 start=0,end=0; - LLUrlMatch match; - std::string text = new_text; - while (LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons)) - { - start = match.getStart(); - end = match.getEnd()+1; - - LLStyle::Params link_params(style_params); - link_params.overwriteFrom(match.getStyle()); - - // output the text before the Url - if (start > 0) - { - if (part == (S32)LLTextParser::WHOLE || - part == (S32)LLTextParser::START) - { - part = (S32)LLTextParser::START; - } - else - { - part = (S32)LLTextParser::MIDDLE; - } - std::string subtext=text.substr(0,start); - appendAndHighlightText(subtext, part, style_params); - } - - // add icon before url if need - LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons); - if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) - { - setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); - } - - // output the styled Url - appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); - bool tooltip_required = !match.getTooltip().empty(); - - // set the tooltip for the Url label - if (tooltip_required) - { - setLastSegmentToolTip(match.getTooltip()); - } - - // show query part of url with gray color only for LLUrlEntryHTTP url entries - std::string label = match.getQuery(); - if (label.size()) - { - link_params.color = LLColor4::grey; - link_params.readonly_color = LLColor4::grey; - appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); - - // set the tooltip for the query part of url - if (tooltip_required) - { - setLastSegmentToolTip(match.getTooltip()); - } - } - - // move on to the rest of the text after the Url - if (end < (S32)text.length()) - { - text = text.substr(end,text.length() - end); - end=0; - part=(S32)LLTextParser::END; - } - else - { - break; - } - } - if (part != (S32)LLTextParser::WHOLE) - part=(S32)LLTextParser::END; - if (end < (S32)text.length()) - appendAndHighlightText(text, part, style_params); - } - else - { - appendAndHighlightText(new_text, part, style_params); - } + LLStyle::Params style_params(input_params); + style_params.fillFrom(getStyleParams()); + + S32 part = (S32)LLTextParser::WHOLE; + if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). + { + S32 start=0,end=0; + LLUrlMatch match; + std::string text = new_text; + while (LLUrlRegistry::instance().findUrl(text, match, + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons)) + { + start = match.getStart(); + end = match.getEnd()+1; + + LLStyle::Params link_params(style_params); + link_params.overwriteFrom(match.getStyle()); + + // output the text before the Url + if (start > 0) + { + if (part == (S32)LLTextParser::WHOLE || + part == (S32)LLTextParser::START) + { + part = (S32)LLTextParser::START; + } + else + { + part = (S32)LLTextParser::MIDDLE; + } + std::string subtext=text.substr(0,start); + appendAndHighlightText(subtext, part, style_params); + } + + // add icon before url if need + LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons); + if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) + { + setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); + } + + // output the styled Url + appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); + bool tooltip_required = !match.getTooltip().empty(); + + // set the tooltip for the Url label + if (tooltip_required) + { + setLastSegmentToolTip(match.getTooltip()); + } + + // show query part of url with gray color only for LLUrlEntryHTTP url entries + std::string label = match.getQuery(); + if (label.size()) + { + link_params.color = LLColor4::grey; + link_params.readonly_color = LLColor4::grey; + appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); + + // set the tooltip for the query part of url + if (tooltip_required) + { + setLastSegmentToolTip(match.getTooltip()); + } + } + + // move on to the rest of the text after the Url + if (end < (S32)text.length()) + { + text = text.substr(end,text.length() - end); + end=0; + part=(S32)LLTextParser::END; + } + else + { + break; + } + } + if (part != (S32)LLTextParser::WHOLE) + part=(S32)LLTextParser::END; + if (end < (S32)text.length()) + appendAndHighlightText(text, part, style_params); + } + else + { + appendAndHighlightText(new_text, part, style_params); + } } void LLTextBase::setLastSegmentToolTip(const std::string &tooltip) { - segment_set_t::iterator it = getSegIterContaining(getLength()-1); - if (it != mSegments.end()) - { - LLTextSegmentPtr segment = *it; - segment->setToolTip(tooltip); - } + segment_set_t::iterator it = getSegIterContaining(getLength()-1); + if (it != mSegments.end()) + { + LLTextSegmentPtr segment = *it; + segment->setToolTip(tooltip); + } } void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if (new_text.empty()) - return; + if (new_text.empty()) + return; - if(prepend_newline) - appendLineBreakSegment(input_params); - appendTextImpl(new_text,input_params); + if(prepend_newline) + appendLineBreakSegment(input_params); + appendTextImpl(new_text,input_params); } void LLTextBase::setLabel(const LLStringExplicit& label) { - mLabel = label; - resetLabel(); + mLabel = label; + resetLabel(); } BOOL LLTextBase::setLabelArg(const std::string& key, const LLStringExplicit& text ) { - mLabel.setArg(key, text); - return TRUE; + mLabel.setArg(key, text); + return TRUE; } void LLTextBase::resetLabel() { - if (useLabel()) - { - clearSegments(); + if (useLabel()) + { + clearSegments(); - LLStyle* style = new LLStyle(getStyleParams()); - style->setColor(mTentativeFgColor); - LLStyleConstSP sp(style); + LLStyle* style = new LLStyle(getStyleParams()); + style->setColor(mTentativeFgColor); + LLStyleConstSP sp(style); - LLTextSegmentPtr label = new LLLabelTextSegment(sp, 0, mLabel.getWString().length() + 1, *this); - insertSegment(label); - } + LLTextSegmentPtr label = new LLLabelTextSegment(sp, 0, mLabel.getWString().length() + 1, *this); + insertSegment(label); + } } bool LLTextBase::useLabel() const @@ -2350,17 +2340,17 @@ bool LLTextBase::useLabel() const void LLTextBase::setFont(const LLFontGL* font) { - mFont = font; - mStyleDirty = true; + mFont = font; + mStyleDirty = true; } void LLTextBase::needsReflow(S32 index) { - LL_DEBUGS() << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << LL_ENDL; - mReflowIndex = llmin(mReflowIndex, index); + LL_DEBUGS() << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << LL_ENDL; + mReflowIndex = llmin(mReflowIndex, index); } -S32 LLTextBase::removeFirstLine() +S32 LLTextBase::removeFirstLine() { if (!mLineInfoList.empty()) { @@ -2374,222 +2364,222 @@ S32 LLTextBase::removeFirstLine() void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) { - segment_vec_t segments; - LLStyleConstSP sp(new LLStyle(style_params)); - segments.push_back(new LLLineBreakTextSegment(sp, getLength())); + segment_vec_t segments; + LLStyleConstSP sp(new LLStyle(style_params)); + segments.push_back(new LLLineBreakTextSegment(sp, getLength())); - insertStringNoUndo(getLength(), utf8str_to_wstring("\n"), &segments); + insertStringNoUndo(getLength(), utf8str_to_wstring("\n"), &segments); } void LLTextBase::appendImageSegment(const LLStyle::Params& style_params) { - if(getPlainText()) - { - return; - } - segment_vec_t segments; - LLStyleConstSP sp(new LLStyle(style_params)); - segments.push_back(new LLImageTextSegment(sp, getLength(),*this)); + if(getPlainText()) + { + return; + } + segment_vec_t segments; + LLStyleConstSP sp(new LLStyle(style_params)); + segments.push_back(new LLImageTextSegment(sp, getLength(),*this)); - insertStringNoUndo(getLength(), utf8str_to_wstring(" "), &segments); + insertStringNoUndo(getLength(), utf8str_to_wstring(" "), &segments); } void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - segment_vec_t segments; - LLWString widget_wide_text = utf8str_to_wstring(text); - segments.push_back(new LLInlineViewSegment(params, getLength(), getLength() + widget_wide_text.size())); + segment_vec_t segments; + LLWString widget_wide_text = utf8str_to_wstring(text); + segments.push_back(new LLInlineViewSegment(params, getLength(), getLength() + widget_wide_text.size())); - insertStringNoUndo(getLength(), widget_wide_text, &segments); + insertStringNoUndo(getLength(), widget_wide_text, &segments); } void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); - - deselect(); - - setCursorPos(old_length); - - if (mParseHighlights) - { - LLStyle::Params highlight_params(style_params); - - LLSD pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part); - for (S32 i = 0; i < pieces.size(); i++) - { - LLSD color_llsd = pieces[i]["color"]; - LLColor4 lcolor; - lcolor.setValue(color_llsd); - highlight_params.color = lcolor; - - LLWString wide_text; - wide_text = utf8str_to_wstring(pieces[i]["text"].asString()); - - S32 cur_length = getLength(); - LLStyleConstSP sp(new LLStyle(highlight_params)); - LLTextSegmentPtr segmentp; - if (underline_on_hover_only || mSkipLinkUnderline) - { - highlight_params.font.style("NORMAL"); - LLStyleConstSP normal_sp(new LLStyle(highlight_params)); - segmentp = new LLOnHoverChangeableTextSegment(sp, normal_sp, cur_length, cur_length + wide_text.size(), *this); - } - else - { - segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); - } - segment_vec_t segments; - segments.push_back(segmentp); - insertStringNoUndo(cur_length, wide_text, &segments); - } - } - else - { - LLWString wide_text; - wide_text = utf8str_to_wstring(new_text); - - segment_vec_t segments; - S32 segment_start = old_length; - S32 segment_end = old_length + wide_text.size(); - LLStyleConstSP sp(new LLStyle(style_params)); - if (underline_on_hover_only || mSkipLinkUnderline) - { - LLStyle::Params normal_style_params(style_params); - normal_style_params.font.style("NORMAL"); - LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); - segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this)); - } - else - { - segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this)); - } - - insertStringNoUndo(getLength(), wide_text, &segments); - } - - // Set the cursor and scroll position - if (selection_start != selection_end) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; - - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if (cursor_was_at_end) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); + + deselect(); + + setCursorPos(old_length); + + if (mParseHighlights) + { + LLStyle::Params highlight_params(style_params); + + LLSD pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part); + for (S32 i = 0; i < pieces.size(); i++) + { + LLSD color_llsd = pieces[i]["color"]; + LLColor4 lcolor; + lcolor.setValue(color_llsd); + highlight_params.color = lcolor; + + LLWString wide_text; + wide_text = utf8str_to_wstring(pieces[i]["text"].asString()); + + S32 cur_length = getLength(); + LLStyleConstSP sp(new LLStyle(highlight_params)); + LLTextSegmentPtr segmentp; + if (underline_on_hover_only || mSkipLinkUnderline) + { + highlight_params.font.style("NORMAL"); + LLStyleConstSP normal_sp(new LLStyle(highlight_params)); + segmentp = new LLOnHoverChangeableTextSegment(sp, normal_sp, cur_length, cur_length + wide_text.size(), *this); + } + else + { + segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); + } + segment_vec_t segments; + segments.push_back(segmentp); + insertStringNoUndo(cur_length, wide_text, &segments); + } + } + else + { + LLWString wide_text; + wide_text = utf8str_to_wstring(new_text); + + segment_vec_t segments; + S32 segment_start = old_length; + S32 segment_end = old_length + wide_text.size(); + LLStyleConstSP sp(new LLStyle(style_params)); + if (underline_on_hover_only || mSkipLinkUnderline) + { + LLStyle::Params normal_style_params(style_params); + normal_style_params.font.style("NORMAL"); + LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); + segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this)); + } + else + { + segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this)); + } + + insertStringNoUndo(getLength(), wide_text, &segments); + } + + // Set the cursor and scroll position + if (selection_start != selection_end) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; + + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if (cursor_was_at_end) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } } void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { - if (new_text.empty()) - { - return; - } + if (new_text.empty()) + { + return; + } - std::string::size_type start = 0; - std::string::size_type pos = new_text.find("\n", start); - - while (pos != std::string::npos) - { - if (pos != start) - { - std::string str = std::string(new_text,start,pos-start); - appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); - } - appendLineBreakSegment(style_params); - start = pos+1; - pos = new_text.find("\n", start); - } + std::string::size_type start = 0; + std::string::size_type pos = new_text.find("\n", start); + + while (pos != std::string::npos) + { + if (pos != start) + { + std::string str = std::string(new_text,start,pos-start); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); + } + appendLineBreakSegment(style_params); + start = pos+1; + pos = new_text.find("\n", start); + } - std::string str = std::string(new_text, start, new_text.length() - start); - appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); + std::string str = std::string(new_text, start, new_text.length() - start); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); } void LLTextBase::replaceUrl(const std::string &url, - const std::string &label, - const std::string &icon) -{ - // 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->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; - } - - // Icon might be updated when more avatar or group info - // becomes available - if (style->isImage() && style->getLinkHREF() == url) - { - LLUIImagePtr image = image_from_icon_name( icon ); - if (image) - { - LLStyle::Params icon_params; - icon_params.image = image; - LLStyleConstSP new_style(new LLStyle(icon_params)); - seg->setStyle(new_style); - 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(); - } + const std::string &label, + const std::string &icon) +{ + // 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->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; + } + + // Icon might be updated when more avatar or group info + // becomes available + if (style->isImage() && style->getLinkHREF() == url) + { + LLUIImagePtr image = image_from_icon_name( icon ); + if (image) + { + LLStyle::Params icon_params; + icon_params.image = image; + LLStyleConstSP new_style(new LLStyle(icon_params)); + seg->setStyle(new_style); + 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 LLTextBase::setWText(const LLWString& text) { - setText(wstring_to_utf8str(text)); + setText(wstring_to_utf8str(text)); } const LLWString& LLTextBase::getWText() const { - return getViewModel()->getDisplay(); + return getViewModel()->getDisplay(); } // If round is true, if the position is on the right half of a character, the cursor @@ -2598,624 +2588,624 @@ const LLWString& LLTextBase::getWText() const S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line) const { - // Figure out which line we're nearest to. - LLRect doc_rect = mDocumentView->getRect(); - S32 doc_y = local_y - doc_rect.mBottom; - - // binary search for line that starts before local_y - line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_y, compare_bottom()); - - if (!mLineInfoList.size() || line_iter == mLineInfoList.end()) - { - return getLength(); // past the end - } - - S32 pos = getLength(); - F32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft; - - segment_set_t::iterator line_seg_iter; - S32 line_seg_offset; - for(getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset); - line_seg_iter != mSegments.end(); - ++line_seg_iter, line_seg_offset = 0) - { - const LLTextSegmentPtr segmentp = *line_seg_iter; - - S32 segment_line_start = segmentp->getStart() + line_seg_offset; - S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd) - segment_line_start; + // Figure out which line we're nearest to. + LLRect doc_rect = mDocumentView->getRect(); + S32 doc_y = local_y - doc_rect.mBottom; + + // binary search for line that starts before local_y + line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_y, compare_bottom()); + + if (!mLineInfoList.size() || line_iter == mLineInfoList.end()) + { + return getLength(); // past the end + } + + S32 pos = getLength(); + F32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft; + + segment_set_t::iterator line_seg_iter; + S32 line_seg_offset; + for(getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset); + line_seg_iter != mSegments.end(); + ++line_seg_iter, line_seg_offset = 0) + { + const LLTextSegmentPtr segmentp = *line_seg_iter; + + S32 segment_line_start = segmentp->getStart() + line_seg_offset; + S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd) - segment_line_start; F32 text_width; S32 text_height; - bool newline = segmentp->getDimensionsF32(line_seg_offset, segment_line_length, text_width, text_height); - - if(newline) - { - pos = segment_line_start + segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round); - break; - } - - // if we've reached a line of text *below* the mouse cursor, doc index is first character on that line - if (hit_past_end_of_line && doc_y > line_iter->mRect.mTop) - { - pos = segment_line_start; - break; - } - if (local_x < start_x + text_width) // cursor to left of right edge of text - { - // Figure out which character we're nearest to. - S32 offset; - if (!segmentp->canEdit()) - { + bool newline = segmentp->getDimensionsF32(line_seg_offset, segment_line_length, text_width, text_height); + + if(newline) + { + pos = segment_line_start + segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round); + break; + } + + // if we've reached a line of text *below* the mouse cursor, doc index is first character on that line + if (hit_past_end_of_line && doc_y > line_iter->mRect.mTop) + { + pos = segment_line_start; + break; + } + if (local_x < start_x + text_width) // cursor to left of right edge of text + { + // Figure out which character we're nearest to. + S32 offset; + if (!segmentp->canEdit()) + { F32 segment_width; S32 segment_height; - segmentp->getDimensionsF32(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height); - if (round && local_x - start_x > segment_width / 2) - { - offset = segment_line_length; - } - else - { - offset = 0; - } - } - else - { - offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round); - } - pos = segment_line_start + offset; - break; - } - else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd) - { - if (getLineNumFromDocIndex(line_iter->mDocIndexEnd - 1) == line_iter->mLineNum) - { - // if segment wraps to the next line we should step one char back - // to compensate for the space char between words - // which is removed due to wrapping - pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength()); - } - else - { - pos = llclamp(line_iter->mDocIndexEnd, 0, getLength()); - } - break; - } - start_x += text_width; - } - - return pos; -} - -// returns rectangle of insertion caret + segmentp->getDimensionsF32(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height); + if (round && local_x - start_x > segment_width / 2) + { + offset = segment_line_length; + } + else + { + offset = 0; + } + } + else + { + offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round); + } + pos = segment_line_start + offset; + break; + } + else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd) + { + if (getLineNumFromDocIndex(line_iter->mDocIndexEnd - 1) == line_iter->mLineNum) + { + // if segment wraps to the next line we should step one char back + // to compensate for the space char between words + // which is removed due to wrapping + pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength()); + } + else + { + pos = llclamp(line_iter->mDocIndexEnd, 0, getLength()); + } + break; + } + start_x += text_width; + } + + return pos; +} + +// returns rectangle of insertion caret // in document coordinate frame from given index into text LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const { - if (mLineInfoList.empty()) - { - return LLRect(); - } + if (mLineInfoList.empty()) + { + return LLRect(); + } - // clamp pos to valid values - pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1); + // clamp pos to valid values + pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1); - line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare()); + line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare()); - segment_set_t::iterator line_seg_iter; - S32 line_seg_offset; - segment_set_t::iterator cursor_seg_iter; - S32 cursor_seg_offset; - getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset); - getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset); + segment_set_t::iterator line_seg_iter; + S32 line_seg_offset; + segment_set_t::iterator cursor_seg_iter; + S32 cursor_seg_offset; + getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset); + getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset); F32 doc_left_precise = line_iter->mRect.mLeft; - while(line_seg_iter != mSegments.end()) - { - const LLTextSegmentPtr segmentp = *line_seg_iter; + while(line_seg_iter != mSegments.end()) + { + const LLTextSegmentPtr segmentp = *line_seg_iter; - if (line_seg_iter == cursor_seg_iter) - { - // cursor advanced to right based on difference in offset of cursor to start of line + if (line_seg_iter == cursor_seg_iter) + { + // cursor advanced to right based on difference in offset of cursor to start of line F32 segment_width; S32 segment_height; - segmentp->getDimensionsF32(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height); + segmentp->getDimensionsF32(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height); doc_left_precise += segment_width; - break; - } - else - { - // add remainder of current text segment to cursor position + break; + } + else + { + // add remainder of current text segment to cursor position F32 segment_width; S32 segment_height; - segmentp->getDimensionsF32(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height); + segmentp->getDimensionsF32(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height); doc_left_precise += segment_width; - // offset will be 0 for all segments after the first - line_seg_offset = 0; - // go to next text segment on this line - ++line_seg_iter; - } - } + // offset will be 0 for all segments after the first + line_seg_offset = 0; + // go to next text segment on this line + ++line_seg_iter; + } + } LLRect doc_rect; doc_rect.mLeft = doc_left_precise; doc_rect.mBottom = line_iter->mRect.mBottom; doc_rect.mTop = line_iter->mRect.mTop; - // set rect to 0 width - doc_rect.mRight = doc_rect.mLeft; + // set rect to 0 width + doc_rect.mRight = doc_rect.mLeft; - return doc_rect; + return doc_rect; } LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const { - LLRect content_window_rect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); - if (mBorderVisible) - { - content_window_rect.stretch(-1); - } + LLRect content_window_rect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + if (mBorderVisible) + { + content_window_rect.stretch(-1); + } - LLRect local_rect; + LLRect local_rect; - if (mLineInfoList.empty()) - { - // return default height rect in upper left - local_rect = content_window_rect; - local_rect.mBottom = local_rect.mTop - mFont->getLineHeight(); - return local_rect; - } + if (mLineInfoList.empty()) + { + // return default height rect in upper left + local_rect = content_window_rect; + local_rect.mBottom = local_rect.mTop - mFont->getLineHeight(); + return local_rect; + } - // get the rect in document coordinates - LLRect doc_rect = getDocRectFromDocIndex(pos); + // get the rect in document coordinates + LLRect doc_rect = getDocRectFromDocIndex(pos); - // compensate for scrolled, inset view of doc - LLRect scrolled_view_rect = getVisibleDocumentRect(); - local_rect = doc_rect; - local_rect.translate(content_window_rect.mLeft - scrolled_view_rect.mLeft, - content_window_rect.mBottom - scrolled_view_rect.mBottom); + // compensate for scrolled, inset view of doc + LLRect scrolled_view_rect = getVisibleDocumentRect(); + local_rect = doc_rect; + local_rect.translate(content_window_rect.mLeft - scrolled_view_rect.mLeft, + content_window_rect.mBottom - scrolled_view_rect.mBottom); - return local_rect; + return local_rect; } void LLTextBase::updateCursorXPos() { - // reset desired x cursor position - mDesiredXPixel = getLocalRectFromDocIndex(mCursorPos).mLeft; + // reset desired x cursor position + mDesiredXPixel = getLocalRectFromDocIndex(mCursorPos).mLeft; } void LLTextBase::startOfLine() { - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - setCursorPos(mCursorPos - offset); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + setCursorPos(mCursorPos - offset); } void LLTextBase::endOfLine() { - S32 line = getLineNumFromDocIndex(mCursorPos); - S32 num_lines = getLineCount(); - if (line + 1 >= num_lines) - { - setCursorPos(getLength()); - } - else - { - setCursorPos( getLineStart(line + 1) - 1 ); - } + S32 line = getLineNumFromDocIndex(mCursorPos); + S32 num_lines = getLineCount(); + if (line + 1 >= num_lines) + { + setCursorPos(getLength()); + } + else + { + setCursorPos( getLineStart(line + 1) - 1 ); + } } void LLTextBase::startOfDoc() { - setCursorPos(0); - if (mScroller) - { - mScroller->goToTop(); - } + setCursorPos(0); + if (mScroller) + { + mScroller->goToTop(); + } } void LLTextBase::endOfDoc() { - setCursorPos(getLength()); - if (mScroller) - { - mScroller->goToBottom(); - } + setCursorPos(getLength()); + if (mScroller) + { + mScroller->goToBottom(); + } } void LLTextBase::changePage( S32 delta ) { - const S32 PIXEL_OVERLAP_ON_PAGE_CHANGE = 10; - if (delta == 0 || !mScroller) return; - - LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); - - if( delta == -1 ) - { - mScroller->pageUp(PIXEL_OVERLAP_ON_PAGE_CHANGE); - } - else - if( delta == 1 ) - { - mScroller->pageDown(PIXEL_OVERLAP_ON_PAGE_CHANGE); - } - - if (getLocalRectFromDocIndex(mCursorPos) == cursor_rect) - { - // cursor didn't change apparent position, so move to top or bottom of document, respectively - if (delta < 0) - { - startOfDoc(); - } - else - { - endOfDoc(); - } - } - else - { - setCursorAtLocalPos(cursor_rect.getCenterX(), cursor_rect.getCenterY(), true, false); - } + const S32 PIXEL_OVERLAP_ON_PAGE_CHANGE = 10; + if (delta == 0 || !mScroller) return; + + LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos); + + if( delta == -1 ) + { + mScroller->pageUp(PIXEL_OVERLAP_ON_PAGE_CHANGE); + } + else + if( delta == 1 ) + { + mScroller->pageDown(PIXEL_OVERLAP_ON_PAGE_CHANGE); + } + + if (getLocalRectFromDocIndex(mCursorPos) == cursor_rect) + { + // cursor didn't change apparent position, so move to top or bottom of document, respectively + if (delta < 0) + { + startOfDoc(); + } + else + { + endOfDoc(); + } + } + else + { + setCursorAtLocalPos(cursor_rect.getCenterX(), cursor_rect.getCenterY(), true, false); + } } // Picks a new cursor position based on the screen size of text being drawn. void LLTextBase::setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset ) { - setCursorPos(getDocIndexFromLocalCoord(local_x, local_y, round), keep_cursor_offset); + setCursorPos(getDocIndexFromLocalCoord(local_x, local_y, round), keep_cursor_offset); } void LLTextBase::changeLine( S32 delta ) { - S32 line = getLineNumFromDocIndex(mCursorPos); - S32 max_line_nb = getLineCount() - 1; - max_line_nb = (max_line_nb < 0 ? 0 : max_line_nb); - - S32 new_line = llclamp(line + delta, 0, max_line_nb); + S32 line = getLineNumFromDocIndex(mCursorPos); + S32 max_line_nb = getLineCount() - 1; + max_line_nb = (max_line_nb < 0 ? 0 : max_line_nb); + + S32 new_line = llclamp(line + delta, 0, max_line_nb); if (new_line != line) { LLRect visible_region = getVisibleDocumentRect(); S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mRect.mBottom + mVisibleTextRect.mBottom - visible_region.mBottom, TRUE); - S32 actual_line = getLineNumFromDocIndex(new_cursor_pos); - if (actual_line != new_line) - { - // line edge, correcting position by 1 to move onto proper line - new_cursor_pos += new_line - actual_line; - } + S32 actual_line = getLineNumFromDocIndex(new_cursor_pos); + if (actual_line != new_line) + { + // line edge, correcting position by 1 to move onto proper line + new_cursor_pos += new_line - actual_line; + } setCursorPos(new_cursor_pos, true); } } bool LLTextBase::scrolledToStart() { - return mScroller->isAtTop(); + return mScroller->isAtTop(); } bool LLTextBase::scrolledToEnd() { - return mScroller->isAtBottom(); + return mScroller->isAtBottom(); } bool LLTextBase::setCursor(S32 row, S32 column) { - if (row < 0 || column < 0) return false; + if (row < 0 || column < 0) return false; - S32 n_lines = mLineInfoList.size(); - for (S32 line = row; line < n_lines; ++line) - { - const line_info& li = mLineInfoList[line]; + S32 n_lines = mLineInfoList.size(); + for (S32 line = row; line < n_lines; ++line) + { + const line_info& li = mLineInfoList[line]; - if (li.mLineNum < row) - { - continue; - } - else if (li.mLineNum > row) - { - break; // invalid column specified - } + if (li.mLineNum < row) + { + continue; + } + else if (li.mLineNum > row) + { + break; // invalid column specified + } - // Found the given row. - S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;; - if (column >= line_length) - { - column -= line_length; - continue; - } + // Found the given row. + S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;; + if (column >= line_length) + { + column -= line_length; + continue; + } - // Found the given column. - updateCursorXPos(); - S32 doc_pos = li.mDocIndexStart + column; - return setCursorPos(doc_pos); - } + // Found the given column. + updateCursorXPos(); + S32 doc_pos = li.mDocIndexStart + column; + return setCursorPos(doc_pos); + } - return false; // invalid row or column specified + return false; // invalid row or column specified } bool LLTextBase::setCursorPos(S32 cursor_pos, bool keep_cursor_offset) { - S32 new_cursor_pos = cursor_pos; - if (new_cursor_pos != mCursorPos) - { - new_cursor_pos = getEditableIndex(new_cursor_pos, new_cursor_pos >= mCursorPos); - } + S32 new_cursor_pos = cursor_pos; + if (new_cursor_pos != mCursorPos) + { + new_cursor_pos = getEditableIndex(new_cursor_pos, new_cursor_pos >= mCursorPos); + } - mCursorPos = llclamp(new_cursor_pos, 0, (S32)getLength()); - needsScroll(); - if (!keep_cursor_offset) - updateCursorXPos(); - // did we get requested position? - return new_cursor_pos == cursor_pos; + mCursorPos = llclamp(new_cursor_pos, 0, (S32)getLength()); + needsScroll(); + if (!keep_cursor_offset) + updateCursorXPos(); + // did we get requested position? + return new_cursor_pos == cursor_pos; } // constraint cursor to editable segments of document S32 LLTextBase::getEditableIndex(S32 index, bool increasing_direction) { - segment_set_t::iterator segment_iter; - S32 offset; - getSegmentAndOffset(index, &segment_iter, &offset); - if (segment_iter == mSegments.end()) - { - return 0; - } - - LLTextSegmentPtr segmentp = *segment_iter; - - if (segmentp->canEdit()) - { - return segmentp->getStart() + offset; - } - else if (segmentp->getStart() < index && index < segmentp->getEnd()) - { - // bias towards document end - if (increasing_direction) - { - return segmentp->getEnd(); - } - // bias towards document start - else - { - return segmentp->getStart(); - } - } - else - { - return index; - } + segment_set_t::iterator segment_iter; + S32 offset; + getSegmentAndOffset(index, &segment_iter, &offset); + if (segment_iter == mSegments.end()) + { + return 0; + } + + LLTextSegmentPtr segmentp = *segment_iter; + + if (segmentp->canEdit()) + { + return segmentp->getStart() + offset; + } + else if (segmentp->getStart() < index && index < segmentp->getEnd()) + { + // bias towards document end + if (increasing_direction) + { + return segmentp->getEnd(); + } + // bias towards document start + else + { + return segmentp->getStart(); + } + } + else + { + return index; + } } void LLTextBase::updateRects() { - LLRect old_text_rect = mVisibleTextRect; - mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); - - if (mLineInfoList.empty()) - { - mTextBoundingRect = LLRect(0, mVPad, mHPad, 0); - } - else - { - mTextBoundingRect = mLineInfoList.begin()->mRect; - for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin(); - line_iter != mLineInfoList.end(); - ++line_iter) - { - mTextBoundingRect.unionWith(line_iter->mRect); - } - - mTextBoundingRect.mTop += mVPad; - - S32 delta_pos = 0; - - switch(mVAlign) - { - case LLFontGL::TOP: - delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); - break; - case LLFontGL::VCENTER: - delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; - break; - case LLFontGL::BOTTOM: - delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; - break; - case LLFontGL::BASELINE: - // do nothing - break; - } - // move line segments to fit new document rect - for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) - { - it->mRect.translate(0, delta_pos); - } - mTextBoundingRect.translate(0, delta_pos); - } - - // update document container dimensions according to text contents - LLRect doc_rect; - // use old mVisibleTextRect constraint document to width of viewable region - doc_rect.mBottom = llmin(mVisibleTextRect.mBottom, mTextBoundingRect.mBottom); - doc_rect.mLeft = 0; - - // allow horizontal scrolling? - // if so, use entire width of text contents - // otherwise, stop at width of mVisibleTextRect - //FIXME: consider use of getWordWrap() instead - doc_rect.mRight = mScroller - ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) - : mVisibleTextRect.getWidth(); - doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop); - - if (!mScroller) - { - // push doc rect to top of text widget - switch(mVAlign) - { - case LLFontGL::TOP: - doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); - break; - case LLFontGL::VCENTER: - doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); - case LLFontGL::BOTTOM: - default: - break; - } - } - - mDocumentView->setShape(doc_rect); - - //update mVisibleTextRect *after* mDocumentView has been resized - // so that scrollbars are added if document needs to scroll - // since mVisibleTextRect does not include scrollbars - mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); - //FIXME: replace border with image? - if (mBorderVisible) - { - mVisibleTextRect.stretch(-1); - } - if (mVisibleTextRect != old_text_rect) - { - needsReflow(); - } - - // update mTextBoundingRect after mVisibleTextRect took scrolls into account - if (!mLineInfoList.empty() && mScroller) - { - S32 delta_pos = 0; - - switch(mVAlign) - { - case LLFontGL::TOP: - delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); - break; - case LLFontGL::VCENTER: - delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; - break; - case LLFontGL::BOTTOM: - delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; - break; - case LLFontGL::BASELINE: - // do nothing - break; - } - // move line segments to fit new visible rect - if (delta_pos != 0) - { - for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) - { - it->mRect.translate(0, delta_pos); - } - mTextBoundingRect.translate(0, delta_pos); - } - } - - // update document container again, using new mVisibleTextRect (that has scrollbars enabled as needed) - doc_rect.mBottom = llmin(mVisibleTextRect.mBottom, mTextBoundingRect.mBottom); - doc_rect.mLeft = 0; - doc_rect.mRight = mScroller - ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) - : mVisibleTextRect.getWidth(); - doc_rect.mTop = llmax(mVisibleTextRect.getHeight(), mTextBoundingRect.getHeight()) + doc_rect.mBottom; - if (!mScroller) - { - // push doc rect to top of text widget - switch(mVAlign) - { - case LLFontGL::TOP: - doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); - break; - case LLFontGL::VCENTER: - doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); - case LLFontGL::BOTTOM: - default: - break; - } - } - mDocumentView->setShape(doc_rect); + LLRect old_text_rect = mVisibleTextRect; + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + + if (mLineInfoList.empty()) + { + mTextBoundingRect = LLRect(0, mVPad, mHPad, 0); + } + else + { + mTextBoundingRect = mLineInfoList.begin()->mRect; + for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin(); + line_iter != mLineInfoList.end(); + ++line_iter) + { + mTextBoundingRect.unionWith(line_iter->mRect); + } + + mTextBoundingRect.mTop += mVPad; + + S32 delta_pos = 0; + + switch(mVAlign) + { + case LLFontGL::TOP: + delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); + break; + case LLFontGL::VCENTER: + delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; + break; + case LLFontGL::BOTTOM: + delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; + break; + case LLFontGL::BASELINE: + // do nothing + break; + } + // move line segments to fit new document rect + for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) + { + it->mRect.translate(0, delta_pos); + } + mTextBoundingRect.translate(0, delta_pos); + } + + // update document container dimensions according to text contents + LLRect doc_rect; + // use old mVisibleTextRect constraint document to width of viewable region + doc_rect.mBottom = llmin(mVisibleTextRect.mBottom, mTextBoundingRect.mBottom); + doc_rect.mLeft = 0; + + // allow horizontal scrolling? + // if so, use entire width of text contents + // otherwise, stop at width of mVisibleTextRect + //FIXME: consider use of getWordWrap() instead + doc_rect.mRight = mScroller + ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) + : mVisibleTextRect.getWidth(); + doc_rect.mTop = llmax(mVisibleTextRect.mTop, mTextBoundingRect.mTop); + + if (!mScroller) + { + // push doc rect to top of text widget + switch(mVAlign) + { + case LLFontGL::TOP: + doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); + break; + case LLFontGL::VCENTER: + doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); + case LLFontGL::BOTTOM: + default: + break; + } + } + + mDocumentView->setShape(doc_rect); + + //update mVisibleTextRect *after* mDocumentView has been resized + // so that scrollbars are added if document needs to scroll + // since mVisibleTextRect does not include scrollbars + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + //FIXME: replace border with image? + if (mBorderVisible) + { + mVisibleTextRect.stretch(-1); + } + if (mVisibleTextRect != old_text_rect) + { + needsReflow(); + } + + // update mTextBoundingRect after mVisibleTextRect took scrolls into account + if (!mLineInfoList.empty() && mScroller) + { + S32 delta_pos = 0; + + switch(mVAlign) + { + case LLFontGL::TOP: + delta_pos = llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom); + break; + case LLFontGL::VCENTER: + delta_pos = (llmax(mVisibleTextRect.getHeight() - mTextBoundingRect.mTop, -mTextBoundingRect.mBottom) + (mVisibleTextRect.mBottom - mTextBoundingRect.mBottom)) / 2; + break; + case LLFontGL::BOTTOM: + delta_pos = mVisibleTextRect.mBottom - mTextBoundingRect.mBottom; + break; + case LLFontGL::BASELINE: + // do nothing + break; + } + // move line segments to fit new visible rect + if (delta_pos != 0) + { + for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) + { + it->mRect.translate(0, delta_pos); + } + mTextBoundingRect.translate(0, delta_pos); + } + } + + // update document container again, using new mVisibleTextRect (that has scrollbars enabled as needed) + doc_rect.mBottom = llmin(mVisibleTextRect.mBottom, mTextBoundingRect.mBottom); + doc_rect.mLeft = 0; + doc_rect.mRight = mScroller + ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) + : mVisibleTextRect.getWidth(); + doc_rect.mTop = llmax(mVisibleTextRect.getHeight(), mTextBoundingRect.getHeight()) + doc_rect.mBottom; + if (!mScroller) + { + // push doc rect to top of text widget + switch(mVAlign) + { + case LLFontGL::TOP: + doc_rect.translate(0, mVisibleTextRect.getHeight() - doc_rect.mTop); + break; + case LLFontGL::VCENTER: + doc_rect.translate(0, (mVisibleTextRect.getHeight() - doc_rect.mTop) / 2); + case LLFontGL::BOTTOM: + default: + break; + } + } + mDocumentView->setShape(doc_rect); } void LLTextBase::startSelection() { - if( !mIsSelecting ) - { - mIsSelecting = TRUE; - mSelectionStart = mCursorPos; - mSelectionEnd = mCursorPos; - } + if( !mIsSelecting ) + { + mIsSelecting = TRUE; + mSelectionStart = mCursorPos; + mSelectionEnd = mCursorPos; + } } void LLTextBase::endSelection() { - if( mIsSelecting ) - { - mIsSelecting = FALSE; - mSelectionEnd = mCursorPos; - } + if( mIsSelecting ) + { + mIsSelecting = FALSE; + mSelectionEnd = mCursorPos; + } } // get portion of document that is visible in text editor LLRect LLTextBase::getVisibleDocumentRect() const { - if (mScroller) - { - return mScroller->getVisibleContentRect(); - } - else if (mClip) - { - LLRect visible_text_rect = getVisibleTextRect(); - LLRect doc_rect = mDocumentView->getRect(); - visible_text_rect.translate(-doc_rect.mLeft, -doc_rect.mBottom); - - // reject partially visible lines - LLRect visible_lines_rect; - for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); - it != end_it; - ++it) - { - bool line_visible = mClipPartial ? visible_text_rect.contains(it->mRect) : visible_text_rect.overlaps(it->mRect); - if (line_visible) - { - if (visible_lines_rect.isEmpty()) - { - visible_lines_rect = it->mRect; - } - else - { - visible_lines_rect.unionWith(it->mRect); - } - } - } - return visible_lines_rect; - } - else - { // entire document rect is visible - // but offset according to height of widget - - LLRect doc_rect = mDocumentView->getLocalRect(); - doc_rect.mLeft -= mDocumentView->getRect().mLeft; - // adjust for height of text above widget baseline - doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); - return doc_rect; - } + if (mScroller) + { + return mScroller->getVisibleContentRect(); + } + else if (mClip) + { + LLRect visible_text_rect = getVisibleTextRect(); + LLRect doc_rect = mDocumentView->getRect(); + visible_text_rect.translate(-doc_rect.mLeft, -doc_rect.mBottom); + + // reject partially visible lines + LLRect visible_lines_rect; + for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); + it != end_it; + ++it) + { + bool line_visible = mClipPartial ? visible_text_rect.contains(it->mRect) : visible_text_rect.overlaps(it->mRect); + if (line_visible) + { + if (visible_lines_rect.isEmpty()) + { + visible_lines_rect = it->mRect; + } + else + { + visible_lines_rect.unionWith(it->mRect); + } + } + } + return visible_lines_rect; + } + else + { // entire document rect is visible + // but offset according to height of widget + + LLRect doc_rect = mDocumentView->getLocalRect(); + doc_rect.mLeft -= mDocumentView->getRect().mLeft; + // adjust for height of text above widget baseline + doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); + return doc_rect; + } } boost::signals2::connection LLTextBase::setURLClickedCallback(const commit_signal_t::slot_type& cb) { - if (!mURLClickSignal) - { - mURLClickSignal = new commit_signal_t(); - } - return mURLClickSignal->connect(cb); + if (!mURLClickSignal) + { + mURLClickSignal = new commit_signal_t(); + } + return mURLClickSignal->connect(cb); } boost::signals2::connection LLTextBase::setIsFriendCallback(const is_friend_signal_t::slot_type& cb) { - if (!mIsFriendSignal) - { - mIsFriendSignal = new is_friend_signal_t(); - } - return mIsFriendSignal->connect(cb); + if (!mIsFriendSignal) + { + mIsFriendSignal = new is_friend_signal_t(); + } + return mIsFriendSignal->connect(cb); } boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb) @@ -3237,16 +3227,16 @@ LLTextSegment::~LLTextSegment() bool LLTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; height = 0; return false; } bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { - F32 fwidth = 0; - bool result = getDimensionsF32(first_char, num_chars, fwidth, height); - width = ll_round(fwidth); - return result; + F32 fwidth = 0; + bool result = getDimensionsF32(first_char, num_chars, fwidth, height); + width = ll_round(fwidth); + return result; } -S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; } -S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { return 0; } +S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; } +S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { return 0; } void LLTextSegment::updateLayout(const LLTextBase& editor) {} -F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { return draw_rect.mLeft; } +F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { return draw_rect.mLeft; } bool LLTextSegment::canEdit() const { return false; } void LLTextSegment::unlinkFromDocument(LLTextBase*) {} void LLTextSegment::linkToDocument(LLTextBase*) {} @@ -3255,7 +3245,7 @@ const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; } LLStyleConstSP LLTextSegment::getStyle() const {static LLStyleConstSP sp(new LLStyle()); return sp; } void LLTextSegment::setStyle(LLStyleConstSP style) {} void LLTextSegment::setToken( LLKeywordToken* token ) {} -LLKeywordToken* LLTextSegment::getToken() const { return NULL; } +LLKeywordToken* LLTextSegment::getToken() const { return NULL; } void LLTextSegment::setToolTip( const std::string &msg ) {} void LLTextSegment::dump() const {} BOOL LLTextSegment::handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } @@ -3269,9 +3259,9 @@ BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; } BOOL LLTextSegment::handleScrollHWheel(S32 x, S32 y, S32 clicks) { return FALSE; } BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; } -const std::string& LLTextSegment::getName() const +const std::string& LLTextSegment::getName() const { - return LLStringUtil::null; + return LLStringUtil::null; } void LLTextSegment::onMouseCaptureLost() {} void LLTextSegment::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {} @@ -3282,171 +3272,171 @@ BOOL LLTextSegment::hasMouseCapture() { return FALSE; } // LLNormalTextSegment // -LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ) -: LLTextSegment(start, end), - mStyle( style ), - mToken(NULL), - mEditor(editor) +LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ) +: LLTextSegment(start, end), + mStyle( style ), + mToken(NULL), + mEditor(editor) { - mFontHeight = mStyle->getFont()->getLineHeight(); + mFontHeight = mStyle->getFont()->getLineHeight(); - LLUIImagePtr image = mStyle->getImage(); - if (image.notNull()) - { - mImageLoadedConnection = image->addLoadedCallback(boost::bind(&LLTextBase::needsReflow, &mEditor, start)); - } + LLUIImagePtr image = mStyle->getImage(); + if (image.notNull()) + { + mImageLoadedConnection = image->addLoadedCallback(boost::bind(&LLTextBase::needsReflow, &mEditor, start)); + } } -LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) -: LLTextSegment(start, end), - mToken(NULL), - mEditor(editor) +LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) +: LLTextSegment(start, end), + mToken(NULL), + mEditor(editor) { - mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); + mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); - mFontHeight = mStyle->getFont()->getLineHeight(); + mFontHeight = mStyle->getFont()->getLineHeight(); } LLNormalTextSegment::~LLNormalTextSegment() { - mImageLoadedConnection.disconnect(); + mImageLoadedConnection.disconnect(); } F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { - if( end - start > 0 ) - { - return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect); - } - return draw_rect.mLeft; + if( end - start > 0 ) + { + return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect); + } + return draw_rect.mLeft; } // Draws a single text segment, reversing the color for selection if needed. F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect) { - F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha; - - const LLWString &text = getWText(); - - F32 right_x = rect.mLeft; - if (!mStyle->isVisible()) - { - return right_x; - } - - const LLFontGL* font = mStyle->getFont(); - - LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha; - - if( selection_start > seg_start ) - { - // Draw normally - S32 start = seg_start; - S32 end = llmin( selection_start, seg_end ); - S32 length = end - start; - font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); - } - rect.mLeft = right_x; - - if( (selection_start < seg_end) && (selection_end > seg_start) ) - { - // Draw reversed - S32 start = llmax( selection_start, seg_start ); - S32 end = llmin( selection_end, seg_end ); - S32 length = end - start; - - font->render(text, start, - rect, - mStyle->getSelectedColor().get(), - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); - } - rect.mLeft = right_x; - if( selection_end < seg_end ) - { - // Draw normally - S32 start = llmax( selection_end, seg_start ); - S32 end = seg_end; - S32 length = end - start; - font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); - } + F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha; + + const LLWString &text = getWText(); + + F32 right_x = rect.mLeft; + if (!mStyle->isVisible()) + { + return right_x; + } + + const LLFontGL* font = mStyle->getFont(); + + LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha; + + if( selection_start > seg_start ) + { + // Draw normally + S32 start = seg_start; + S32 end = llmin( selection_start, seg_end ); + S32 length = end - start; + font->render(text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } + rect.mLeft = right_x; + + if( (selection_start < seg_end) && (selection_end > seg_start) ) + { + // Draw reversed + S32 start = llmax( selection_start, seg_start ); + S32 end = llmin( selection_end, seg_end ); + S32 length = end - start; + + font->render(text, start, + rect, + mStyle->getSelectedColor().get(), + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } + rect.mLeft = right_x; + if( selection_end < seg_end ) + { + // Draw normally + S32 start = llmax( selection_end, seg_start ); + S32 end = seg_end; + S32 length = end - start; + font->render(text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } return right_x; } BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask) { - if (getStyle() && getStyle()->isLink()) - { - // Only process the click if it's actually in this segment, not to the right of the end-of-line. - if(mEditor.getSegmentAtLocalPos(x, y, false) == this) - { - LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); - return TRUE; - } - } - return FALSE; + if (getStyle() && getStyle()->isLink()) + { + // Only process the click if it's actually in this segment, not to the right of the end-of-line. + if(mEditor.getSegmentAtLocalPos(x, y, false) == this) + { + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; + } + } + return FALSE; } BOOL LLNormalTextSegment::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (getStyle() && getStyle()->isLink()) - { - // Only process the click if it's actually in this segment, not to the right of the end-of-line. - if(mEditor.getSegmentAtLocalPos(x, y, false) == this) - { - mEditor.createUrlContextMenu(x, y, getStyle()->getLinkHREF()); - return TRUE; - } - } - return FALSE; + if (getStyle() && getStyle()->isLink()) + { + // Only process the click if it's actually in this segment, not to the right of the end-of-line. + if(mEditor.getSegmentAtLocalPos(x, y, false) == this) + { + mEditor.createUrlContextMenu(x, y, getStyle()->getLinkHREF()); + return TRUE; + } + } + return FALSE; } BOOL LLNormalTextSegment::handleMouseDown(S32 x, S32 y, MASK mask) { - if (getStyle() && getStyle()->isLink()) - { - // Only process the click if it's actually in this segment, not to the right of the end-of-line. - if(mEditor.getSegmentAtLocalPos(x, y, false) == this) - { - // eat mouse down event on hyperlinks, so we get the mouse up - return TRUE; - } - } + if (getStyle() && getStyle()->isLink()) + { + // Only process the click if it's actually in this segment, not to the right of the end-of-line. + if(mEditor.getSegmentAtLocalPos(x, y, false) == this) + { + // eat mouse down event on hyperlinks, so we get the mouse up + return TRUE; + } + } - return FALSE; + return FALSE; } BOOL LLNormalTextSegment::handleMouseUp(S32 x, S32 y, MASK mask) { - if (getStyle() && getStyle()->isLink()) - { - // Only process the click if it's actually in this segment, not to the right of the end-of-line. - if(mEditor.getSegmentAtLocalPos(x, y, false) == this) - { + if (getStyle() && getStyle()->isLink()) + { + // Only process the click if it's actually in this segment, not to the right of the end-of-line. + if(mEditor.getSegmentAtLocalPos(x, y, false) == this) + { std::string url = getStyle()->getLinkHREF(); if (!mEditor.mForceUrlsExternal) { @@ -3456,198 +3446,198 @@ BOOL LLNormalTextSegment::handleMouseUp(S32 x, S32 y, MASK mask) { LLUrlAction::openURLExternal(url); } - return TRUE; - } - } + return TRUE; + } + } - return FALSE; + return FALSE; } BOOL LLNormalTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { - std::string msg; - // do we have a tooltip for a loaded keyword (for script editor)? - if (mToken && !mToken->getToolTip().empty()) - { - const LLWString& wmsg = mToken->getToolTip(); + std::string msg; + // do we have a tooltip for a loaded keyword (for script editor)? + if (mToken && !mToken->getToolTip().empty()) + { + const LLWString& wmsg = mToken->getToolTip(); LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg), (mToken->getType() == LLKeywordToken::TT_FUNCTION)); - return TRUE; - } - // or do we have an explicitly set tooltip (e.g., for Urls) - if (!mTooltip.empty()) - { - LLToolTipMgr::instance().show(mTooltip); - return TRUE; - } + return TRUE; + } + // or do we have an explicitly set tooltip (e.g., for Urls) + if (!mTooltip.empty()) + { + LLToolTipMgr::instance().show(mTooltip); + return TRUE; + } - return FALSE; + return FALSE; } void LLNormalTextSegment::setToolTip(const std::string& tooltip) { - // we cannot replace a keyword tooltip that's loaded from a file - if (mToken) - { - LL_WARNS() << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << LL_ENDL; - return; - } - mTooltip = tooltip; + // we cannot replace a keyword tooltip that's loaded from a file + if (mToken) + { + LL_WARNS() << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << LL_ENDL; + return; + } + mTooltip = tooltip; } bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { - height = 0; - width = 0; - if (num_chars > 0) - { - height = mFontHeight; - const LLWString &text = getWText(); - // if last character is a newline, then return true, forcing line break - width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars, true); - } - return false; -} - -S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const -{ - const LLWString &text = getWText(); - return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset, - (F32)segment_local_x_coord, - F32_MAX, - num_chars, - round); -} - -S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const -{ - const LLWString &text = getWText(); - - LLUIImagePtr image = mStyle->getImage(); - if( image.notNull()) - { - num_pixels = llmax(0, num_pixels - image->getWidth()); - } - - S32 last_char = mEnd; - - // set max characters to length of segment, or to first newline - max_chars = llmin(max_chars, last_char - (mStart + segment_offset)); - - // if no character yet displayed on this line, don't require word wrapping since - // we can just move to the next line, otherwise insist on it so we make forward progress - LLFontGL::EWordWrapStyle word_wrap_style = (line_offset == 0) - ? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE - : LLFontGL::ONLY_WORD_BOUNDARIES; - - - S32 offsetLength = text.length() - (segment_offset + mStart); - - if(getLength() < segment_offset + mStart) - { - LL_INFOS() << "getLength() < segment_offset + mStart\t getLength()\t" << getLength() << "\tsegment_offset:\t" - << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << "\tmax_chars\t" << max_chars << LL_ENDL; - } - - if( (offsetLength + 1) < max_chars) - { - LL_INFOS() << "offsetString.length() + 1 < max_chars\t max_chars:\t" << max_chars << "\toffsetString.length():\t" << offsetLength << " getLength() : " - << getLength() << "\tsegment_offset:\t" << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << LL_ENDL; - } - - S32 num_chars = mStyle->getFont()->maxDrawableChars( text.c_str() + (segment_offset + mStart), - (F32)num_pixels, - max_chars, - word_wrap_style); - - if (num_chars == 0 - && line_offset == 0 - && max_chars > 0) - { - // If at the beginning of a line, and a single character won't fit, draw it anyway - num_chars = 1; - } - - // include *either* the EOF or newline character in this run of text - // but not both - S32 last_char_in_run = mStart + segment_offset + num_chars; - // check length first to avoid indexing off end of string - if (last_char_in_run < mEnd - && (last_char_in_run >= getLength())) - { - num_chars++; - } - return num_chars; + height = 0; + width = 0; + if (num_chars > 0) + { + height = mFontHeight; + const LLWString &text = getWText(); + // if last character is a newline, then return true, forcing line break + width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars, true); + } + return false; +} + +S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const +{ + const LLWString &text = getWText(); + return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset, + (F32)segment_local_x_coord, + F32_MAX, + num_chars, + round); +} + +S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const +{ + const LLWString &text = getWText(); + + LLUIImagePtr image = mStyle->getImage(); + if( image.notNull()) + { + num_pixels = llmax(0, num_pixels - image->getWidth()); + } + + S32 last_char = mEnd; + + // set max characters to length of segment, or to first newline + max_chars = llmin(max_chars, last_char - (mStart + segment_offset)); + + // if no character yet displayed on this line, don't require word wrapping since + // we can just move to the next line, otherwise insist on it so we make forward progress + LLFontGL::EWordWrapStyle word_wrap_style = (line_offset == 0) + ? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE + : LLFontGL::ONLY_WORD_BOUNDARIES; + + + S32 offsetLength = text.length() - (segment_offset + mStart); + + if(getLength() < segment_offset + mStart) + { + LL_INFOS() << "getLength() < segment_offset + mStart\t getLength()\t" << getLength() << "\tsegment_offset:\t" + << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << "\tmax_chars\t" << max_chars << LL_ENDL; + } + + if( (offsetLength + 1) < max_chars) + { + LL_INFOS() << "offsetString.length() + 1 < max_chars\t max_chars:\t" << max_chars << "\toffsetString.length():\t" << offsetLength << " getLength() : " + << getLength() << "\tsegment_offset:\t" << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << LL_ENDL; + } + + S32 num_chars = mStyle->getFont()->maxDrawableChars( text.c_str() + (segment_offset + mStart), + (F32)num_pixels, + max_chars, + word_wrap_style); + + if (num_chars == 0 + && line_offset == 0 + && max_chars > 0) + { + // If at the beginning of a line, and a single character won't fit, draw it anyway + num_chars = 1; + } + + // include *either* the EOF or newline character in this run of text + // but not both + S32 last_char_in_run = mStart + segment_offset + num_chars; + // check length first to avoid indexing off end of string + if (last_char_in_run < mEnd + && (last_char_in_run >= getLength())) + { + num_chars++; + } + return num_chars; } void LLNormalTextSegment::dump() const { - LL_INFOS() << "Segment [" << -// mColor.mV[VX] << ", " << -// mColor.mV[VY] << ", " << -// mColor.mV[VZ] << "]\t[" << - mStart << ", " << - getEnd() << "]" << - LL_ENDL; + LL_INFOS() << "Segment [" << +// mColor.mV[VX] << ", " << +// mColor.mV[VY] << ", " << +// mColor.mV[VZ] << "]\t[" << + mStart << ", " << + getEnd() << "]" << + LL_ENDL; } /*virtual*/ -const LLWString& LLNormalTextSegment::getWText() const +const LLWString& LLNormalTextSegment::getWText() const { - return mEditor.getWText(); + return mEditor.getWText(); } /*virtual*/ const S32 LLNormalTextSegment::getLength() const { - return mEditor.getLength(); + return mEditor.getLength(); } LLLabelTextSegment::LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ) -: LLNormalTextSegment(style, start, end, editor) +: LLNormalTextSegment(style, start, end, editor) { } LLLabelTextSegment::LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) -: LLNormalTextSegment(color, start, end, editor, is_visible) +: LLNormalTextSegment(color, start, end, editor, is_visible) { } /*virtual*/ -const LLWString& LLLabelTextSegment::getWText() const +const LLWString& LLLabelTextSegment::getWText() const { - return mEditor.getWlabel(); + return mEditor.getWlabel(); } /*virtual*/ const S32 LLLabelTextSegment::getLength() const { - return mEditor.getWlabel().length(); + return mEditor.getWlabel().length(); } // // LLEmojiTextSegment // LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor) - : LLNormalTextSegment(style, start, end, editor) + : LLNormalTextSegment(style, start, end, editor) { } LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) - : LLNormalTextSegment(color, start, end, editor, is_visible) + : LLNormalTextSegment(color, start, end, editor, is_visible) { } BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { - if (mTooltip.empty()) - { - LLWString emoji = getWText().substr(getStart(), getEnd() - getStart()); - if (!emoji.empty()) - { - mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]); - } - } + if (mTooltip.empty()) + { + LLWString emoji = getWText().substr(getStart(), getEnd() - getStart()); + if (!emoji.empty()) + { + mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]); + } + } - return LLNormalTextSegment::handleToolTip(x, y, mask); + return LLNormalTextSegment::handleToolTip(x, y, mask); } // @@ -3655,26 +3645,26 @@ BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) // LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ): - LLNormalTextSegment(normal_style, start, end, editor), - mHoveredStyle(style), - mNormalStyle(normal_style){} + LLNormalTextSegment(normal_style, start, end, editor), + mHoveredStyle(style), + mNormalStyle(normal_style){} -/*virtual*/ +/*virtual*/ F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { - F32 result = LLNormalTextSegment::draw(start, end, selection_start, selection_end, draw_rect); - if (end == mEnd - mStart) - { - mStyle = mNormalStyle; - } - return result; + F32 result = LLNormalTextSegment::draw(start, end, selection_start, selection_end, draw_rect); + if (end == mEnd - mStart) + { + mStyle = mNormalStyle; + } + return result; } /*virtual*/ BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask) { - mStyle = mEditor.getSkipLinkUnderline() ? mNormalStyle : mHoveredStyle; - return LLNormalTextSegment::handleHover(x, y, mask); + mStyle = mEditor.getSkipLinkUnderline() ? mNormalStyle : mHoveredStyle; + return LLNormalTextSegment::handleHover(x, y, mask); } @@ -3683,128 +3673,128 @@ BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask) // LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end) -: LLTextSegment(start, end), - mView(p.view), - mForceNewLine(p.force_newline), - mLeftPad(p.left_pad), - mRightPad(p.right_pad), - mTopPad(p.top_pad), - mBottomPad(p.bottom_pad) +: LLTextSegment(start, end), + mView(p.view), + mForceNewLine(p.force_newline), + mLeftPad(p.left_pad), + mRightPad(p.right_pad), + mTopPad(p.top_pad), + mBottomPad(p.bottom_pad) { -} +} LLInlineViewSegment::~LLInlineViewSegment() { - mView->die(); + mView->die(); } bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { - if (first_char == 0 && num_chars == 0) - { - // We didn't fit on a line or were forced to new string - // the widget will fall on the next line, so width here is 0 - width = 0; - - if (mForceNewLine) - { - // Chat, string can't be smaller then font height even if it is empty - LLStyleSP s(new LLStyle(LLStyle::Params().visible(true))); - height = s->getFont()->getLineHeight(); - - return true; // new line - } - else - { - // height from previous segment in same string will be used, word-wrap - height = 0; - } - - } - else - { - width = mLeftPad + mRightPad + mView->getRect().getWidth(); - height = mBottomPad + mTopPad + mView->getRect().getHeight(); - } - - return false; -} - -S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const -{ - // if putting a widget anywhere but at the beginning of a line - // and the widget doesn't fit or mForceNewLine is true - // then return 0 chars for that line, and all characters for the next - if (mForceNewLine && line_ind == 0) - { - return 0; - } - else if (line_offset != 0 && num_pixels < mView->getRect().getWidth()) - { - return 0; - } - else - { - return mEnd - mStart; - } + if (first_char == 0 && num_chars == 0) + { + // We didn't fit on a line or were forced to new string + // the widget will fall on the next line, so width here is 0 + width = 0; + + if (mForceNewLine) + { + // Chat, string can't be smaller then font height even if it is empty + LLStyleSP s(new LLStyle(LLStyle::Params().visible(true))); + height = s->getFont()->getLineHeight(); + + return true; // new line + } + else + { + // height from previous segment in same string will be used, word-wrap + height = 0; + } + + } + else + { + width = mLeftPad + mRightPad + mView->getRect().getWidth(); + height = mBottomPad + mTopPad + mView->getRect().getHeight(); + } + + return false; +} + +S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const +{ + // if putting a widget anywhere but at the beginning of a line + // and the widget doesn't fit or mForceNewLine is true + // then return 0 chars for that line, and all characters for the next + if (mForceNewLine && line_ind == 0) + { + return 0; + } + else if (line_offset != 0 && num_pixels < mView->getRect().getWidth()) + { + return 0; + } + else + { + return mEnd - mStart; + } } void LLInlineViewSegment::updateLayout(const LLTextBase& editor) { - LLRect start_rect = editor.getDocRectFromDocIndex(mStart); - mView->setOrigin(start_rect.mLeft + mLeftPad, start_rect.mBottom + mBottomPad); + LLRect start_rect = editor.getDocRectFromDocIndex(mStart); + mView->setOrigin(start_rect.mLeft + mLeftPad, start_rect.mBottom + mBottomPad); } -F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) +F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { - // return padded width of widget - // widget is actually drawn during mDocumentView's draw() - return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mLeftPad + mRightPad); + // return padded width of widget + // widget is actually drawn during mDocumentView's draw() + return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mLeftPad + mRightPad); } void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor) { - editor->removeDocumentChild(mView); + editor->removeDocumentChild(mView); } void LLInlineViewSegment::linkToDocument(LLTextBase* editor) { - editor->addDocumentChild(mView); + editor->addDocumentChild(mView); } LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1) { - LLStyleSP s( new LLStyle(LLStyle::Params().visible(true))); + LLStyleSP s( new LLStyle(LLStyle::Params().visible(true))); - mFontHeight = s->getFont()->getLineHeight(); + mFontHeight = s->getFont()->getLineHeight(); } LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1) { - mFontHeight = style->getFont()->getLineHeight(); + mFontHeight = style->getFont()->getLineHeight(); } LLLineBreakTextSegment::~LLLineBreakTextSegment() { } bool LLLineBreakTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { - width = 0; - height = mFontHeight; + width = 0; + height = mFontHeight; - return true; + return true; } -S32 LLLineBreakTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const +S32 LLLineBreakTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { - return 1; + return 1; } -F32 LLLineBreakTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) +F32 LLLineBreakTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { - return draw_rect.mLeft; + return draw_rect.mLeft; } LLImageTextSegment::LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor) -: LLTextSegment(pos,pos+1), - mStyle( style ), - mEditor(editor) +: LLTextSegment(pos,pos+1), + mStyle( style ), + mEditor(editor) { } @@ -3816,78 +3806,78 @@ static const S32 IMAGE_HPAD = 3; bool LLImageTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { - width = 0; - height = mStyle->getFont()->getLineHeight(); + width = 0; + height = mStyle->getFont()->getLineHeight(); - LLUIImagePtr image = mStyle->getImage(); - if( num_chars>0 && image.notNull()) - { - width += image->getWidth() + IMAGE_HPAD; - height = llmax(height, image->getHeight() + IMAGE_HPAD ); - } - return false; + LLUIImagePtr image = mStyle->getImage(); + if( num_chars>0 && image.notNull()) + { + width += image->getWidth() + IMAGE_HPAD; + height = llmax(height, image->getHeight() + IMAGE_HPAD ); + } + return false; } -S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const +S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { - LLUIImagePtr image = mStyle->getImage(); - - if (image.isNull()) - { - return 1; - } + LLUIImagePtr image = mStyle->getImage(); - S32 image_width = image->getWidth(); - if(line_offset == 0 || num_pixels>image_width + IMAGE_HPAD) - { - return 1; - } + if (image.isNull()) + { + return 1; + } - return 0; + S32 image_width = image->getWidth(); + if(line_offset == 0 || num_pixels>image_width + IMAGE_HPAD) + { + return 1; + } + + return 0; } BOOL LLImageTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { - if (!mTooltip.empty()) - { - LLToolTipMgr::instance().show(mTooltip); - return TRUE; - } + if (!mTooltip.empty()) + { + LLToolTipMgr::instance().show(mTooltip); + return TRUE; + } - return FALSE; + return FALSE; } void LLImageTextSegment::setToolTip(const std::string& tooltip) { - mTooltip = tooltip; -} - -F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) -{ - if ( (start >= 0) && (end <= mEnd - mStart)) - { - LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha; - LLUIImagePtr image = mStyle->getImage(); - if (image.notNull()) - { - S32 style_image_height = image->getHeight(); - S32 style_image_width = image->getWidth(); - // Text is drawn from the top of the draw_rect downward - - S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2); - // Align image to center of draw rect - S32 image_bottom = text_center - (style_image_height / 2); - image->draw(draw_rect.mLeft, image_bottom, - style_image_width, style_image_height, color); - - const S32 IMAGE_HPAD = 3; - return draw_rect.mLeft + style_image_width + IMAGE_HPAD; - } - } - return 0.0; + mTooltip = tooltip; +} + +F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) +{ + if ( (start >= 0) && (end <= mEnd - mStart)) + { + LLColor4 color = LLColor4::white % mEditor.getDrawContext().mAlpha; + LLUIImagePtr image = mStyle->getImage(); + if (image.notNull()) + { + S32 style_image_height = image->getHeight(); + S32 style_image_width = image->getWidth(); + // Text is drawn from the top of the draw_rect downward + + S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2); + // Align image to center of draw rect + S32 image_bottom = text_center - (style_image_height / 2); + image->draw(draw_rect.mLeft, image_bottom, + style_image_width, style_image_height, color); + + const S32 IMAGE_HPAD = 3; + return draw_rect.mLeft + style_image_width + IMAGE_HPAD; + } + } + return 0.0; } void LLTextBase::setWordWrap(bool wrap) { - mWordWrap = wrap; + mWordWrap = wrap; } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9d3c54fbee..97507fe800 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -1,4 +1,4 @@ -/** +/** * @file lltextbase.h * @author Martin Reddy * @brief The base class of text box/editor, providing Url handling support @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,116 +51,116 @@ class LLUrlMatch; /// includes a start/end offset from the start of the string, a /// style to render with, an optional tooltip, etc. /// -class LLTextSegment -: public LLRefCount, - public LLMouseHandler +class LLTextSegment +: public LLRefCount, + public LLMouseHandler { public: - LLTextSegment(S32 start, S32 end) - : mStart(start), - mEnd(end) - {} - virtual ~LLTextSegment(); - bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; - - virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; - - /** - * Get number of chars that fit into free part of current line. - * - * @param num_pixels - maximum width of rect - * @param segment_offset - symbol in segment we start processing line from - * @param line_offset - symbol in line after which segment starts - * @param max_chars - limit of symbols that will fit in current line - * @param line_ind - index of not word-wrapped string inside segment for multi-line segments. - * Two string separated by word-wrap will have same index. - * @return number of chars that will fit into current line - */ - virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; - virtual void updateLayout(const class LLTextBase& editor); - virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - virtual bool canEdit() const; - virtual void unlinkFromDocument(class LLTextBase* editor); - virtual void linkToDocument(class LLTextBase* editor); - - virtual const LLColor4& getColor() const; - //virtual void setColor(const LLColor4 &color); - virtual LLStyleConstSP getStyle() const; - virtual void setStyle(LLStyleConstSP style); - virtual void setToken( LLKeywordToken* token ); - virtual LLKeywordToken* getToken() const; - virtual void setToolTip(const std::string& tooltip); - virtual void dump() const; - - // LLMouseHandler interface - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); - /*virtual*/ const std::string& getName() const; - /*virtual*/ void onMouseCaptureLost(); - /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; - /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; - /*virtual*/ BOOL hasMouseCapture(); - - S32 getStart() const { return mStart; } - void setStart(S32 start) { mStart = start; } - S32 getEnd() const { return mEnd; } - void setEnd( S32 end ) { mEnd = end; } + LLTextSegment(S32 start, S32 end) + : mStart(start), + mEnd(end) + {} + virtual ~LLTextSegment(); + bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; + + virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; + + /** + * Get number of chars that fit into free part of current line. + * + * @param num_pixels - maximum width of rect + * @param segment_offset - symbol in segment we start processing line from + * @param line_offset - symbol in line after which segment starts + * @param max_chars - limit of symbols that will fit in current line + * @param line_ind - index of not word-wrapped string inside segment for multi-line segments. + * Two string separated by word-wrap will have same index. + * @return number of chars that will fit into current line + */ + virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; + virtual void updateLayout(const class LLTextBase& editor); + virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + virtual bool canEdit() const; + virtual void unlinkFromDocument(class LLTextBase* editor); + virtual void linkToDocument(class LLTextBase* editor); + + virtual const LLColor4& getColor() const; + //virtual void setColor(const LLColor4 &color); + virtual LLStyleConstSP getStyle() const; + virtual void setStyle(LLStyleConstSP style); + virtual void setToken( LLKeywordToken* token ); + virtual LLKeywordToken* getToken() const; + virtual void setToolTip(const std::string& tooltip); + virtual void dump() const; + + // LLMouseHandler interface + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ const std::string& getName() const; + /*virtual*/ void onMouseCaptureLost(); + /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; + /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; + /*virtual*/ BOOL hasMouseCapture(); + + S32 getStart() const { return mStart; } + void setStart(S32 start) { mStart = start; } + S32 getEnd() const { return mEnd; } + void setEnd( S32 end ) { mEnd = end; } protected: - S32 mStart; - S32 mEnd; + S32 mStart; + S32 mEnd; }; class LLNormalTextSegment : public LLTextSegment { public: - LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); - LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); - virtual ~LLNormalTextSegment(); - - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; - /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; - /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - /*virtual*/ bool canEdit() const { return true; } - /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } - /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; } - /*virtual*/ void setStyle(LLStyleConstSP style) { mStyle = style; } - /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } - /*virtual*/ LLKeywordToken* getToken() const { return mToken; } - /*virtual*/ BOOL getToolTip( std::string& msg ) const; - /*virtual*/ void setToolTip(const std::string& tooltip); - /*virtual*/ void dump() const; - - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); + LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + virtual ~LLNormalTextSegment(); + + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + /*virtual*/ bool canEdit() const { return true; } + /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } + /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; } + /*virtual*/ void setStyle(LLStyleConstSP style) { mStyle = style; } + /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } + /*virtual*/ LLKeywordToken* getToken() const { return mToken; } + /*virtual*/ BOOL getToolTip( std::string& msg ) const; + /*virtual*/ void setToolTip(const std::string& tooltip); + /*virtual*/ void dump() const; + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); protected: - F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect); + F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect); - virtual const LLWString& getWText() const; - virtual const S32 getLength() const; + virtual const LLWString& getWText() const; + virtual const S32 getLength() const; protected: - class LLTextBase& mEditor; - LLStyleConstSP mStyle; - S32 mFontHeight; - LLKeywordToken* mToken; - std::string mTooltip; - boost::signals2::connection mImageLoadedConnection; + class LLTextBase& mEditor; + LLStyleConstSP mStyle; + S32 mFontHeight; + LLKeywordToken* mToken; + std::string mTooltip; + boost::signals2::connection mImageLoadedConnection; }; // This text segment is the same as LLNormalTextSegment, the only difference @@ -169,13 +169,13 @@ protected: class LLLabelTextSegment : public LLNormalTextSegment { public: - LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); - LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); + LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); protected: - /*virtual*/ const LLWString& getWText() const; - /*virtual*/ const S32 getLength() const; + /*virtual*/ const LLWString& getWText() const; + /*virtual*/ const S32 getLength() const; }; // Text segment that represents a single emoji character that has a different style (=font size) than the rest of @@ -183,99 +183,99 @@ protected: class LLEmojiTextSegment : public LLNormalTextSegment { public: - LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); - LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); + LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); - bool canEdit() const override { return false; } - BOOL handleToolTip(S32 x, S32 y, MASK mask) override; + bool canEdit() const override { return false; } + BOOL handleToolTip(S32 x, S32 y, MASK mask) override; }; // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) class LLOnHoverChangeableTextSegment : public LLNormalTextSegment { public: - LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ); - /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ); + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); protected: - // Style used for text when mouse pointer is over segment - LLStyleConstSP mHoveredStyle; - // Style used for text when mouse pointer is outside segment - LLStyleConstSP mNormalStyle; + // Style used for text when mouse pointer is over segment + LLStyleConstSP mHoveredStyle; + // Style used for text when mouse pointer is outside segment + LLStyleConstSP mNormalStyle; }; class LLIndexSegment : public LLTextSegment { public: - LLIndexSegment() : LLTextSegment(0, 0) {} + LLIndexSegment() : LLTextSegment(0, 0) {} }; class LLInlineViewSegment : public LLTextSegment { public: - struct Params : public LLInitParam::Block<Params> - { - Mandatory<LLView*> view; - Optional<bool> force_newline; - Optional<S32> left_pad, - right_pad, - bottom_pad, - top_pad; - }; - - LLInlineViewSegment(const Params& p, S32 start, S32 end); - ~LLInlineViewSegment(); - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; - /*virtual*/ void updateLayout(const class LLTextBase& editor); - /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - /*virtual*/ bool canEdit() const { return false; } - /*virtual*/ void unlinkFromDocument(class LLTextBase* editor); - /*virtual*/ void linkToDocument(class LLTextBase* editor); + struct Params : public LLInitParam::Block<Params> + { + Mandatory<LLView*> view; + Optional<bool> force_newline; + Optional<S32> left_pad, + right_pad, + bottom_pad, + top_pad; + }; + + LLInlineViewSegment(const Params& p, S32 start, S32 end); + ~LLInlineViewSegment(); + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; + /*virtual*/ void updateLayout(const class LLTextBase& editor); + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + /*virtual*/ bool canEdit() const { return false; } + /*virtual*/ void unlinkFromDocument(class LLTextBase* editor); + /*virtual*/ void linkToDocument(class LLTextBase* editor); private: - S32 mLeftPad; - S32 mRightPad; - S32 mTopPad; - S32 mBottomPad; - LLView* mView; - bool mForceNewLine; + S32 mLeftPad; + S32 mRightPad; + S32 mTopPad; + S32 mBottomPad; + LLView* mView; + bool mForceNewLine; }; class LLLineBreakTextSegment : public LLTextSegment { public: - LLLineBreakTextSegment(LLStyleConstSP style,S32 pos); - LLLineBreakTextSegment(S32 pos); - ~LLLineBreakTextSegment(); - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; - F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + LLLineBreakTextSegment(LLStyleConstSP style,S32 pos); + LLLineBreakTextSegment(S32 pos); + ~LLLineBreakTextSegment(); + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; + F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); private: - S32 mFontHeight; + S32 mFontHeight; }; class LLImageTextSegment : public LLTextSegment { public: - LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); - ~LLImageTextSegment(); - /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; - S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; - F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); + LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); + ~LLImageTextSegment(); + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; + S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; + F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); - /*virtual*/ void setToolTip(const std::string& tooltip); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ void setToolTip(const std::string& tooltip); private: - class LLTextBase& mEditor; - LLStyleConstSP mStyle; + class LLTextBase& mEditor; + LLStyleConstSP mStyle; protected: - std::string mTooltip; + std::string mTooltip; }; typedef LLPointer<LLTextSegment> LLTextSegmentPtr; @@ -286,469 +286,473 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr; /// such as Url highlighting and opening. /// class LLTextBase -: public LLUICtrl, - protected LLEditMenuHandler, - public LLSpellCheckMenuHandler, - public ll::ui::SearchableControl +: public LLUICtrl, + protected LLEditMenuHandler, + public LLSpellCheckMenuHandler, + public ll::ui::SearchableControl { public: - friend class LLTextSegment; - friend class LLNormalTextSegment; - friend class LLUICtrlFactory; - - typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t; - typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t; - - struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams> - { - Alternative<F32> multiple; - Alternative<S32> pixels; - LineSpacingParams(); - }; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<LLUIColor> cursor_color, - text_color, - text_readonly_color, - text_tentative_color, - bg_readonly_color, - bg_writeable_color, - bg_focus_color, - text_selected_color, - bg_selected_color; - - Optional<bool> bg_visible, - border_visible, - track_end, - read_only, - skip_link_underline, - spellcheck, - allow_scroll, - plain_text, - wrap, - use_ellipses, - use_color, - parse_urls, - force_urls_external, - parse_highlights, - clip, - clip_partial, - trusted_content, - always_show_icons; - - Optional<S32> v_pad, - h_pad; - - - Optional<LineSpacingParams> - line_spacing; - - Optional<S32> max_text_length; - - Optional<LLFontGL::ShadowType> font_shadow; - - Optional<LLFontGL::VAlign> text_valign; - - Params(); - }; - - // LLMouseHandler interface - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override; - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override; - - // LLView interface - /*virtual*/ const std::string getToolTip() const override; - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; - /*virtual*/ void draw() override; - - // LLUICtrl interface - /*virtual*/ BOOL acceptsTextInput() const override { return !mReadOnly; } - /*virtual*/ void setColor(const LLColor4& c) override; - virtual void setReadOnlyColor(const LLColor4 &c); - /*virtual*/ void onVisibilityChange(BOOL new_visibility) override; - - /*virtual*/ void setValue(const LLSD& value) override; - /*virtual*/ LLTextViewModel* getViewModel() const override; - - // LLEditMenuHandler interface - /*virtual*/ BOOL canDeselect() const override; - /*virtual*/ void deselect() override; - - virtual void onFocusReceived() override; - virtual void onFocusLost() override; + friend class LLTextSegment; + friend class LLNormalTextSegment; + friend class LLUICtrlFactory; + + typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t; + typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t; + + struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams> + { + Alternative<F32> multiple; + Alternative<S32> pixels; + LineSpacingParams(); + }; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLUIColor> cursor_color, + text_color, + text_readonly_color, + text_tentative_color, + bg_readonly_color, + bg_writeable_color, + bg_focus_color, + text_selected_color, + bg_selected_color; + + Optional<bool> bg_visible, + border_visible, + track_end, + read_only, + skip_link_underline, + spellcheck, + allow_scroll, + plain_text, + wrap, + use_ellipses, + use_emoji, + use_color, + parse_urls, + force_urls_external, + parse_highlights, + clip, + clip_partial, + trusted_content, + always_show_icons; + + Optional<S32> v_pad, + h_pad; + + + Optional<LineSpacingParams> + line_spacing; + + Optional<S32> max_text_length; + + Optional<LLFontGL::ShadowType> font_shadow; + + Optional<LLFontGL::VAlign> text_valign; + + Params(); + }; + + // LLMouseHandler interface + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override; + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override; + + // LLView interface + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + /*virtual*/ void draw() override; + + // LLUICtrl interface + /*virtual*/ BOOL acceptsTextInput() const override { return !mReadOnly; } + /*virtual*/ void setColor(const LLColor4& c) override; + virtual void setReadOnlyColor(const LLColor4 &c); + /*virtual*/ void onVisibilityChange(BOOL new_visibility) override; + + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLTextViewModel* getViewModel() const override; + + // LLEditMenuHandler interface + /*virtual*/ BOOL canDeselect() const override; + /*virtual*/ void deselect() override; + + virtual void onFocusReceived() override; + virtual void onFocusLost() override; void setParseHTML(bool parse_html) { mParseHTML = parse_html; } - // LLSpellCheckMenuHandler overrides - /*virtual*/ bool getSpellCheck() const override; + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const override; - /*virtual*/ const std::string& getSuggestion(U32 index) const override; - /*virtual*/ U32 getSuggestionCount() const override; - /*virtual*/ void replaceWithSuggestion(U32 index) override; + /*virtual*/ const std::string& getSuggestion(U32 index) const override; + /*virtual*/ U32 getSuggestionCount() const override; + /*virtual*/ void replaceWithSuggestion(U32 index) override; - /*virtual*/ void addToDictionary() override; - /*virtual*/ bool canAddToDictionary() const override; + /*virtual*/ void addToDictionary() override; + /*virtual*/ bool canAddToDictionary() const override; - /*virtual*/ void addToIgnore() override; - /*virtual*/ bool canAddToIgnore() const override; + /*virtual*/ void addToIgnore() override; + /*virtual*/ bool canAddToIgnore() const override; - // Spell checking helper functions - std::string getMisspelledWord(U32 pos) const; - bool isMisspelledWord(U32 pos) const; - void onSpellCheckSettingsChange(); - virtual void onSpellCheckPerformed(){} + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + virtual void onSpellCheckPerformed(){} - // used by LLTextSegment layout code - bool getWordWrap() { return mWordWrap; } - bool getUseEllipses() { return mUseEllipses; } - bool getUseColor() { return mUseColor; } - bool truncate(); // returns true of truncation occurred + // used by LLTextSegment layout code + bool getWordWrap() const { return mWordWrap; } + bool getUseEllipses() const { return mUseEllipses; } + bool getUseEmoji() const { return mUseEmoji; } + void setUseEmoji(bool value) { mUseEmoji = value; } + bool getUseColor() const { return mUseColor; } + void setUseColor(bool value) { mUseColor = value; } + bool truncate(); // returns true of truncation occurred - bool isContentTrusted() {return mTrustedContent;} - void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; } + bool isContentTrusted() const { return mTrustedContent; } + void setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; } - // TODO: move into LLTextSegment? - void createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url + // TODO: move into LLTextSegment? + void createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url - // Text accessors - // TODO: add optional style parameter - virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style - virtual std::string getText() const; - void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } - S32 getMaxTextLength() { return mMaxTextByteLength; } + // Text accessors + // TODO: add optional style parameter + virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style + /*virtual*/ const std::string& getText() const override; + void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } + S32 getMaxTextLength() { return mMaxTextByteLength; } - // wide-char versions - void setWText(const LLWString& text); - const LLWString& getWText() const; + // wide-char versions + void setWText(const LLWString& text); + const LLWString& getWText() const; - void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); + void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); - void setLabel(const LLStringExplicit& label); - /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; + void setLabel(const LLStringExplicit& label); + /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; - const std::string& getLabel() { return mLabel.getString(); } - const LLWString& getWlabel() { return mLabel.getWString();} + const std::string& getLabel() { return mLabel.getString(); } + const LLWString& getWlabel() { return mLabel.getWString();} - void setLastSegmentToolTip(const std::string &tooltip); + void setLastSegmentToolTip(const std::string &tooltip); - /** - * If label is set, draws text label (which is LLLabelTextSegment) - * that is visible when no user text provided - */ - void resetLabel(); + /** + * If label is set, draws text label (which is LLLabelTextSegment) + * that is visible when no user text provided + */ + void resetLabel(); - void setFont(const LLFontGL* font); + void setFont(const LLFontGL* font); - // force reflow of text - void needsReflow(S32 index = 0); + // force reflow of text + void needsReflow(S32 index = 0); - S32 getLength() const { return getWText().length(); } - S32 getLineCount() const { return mLineInfoList.size(); } - S32 removeFirstLine(); // returns removed length + S32 getLength() const { return getWText().length(); } + S32 getLineCount() const { return mLineInfoList.size(); } + S32 removeFirstLine(); // returns removed length - void addDocumentChild(LLView* view); - void removeDocumentChild(LLView* view); - const LLView* getDocumentView() const { return mDocumentView; } - LLRect getVisibleTextRect() const { return mVisibleTextRect; } - LLRect getTextBoundingRect(); - LLRect getVisibleDocumentRect() const; + void addDocumentChild(LLView* view); + void removeDocumentChild(LLView* view); + const LLView* getDocumentView() const { return mDocumentView; } + LLRect getVisibleTextRect() const { return mVisibleTextRect; } + LLRect getTextBoundingRect(); + LLRect getVisibleDocumentRect() const; - S32 getVPad() { return mVPad; } - S32 getHPad() { return mHPad; } - F32 getLineSpacingMult() { return mLineSpacingMult; } - S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline + S32 getVPad() { return mVPad; } + S32 getHPad() { return mHPad; } + F32 getLineSpacingMult() { return mLineSpacingMult; } + S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline - S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line = true) const; - LLRect getLocalRectFromDocIndex(S32 pos) const; - LLRect getDocRectFromDocIndex(S32 pos) const; + S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line = true) const; + LLRect getLocalRectFromDocIndex(S32 pos) const; + LLRect getDocRectFromDocIndex(S32 pos) const; - void setReadOnly(bool read_only) { mReadOnly = read_only; } - bool getReadOnly() { return mReadOnly; } + void setReadOnly(bool read_only) { mReadOnly = read_only; } + bool getReadOnly() { return mReadOnly; } - void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; } - bool getSkipLinkUnderline() { return mSkipLinkUnderline; } + void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; } + bool getSkipLinkUnderline() { return mSkipLinkUnderline; } - void setParseURLs(bool parse_urls) { mParseHTML = parse_urls; } + void setParseURLs(bool parse_urls) { mParseHTML = parse_urls; } - void setPlainText(bool value) { mPlainText = value;} - bool getPlainText() const { return mPlainText; } + void setPlainText(bool value) { mPlainText = value;} + bool getPlainText() const { return mPlainText; } - // cursor manipulation - bool setCursor(S32 row, S32 column); - bool setCursorPos(S32 cursor_pos, bool keep_cursor_offset = false); - void startOfLine(); - void endOfLine(); - void startOfDoc(); - void endOfDoc(); - void changePage( S32 delta ); - void changeLine( S32 delta ); + // cursor manipulation + bool setCursor(S32 row, S32 column); + bool setCursorPos(S32 cursor_pos, bool keep_cursor_offset = false); + void startOfLine(); + void endOfLine(); + void startOfDoc(); + void endOfDoc(); + void changePage( S32 delta ); + void changeLine( S32 delta ); - bool scrolledToStart(); - bool scrolledToEnd(); + bool scrolledToStart(); + bool scrolledToEnd(); - const LLFontGL* getFont() const { return mFont; } + const LLFontGL* getFont() const override { return mFont; } - virtual void appendLineBreakSegment(const LLStyle::Params& style_params); - virtual void appendImageSegment(const LLStyle::Params& style_params); - virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb); - boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); - boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb); + virtual void appendLineBreakSegment(const LLStyle::Params& style_params); + virtual void appendImageSegment(const LLStyle::Params& style_params); + virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb); + boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); + boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb); - void setWordWrap(bool wrap); - LLScrollContainer* getScrollContainer() const { return mScroller; } + void setWordWrap(bool wrap); + LLScrollContainer* getScrollContainer() const { return mScroller; } protected: - // protected member variables - // List of offsets and segment index of the start of each line. Always has at least one node (0). - struct line_info - { - line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num); - S32 mDocIndexStart; - S32 mDocIndexEnd; - LLRect mRect; - S32 mLineNum; // actual line count (ignoring soft newlines due to word wrap) - }; - typedef std::vector<line_info> line_list_t; - - // helper structs - struct compare_bottom - { - bool operator()(const S32& a, const line_info& b) const; - bool operator()(const line_info& a, const S32& b) const; - bool operator()(const line_info& a, const line_info& b) const; - }; - struct compare_top - { - bool operator()(const S32& a, const line_info& b) const; - bool operator()(const line_info& a, const S32& b) const; - bool operator()(const line_info& a, const line_info& b) const; - }; - struct line_end_compare; - typedef std::vector<LLTextSegmentPtr> segment_vec_t; - - // Abstract inner base class representing an undoable editor command. - // Concrete sub-classes can be defined for operations such as insert, remove, etc. - // Used as arguments to the execute() method below. - class TextCmd - { - public: - TextCmd( S32 pos, BOOL group_with_next, LLTextSegmentPtr segment = LLTextSegmentPtr() ) - : mPos(pos), - mGroupWithNext(group_with_next) - { - if (segment.notNull()) - { - mSegments.push_back(segment); - } - } - virtual ~TextCmd() {} - virtual BOOL execute(LLTextBase* editor, S32* delta) = 0; - virtual S32 undo(LLTextBase* editor) = 0; - virtual S32 redo(LLTextBase* editor) = 0; - virtual BOOL canExtend(S32 pos) const { return FALSE; } - virtual void blockExtensions() {} - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; } - virtual BOOL hasExtCharValue( llwchar value ) const { return FALSE; } - - // Defined here so they can access protected LLTextEditor editing methods - S32 insert(LLTextBase* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr, &mSegments ); } - S32 remove(LLTextBase* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); } - S32 overwrite(LLTextBase* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); } - - S32 getPosition() const { return mPos; } - BOOL groupWithNext() const { return mGroupWithNext; } - - protected: - const S32 mPos; - BOOL mGroupWithNext; - segment_vec_t mSegments; - }; - - struct compare_segment_end - { - bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const; - }; - typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t; - - // member functions - LLTextBase(const Params &p); - virtual ~LLTextBase(); - void initFromParams(const Params& p); - virtual void beforeValueChange(); - virtual void onValueChange(S32 start, S32 end); + // protected member variables + // List of offsets and segment index of the start of each line. Always has at least one node (0). + struct line_info + { + line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num); + S32 mDocIndexStart; + S32 mDocIndexEnd; + LLRect mRect; + S32 mLineNum; // actual line count (ignoring soft newlines due to word wrap) + }; + typedef std::vector<line_info> line_list_t; + + // helper structs + struct compare_bottom + { + bool operator()(const S32& a, const line_info& b) const; + bool operator()(const line_info& a, const S32& b) const; + bool operator()(const line_info& a, const line_info& b) const; + }; + struct compare_top + { + bool operator()(const S32& a, const line_info& b) const; + bool operator()(const line_info& a, const S32& b) const; + bool operator()(const line_info& a, const line_info& b) const; + }; + struct line_end_compare; + typedef std::vector<LLTextSegmentPtr> segment_vec_t; + + // Abstract inner base class representing an undoable editor command. + // Concrete sub-classes can be defined for operations such as insert, remove, etc. + // Used as arguments to the execute() method below. + class TextCmd + { + public: + TextCmd( S32 pos, BOOL group_with_next, LLTextSegmentPtr segment = LLTextSegmentPtr() ) + : mPos(pos), + mGroupWithNext(group_with_next) + { + if (segment.notNull()) + { + mSegments.push_back(segment); + } + } + virtual ~TextCmd() {} + virtual BOOL execute(LLTextBase* editor, S32* delta) = 0; + virtual S32 undo(LLTextBase* editor) = 0; + virtual S32 redo(LLTextBase* editor) = 0; + virtual BOOL canExtend(S32 pos) const { return FALSE; } + virtual void blockExtensions() {} + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; } + virtual BOOL hasExtCharValue( llwchar value ) const { return FALSE; } + + // Defined here so they can access protected LLTextEditor editing methods + S32 insert(LLTextBase* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr, &mSegments ); } + S32 remove(LLTextBase* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); } + S32 overwrite(LLTextBase* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); } + + S32 getPosition() const { return mPos; } + BOOL groupWithNext() const { return mGroupWithNext; } + + protected: + const S32 mPos; + BOOL mGroupWithNext; + segment_vec_t mSegments; + }; + + struct compare_segment_end + { + bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const; + }; + typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t; + + // member functions + LLTextBase(const Params &p); + virtual ~LLTextBase(); + void initFromParams(const Params& p); + virtual void beforeValueChange(); + virtual void onValueChange(S32 start, S32 end); virtual bool useLabel() const; - // draw methods - virtual void drawSelectionBackground(); // draws the black box behind the selected text - void drawCursor(); - void drawText(); - - // modify contents - S32 insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted - S32 removeStringNoUndo(S32 pos, S32 length); - S32 overwriteCharNoUndo(S32 pos, llwchar wc); - void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false); - - - // manage segments - void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const; - void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ); - LLTextSegmentPtr getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line = true); - segment_set_t::iterator getEditableSegIterContaining(S32 index); - segment_set_t::const_iterator getEditableSegIterContaining(S32 index) const; - segment_set_t::iterator getSegIterContaining(S32 index); - segment_set_t::const_iterator getSegIterContaining(S32 index) const; - void clearSegments(); - void createDefaultSegment(); - virtual void updateSegments(); - void insertSegment(LLTextSegmentPtr segment_to_insert); - const LLStyle::Params& getStyleParams(); - - // manage lines - S32 getLineStart( S32 line ) const; - S32 getLineEnd( S32 line ) const; - S32 getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; - S32 getLineOffsetFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; - S32 getFirstVisibleLine() const; - std::pair<S32, S32> getVisibleLines(bool fully_visible = false); - S32 getLeftOffset(S32 width); - void reflow(); - - // cursor - void updateCursorXPos(); - void setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset=false ); - S32 getEditableIndex(S32 index, bool increasing_direction); // constraint cursor to editable segments of document - void resetCursorBlink() { mCursorBlinkTimer.reset(); } - void updateScrollFromCursor(); - - // text selection - bool hasSelection() const { return (mSelectionStart !=mSelectionEnd); } - void startSelection(); - void endSelection(); - - // misc - void updateRects(); - void needsScroll() { mScrollNeeded = TRUE; } - - struct URLLabelCallback; - // Replace a URL with a new icon and label, for example, when - // avatar names are looked up. - void replaceUrl(const std::string &url, const std::string &label, const std::string& icon); - - void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); - void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); - S32 normalizeUri(std::string& uri); - + // draw methods + virtual void drawSelectionBackground(); // draws the black box behind the selected text + void drawCursor(); + void drawText(); + + // modify contents + S32 insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted + S32 removeStringNoUndo(S32 pos, S32 length); + S32 overwriteCharNoUndo(S32 pos, llwchar wc); + void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false); + + + // manage segments + void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const; + void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ); + LLTextSegmentPtr getSegmentAtLocalPos( S32 x, S32 y, bool hit_past_end_of_line = true); + segment_set_t::iterator getEditableSegIterContaining(S32 index); + segment_set_t::const_iterator getEditableSegIterContaining(S32 index) const; + segment_set_t::iterator getSegIterContaining(S32 index); + segment_set_t::const_iterator getSegIterContaining(S32 index) const; + void clearSegments(); + void createDefaultSegment(); + virtual void updateSegments(); + void insertSegment(LLTextSegmentPtr segment_to_insert); + const LLStyle::Params& getStyleParams(); + + // manage lines + S32 getLineStart( S32 line ) const; + S32 getLineEnd( S32 line ) const; + S32 getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; + S32 getLineOffsetFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; + S32 getFirstVisibleLine() const; + std::pair<S32, S32> getVisibleLines(bool fully_visible = false); + S32 getLeftOffset(S32 width); + void reflow(); + + // cursor + void updateCursorXPos(); + void setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset=false ); + S32 getEditableIndex(S32 index, bool increasing_direction); // constraint cursor to editable segments of document + void resetCursorBlink() { mCursorBlinkTimer.reset(); } + void updateScrollFromCursor(); + + // text selection + bool hasSelection() const { return (mSelectionStart !=mSelectionEnd); } + void startSelection(); + void endSelection(); + + // misc + void updateRects(); + void needsScroll() { mScrollNeeded = TRUE; } + + struct URLLabelCallback; + // Replace a URL with a new icon and label, for example, when + // avatar names are looked up. + void replaceUrl(const std::string &url, const std::string &label, const std::string& icon); + + void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); + void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); + S32 normalizeUri(std::string& uri); + protected: - // virtual - std::string _getSearchText() const override - { - return mLabel.getString() + getToolTip(); - } + // virtual + std::string _getSearchText() const override + { + return mLabel.getString() + getToolTip(); + } std::vector<LLRect> getSelectionRects(); protected: - // text segmentation and flow - segment_set_t mSegments; - line_list_t mLineInfoList; - LLRect mVisibleTextRect; // The rect in which text is drawn. Excludes borders. - LLRect mTextBoundingRect; - - // default text style - LLStyle::Params mStyle; - bool mStyleDirty; - const LLFontGL* mFont; - const LLFontGL::ShadowType mFontShadow; - - // colors - LLUIColor mCursorColor; - LLUIColor mFgColor; - LLUIColor mReadOnlyFgColor; - LLUIColor mTentativeFgColor; - LLUIColor mWriteableBgColor; - LLUIColor mReadOnlyBgColor; - LLUIColor mFocusBgColor; - LLUIColor mTextSelectedColor; - LLUIColor mSelectedBGColor; - - // cursor - S32 mCursorPos; // I-beam is just after the mCursorPos-th character. - S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be - LLFrameTimer mCursorBlinkTimer; // timer that controls cursor blinking - - // selection - S32 mSelectionStart; - S32 mSelectionEnd; - LLTimer mTripleClickTimer; - - BOOL mIsSelecting; // Are we in the middle of a drag-select? - - // spell checking - bool mSpellCheck; - S32 mSpellCheckStart; - S32 mSpellCheckEnd; - LLTimer mSpellCheckTimer; - std::list<std::pair<U32, U32> > mMisspellRanges; - std::vector<std::string> mSuggestionList; - - // configuration - S32 mHPad; // padding on left of text - S32 mVPad; // padding above text - LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety - LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety - LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text - F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding) - S32 mLineSpacingPixels; // padding between lines - bool mBorderVisible; - bool mParseHTML; // make URLs interactive - bool mForceUrlsExternal; // URLs from this textbox will be opened in external browser - bool mParseHighlights; // highlight user-defined keywords - bool mWordWrap; - bool mUseEllipses; - bool mUseColor; - bool mTrackEnd; // if true, keeps scroll position at end of document during resize - bool mReadOnly; - bool mBGVisible; // render background? - bool mClip; // clip text to widget rect - bool mClipPartial; // false if we show lines that are partially inside bounding rect - bool mTrustedContent; // if false, does not allow to execute SURL links from this editor - bool mPlainText; // didn't use Image or Icon segments - bool mAutoIndent; - S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes - bool mSkipTripleClick; - bool mAlwaysShowIcons; - - bool mSkipLinkUnderline; - - // support widgets - LLHandle<LLContextMenu> mPopupMenuHandle; - LLView* mDocumentView; - LLScrollContainer* mScroller; - - // transient state - 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 - - // Fired when a URL link is clicked - commit_signal_t* mURLClickSignal; - - // Used to check if user with given ID is avatar's friend - is_friend_signal_t* mIsFriendSignal; - is_blocked_signal_t* mIsObjectBlockedSignal; - - LLUIString mLabel; // text label that is visible when no user text provided + // text segmentation and flow + segment_set_t mSegments; + line_list_t mLineInfoList; + LLRect mVisibleTextRect; // The rect in which text is drawn. Excludes borders. + LLRect mTextBoundingRect; + + // default text style + LLStyle::Params mStyle; + bool mStyleDirty; + const LLFontGL* mFont; + const LLFontGL::ShadowType mFontShadow; + + // colors + LLUIColor mCursorColor; + LLUIColor mFgColor; + LLUIColor mReadOnlyFgColor; + LLUIColor mTentativeFgColor; + LLUIColor mWriteableBgColor; + LLUIColor mReadOnlyBgColor; + LLUIColor mFocusBgColor; + LLUIColor mTextSelectedColor; + LLUIColor mSelectedBGColor; + + // cursor + S32 mCursorPos; // I-beam is just after the mCursorPos-th character. + S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be + LLFrameTimer mCursorBlinkTimer; // timer that controls cursor blinking + + // selection + S32 mSelectionStart; + S32 mSelectionEnd; + LLTimer mTripleClickTimer; + + BOOL mIsSelecting; // Are we in the middle of a drag-select? + + // spell checking + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list<std::pair<U32, U32> > mMisspellRanges; + std::vector<std::string> mSuggestionList; + + // configuration + S32 mHPad; // padding on left of text + S32 mVPad; // padding above text + LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety + LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety + LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text + F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding) + S32 mLineSpacingPixels; // padding between lines + bool mBorderVisible; + bool mParseHTML; // make URLs interactive + bool mForceUrlsExternal; // URLs from this textbox will be opened in external browser + bool mParseHighlights; // highlight user-defined keywords + bool mWordWrap; + bool mUseEllipses; + bool mUseEmoji; + bool mUseColor; + bool mTrackEnd; // if true, keeps scroll position at end of document during resize + bool mReadOnly; + bool mBGVisible; // render background? + bool mClip; // clip text to widget rect + bool mClipPartial; // false if we show lines that are partially inside bounding rect + bool mTrustedContent; // if false, does not allow to execute SURL links from this editor + bool mPlainText; // didn't use Image or Icon segments + bool mAutoIndent; + S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes + bool mSkipTripleClick; + bool mAlwaysShowIcons; + + bool mSkipLinkUnderline; + + // support widgets + LLHandle<LLContextMenu> mPopupMenuHandle; + LLView* mDocumentView; + LLScrollContainer* mScroller; + + // transient state + 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 + + // Fired when a URL link is clicked + commit_signal_t* mURLClickSignal; + + // Used to check if user with given ID is avatar's friend + is_friend_signal_t* mIsFriendSignal; + is_blocked_signal_t* mIsObjectBlockedSignal; + + LLUIString mLabel; // text label that is visible when no user text provided }; #endif diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 521dabf9d4..ba756a2906 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltextbox.cpp * @brief A text display widget * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,14 +39,14 @@ static LLDefaultChildRegistry::Register<LLTextBox> r("text"); // Compiler optimization, generate extern template template class LLTextBox* LLView::getChild<class LLTextBox>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; LLTextBox::LLTextBox(const LLTextBox::Params& p) -: LLTextBase(p), - mClickedCallback(NULL), - mShowCursorHand(true) +: LLTextBase(p), + mClickedCallback(NULL), + mShowCursorHand(true) { - mSkipTripleClick = true; + mSkipTripleClick = true; } LLTextBox::~LLTextBox() @@ -54,130 +54,130 @@ LLTextBox::~LLTextBox() BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = LLTextBase::handleMouseDown(x, y, mask); + BOOL handled = LLTextBase::handleMouseDown(x, y, mask); - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } - if (!handled && mClickedCallback) - { - handled = TRUE; - } + if (!handled && mClickedCallback) + { + handled = TRUE; + } - if (handled) - { - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - } + if (handled) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + } - return handled; + return handled; } BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = LLTextBase::handleMouseUp(x, y, mask); - - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } - - // We only handle the click if the click both started and ended within us - if (hasMouseCapture()) - { - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - - // DO THIS AT THE VERY END to allow the button to be destroyed - // as a result of being clicked. If mouseup in the widget, - // it's been clicked - if (mClickedCallback && !handled) - { - mClickedCallback(); - handled = TRUE; - } - } - - return handled; + BOOL handled = LLTextBase::handleMouseUp(x, y, mask); + + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + // We only handle the click if the click both started and ended within us + if (hasMouseCapture()) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + + // DO THIS AT THE VERY END to allow the button to be destroyed + // as a result of being clicked. If mouseup in the widget, + // it's been clicked + if (mClickedCallback && !handled) + { + mClickedCallback(); + handled = TRUE; + } + } + + return handled; } BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = LLTextBase::handleHover(x, y, mask); - if (!handled && mClickedCallback && mShowCursorHand) - { - // Clickable text boxes change the cursor to a hand - LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); - return TRUE; - } - return handled; + BOOL handled = LLTextBase::handleHover(x, y, mask); + if (!handled && mClickedCallback && mShowCursorHand) + { + // Clickable text boxes change the cursor to a hand + LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; + } + return handled; } void LLTextBox::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - LLTextBase::setReadOnly(read_only); - updateSegments(); - } - LLTextBase::setEnabled(enabled); + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + LLTextBase::setReadOnly(read_only); + updateSegments(); + } + LLTextBase::setEnabled(enabled); } void LLTextBox::setText(const LLStringExplicit& text , const LLStyle::Params& input_params ) { - // does string argument insertion - mText.assign(text); - - LLTextBase::setText(mText.getString(), input_params ); + // does string argument insertion + mText.assign(text); + + LLTextBase::setText(mText.getString(), input_params ); } void LLTextBox::setClickedCallback( boost::function<void (void*)> cb, void* userdata /*= NULL */ ) { - mClickedCallback = boost::bind(cb, userdata); + mClickedCallback = boost::bind(cb, userdata); } S32 LLTextBox::getTextPixelWidth() { - return getTextBoundingRect().getWidth(); + return getTextBoundingRect().getWidth(); } S32 LLTextBox::getTextPixelHeight() { - return getTextBoundingRect().getHeight(); + return getTextBoundingRect().getHeight(); } LLSD LLTextBox::getValue() const { - return getViewModel()->getValue(); + return getViewModel()->getValue(); } BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text ) { - mText.setArg(key, text); - LLTextBase::setText(mText.getString()); + mText.setArg(key, text); + LLTextBase::setText(mText.getString()); - return TRUE; + return TRUE; } void LLTextBox::reshapeToFitText(BOOL called_from_parent) { - reflow(); + reflow(); - S32 width = getTextPixelWidth(); - S32 height = getTextPixelHeight(); + S32 width = getTextPixelWidth(); + S32 height = getTextPixelHeight(); //consider investigating reflow() to find missing width pixel (see SL-17045 changes) - reshape( width + 2 * mHPad + 1, height + 2 * mVPad, called_from_parent ); + reshape( width + 2 * mHPad + 1, height + 2 * mVPad, called_from_parent ); } void LLTextBox::onUrlLabelUpdated(const std::string &url, const std::string &label) { - needsReflow(); + needsReflow(); } diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index c3e3b61912..cdff041646 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -1,25 +1,25 @@ -/** +/** * @file lltextbox.h * @brief A single text item display * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,57 +31,57 @@ #include "lltextbase.h" class LLTextBox : - public LLTextBase + public LLTextBase { public: - - // *TODO: Add callback to Params - typedef boost::function<void (void)> callback_t; - - struct Params : public LLInitParam::Block<Params, LLTextBase::Params> - {}; + + // *TODO: Add callback to Params + typedef boost::function<void (void)> callback_t; + + struct Params : public LLInitParam::Block<Params, LLTextBase::Params> + {}; protected: - LLTextBox(const Params&); - friend class LLUICtrlFactory; + LLTextBox(const Params&); + friend class LLUICtrlFactory; public: - virtual ~LLTextBox(); + virtual ~LLTextBox(); + + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void setEnabled(BOOL enabled); - /*virtual*/ void setEnabled(BOOL enabled); + /*virtual*/ void setText( const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params() ); - /*virtual*/ void setText( const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params() ); - - void setRightAlign() { mHAlign = LLFontGL::RIGHT; } - void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } - void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ); + void setRightAlign() { mHAlign = LLFontGL::RIGHT; } + void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } + void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ); - void reshapeToFitText(BOOL called_from_parent = FALSE); + void reshapeToFitText(BOOL called_from_parent = FALSE); - S32 getTextPixelWidth(); - S32 getTextPixelHeight(); + S32 getTextPixelWidth(); + S32 getTextPixelHeight(); - /*virtual*/ LLSD getValue() const; - /*virtual*/ BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); + /*virtual*/ LLSD getValue() const; + /*virtual*/ BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); - void setShowCursorHand(bool show_cursor) { mShowCursorHand = show_cursor; } + void setShowCursorHand(bool show_cursor) { mShowCursorHand = show_cursor; } protected: - void onUrlLabelUpdated(const std::string &url, const std::string &label); + void onUrlLabelUpdated(const std::string &url, const std::string &label); - LLUIString mText; - callback_t mClickedCallback; - bool mShowCursorHand; + LLUIString mText; + callback_t mClickedCallback; + bool mShowCursorHand; }; // Build time optimization, generate once in .cpp file #ifndef LLTEXTBOX_CPP extern template class LLTextBox* LLView::getChild<class LLTextBox>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7150052b65..e030861f20 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltexteditor.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR #include "llfontgl.h" -#include "llgl.h" // LLGLSUIDefault() +#include "llgl.h" // LLGLSUIDefault() #include "lllocalcliprect.h" #include "llrender.h" #include "llui.h" @@ -64,105 +64,105 @@ #include <queue> #include "llcombobox.h" -// +// // Globals // static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor"); // Compiler optimization, generate extern template template class LLTextEditor* LLView::getChild<class LLTextEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; // // Constants // -const S32 SPACES_PER_TAB = 4; -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on +const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd { public: - TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(ws) - { - } - virtual ~TextCmdInsert() {} - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString ); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(ws) + { + } + virtual ~TextCmdInsert() {} + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString ); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; + LLWString mWString; }; /////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd { public: - TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) - : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual BOOL canExtend(S32 pos) const - { - // cannot extend text with custom segments - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - //mWString = wstring_truncate(mWString, *delta); - return (*delta != 0); - } - virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) - { - LLWString ws; - ws += wc; - - *delta = insert(editor, pos, ws); - if( *delta > 0 ) - { - mWString += wc; - } - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - remove(editor, getPosition(), mWString.length() ); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString ); - return getPosition() + mWString.length(); - } + TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) + : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) + { + } + virtual void blockExtensions() + { + mBlockExtensions = TRUE; + } + virtual BOOL canExtend(S32 pos) const + { + // cannot extend text with custom segments + if (!mSegments.empty()) return FALSE; + + return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + *delta = insert(editor, getPosition(), mWString); + LLWStringUtil::truncate(mWString, *delta); + //mWString = wstring_truncate(mWString, *delta); + return (*delta != 0); + } + virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) + { + LLWString ws; + ws += wc; + + *delta = insert(editor, pos, ws); + if( *delta > 0 ) + { + mWString += wc; + } + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + remove(editor, getPosition(), mWString.length() ); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString ); + return getPosition() + mWString.length(); + } private: - LLWString mWString; - BOOL mBlockExtensions; + LLWString mWString; + BOOL mBlockExtensions; }; @@ -171,30 +171,30 @@ private: class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { public: - TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) - : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mOldChar = editor->getWText()[getPosition()]; - overwrite(editor, getPosition(), mChar); - *delta = 0; - return TRUE; - } - virtual S32 undo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mOldChar); - return getPosition(); - } - virtual S32 redo( LLTextBase* editor ) - { - overwrite(editor, getPosition(), mChar); - return getPosition()+1; - } + TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) + : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mOldChar = editor->getWText()[getPosition()]; + overwrite(editor, getPosition(), mChar); + *delta = 0; + return TRUE; + } + virtual S32 undo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mOldChar); + return getPosition(); + } + virtual S32 redo( LLTextBase* editor ) + { + overwrite(editor, getPosition(), mChar); + return getPosition()+1; + } private: - llwchar mChar; - llwchar mOldChar; + llwchar mChar; + llwchar mOldChar; }; /////////////////////////////////////////////////////////////////// @@ -202,114 +202,116 @@ private: class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd { public: - TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : - TextCmd(pos, group_with_next), mLen(len) - { - std::swap(mSegments, segments); - } - virtual BOOL execute( LLTextBase* editor, S32* delta ) - { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); - return (*delta != 0); - } - virtual S32 undo( LLTextBase* editor ) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - virtual S32 redo( LLTextBase* editor ) - { - remove(editor, getPosition(), mLen ); - return getPosition(); - } + TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : + TextCmd(pos, group_with_next), mLen(len) + { + std::swap(mSegments, segments); + } + virtual BOOL execute( LLTextBase* editor, S32* delta ) + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen ); + return (*delta != 0); + } + virtual S32 undo( LLTextBase* editor ) + { + insert(editor, getPosition(), mWString); + return getPosition() + mWString.length(); + } + virtual S32 redo( LLTextBase* editor ) + { + remove(editor, getPosition(), mLen ); + return getPosition(); + } private: - LLWString mWString; - S32 mLen; + LLWString mWString; + S32 mLen; }; /////////////////////////////////////////////////////////////////// LLTextEditor::Params::Params() -: default_text("default_text"), - prevalidate_callback("prevalidate_callback"), - embedded_items("embedded_items", false), - ignore_tab("ignore_tab", true), - auto_indent("auto_indent", true), - default_color("default_color"), +: default_text("default_text"), + prevalidator("prevalidator"), + embedded_items("embedded_items", false), + ignore_tab("ignore_tab", true), + auto_indent("auto_indent", true), + default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), - show_context_menu("show_context_menu"), - show_emoji_helper("show_emoji_helper"), - enable_tooltip_paste("enable_tooltip_paste") + show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), + enable_tooltip_paste("enable_tooltip_paste") { - addSynonym(prevalidate_callback, "text_type"); + addSynonym(prevalidator, "prevalidate_callback"); + addSynonym(prevalidator, "text_type"); } LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : - LLTextBase(p), - mAutoreplaceCallback(), - mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mDefaultColor( p.default_color() ), - mAutoIndent(p.auto_indent), - mCommitOnFocusLost( p.commit_on_focus_lost), - mAllowEmbeddedItems( p.embedded_items ), - mMouseDownX(0), - mMouseDownY(0), - mTabsToNextField(p.ignore_tab), - mPrevalidateFunc(p.prevalidate_callback()), - mShowContextMenu(p.show_context_menu), - mShowEmojiHelper(p.show_emoji_helper), - mEnableTooltipPaste(p.enable_tooltip_paste), - mPassDelete(FALSE), - mKeepSelectionOnReturn(false) -{ - mSourceID.generate(); - - //FIXME: use image? - LLViewBorder::Params params; - params.name = "text ed border"; - params.rect = getLocalRect(); - params.bevel_style = LLViewBorder::BEVEL_IN; - params.border_thickness = 1; - params.visible = p.border_visible; - mBorder = LLUICtrlFactory::create<LLViewBorder> (params); - addChild( mBorder ); - setText(p.default_text()); - - mParseOnTheFly = TRUE; + LLTextBase(p), + mAutoreplaceCallback(), + mBaseDocIsPristine(TRUE), + mPristineCmd( NULL ), + mLastCmd( NULL ), + mDefaultColor( p.default_color() ), + mAutoIndent(p.auto_indent), + mParseOnTheFly(false), + mCommitOnFocusLost( p.commit_on_focus_lost), + mAllowEmbeddedItems( p.embedded_items ), + mMouseDownX(0), + mMouseDownY(0), + mTabsToNextField(p.ignore_tab), + mPrevalidator(p.prevalidator()), + mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), + mEnableTooltipPaste(p.enable_tooltip_paste), + mPassDelete(false), + mKeepSelectionOnReturn(false) +{ + mSourceID.generate(); + + //FIXME: use image? + LLViewBorder::Params params; + params.name = "text ed border"; + params.rect = getLocalRect(); + params.bevel_style = LLViewBorder::BEVEL_IN; + params.border_thickness = 1; + params.visible = p.border_visible; + mBorder = LLUICtrlFactory::create<LLViewBorder> (params); + addChild( mBorder ); + setText(p.default_text()); + + mParseOnTheFly = true; } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) { - LLTextBase::initFromParams(p); + LLTextBase::initFromParams(p); - // HACK: text editors always need to be enabled so that we can scroll - LLView::setEnabled(true); + // HACK: text editors always need to be enabled so that we can scroll + LLView::setEnabled(true); - if (p.commit_on_focus_lost.isProvided()) - { - mCommitOnFocusLost = p.commit_on_focus_lost; - } - - updateAllowingLanguageInput(); + if (p.commit_on_focus_lost.isProvided()) + { + mCommitOnFocusLost = p.commit_on_focus_lost; + } + + updateAllowingLanguageInput(); } LLTextEditor::~LLTextEditor() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid - // Scrollbar is deleted by LLView - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); - // Mark the menu as dead or its retained in memory till shutdown. - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if(menu) - { - menu->die(); - mContextMenuHandle.markDead(); - } + // Scrollbar is deleted by LLView + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); + // Mark the menu as dead or its retained in memory till shutdown. + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if(menu) + { + menu->die(); + mContextMenuHandle.markDead(); + } } //////////////////////////////////////////////////////////// @@ -318,649 +320,651 @@ 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; - } - } + // validate incoming text if necessary + if (mPrevalidator) + { + if (!mPrevalidator.validate(utf8str)) + { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + + // not valid text, nothing to do + return; + } + } + + blockUndo(); + deselect(); - blockUndo(); - deselect(); - - mParseOnTheFly = FALSE; - LLTextBase::setText(utf8str, input_params); - mParseOnTheFly = TRUE; + mParseOnTheFly = false; + LLTextBase::setText(utf8str, input_params); + mParseOnTheFly = true; - resetDirty(); + resetDirty(); } void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap) { - if (search_text_in.empty()) - { - return; - } - - LLWString text = getWText(); - LLWString search_text = utf8str_to_wstring(search_text_in); - if (case_insensitive) - { - LLWStringUtil::toLower(text); - LLWStringUtil::toLower(search_text); - } - - if (mIsSelecting) - { - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - - if (selected_text == search_text) - { - // We already have this word selected, we are searching for the next. - setCursorPos(mCursorPos + search_text.size()); - } - } - - S32 loc = text.find(search_text,mCursorPos); - - // If Maybe we wrapped, search again - if (wrap && (-1 == loc)) - { - loc = text.find(search_text); - } - - // If still -1, then search_text just isn't found. + if (search_text_in.empty()) + { + return; + } + + LLWString text = getWText(); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (case_insensitive) + { + LLWStringUtil::toLower(text); + LLWStringUtil::toLower(search_text); + } + + if (mIsSelecting) + { + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + + if (selected_text == search_text) + { + // We already have this word selected, we are searching for the next. + setCursorPos(mCursorPos + search_text.size()); + } + } + + S32 loc = text.find(search_text,mCursorPos); + + // If Maybe we wrapped, search again + if (wrap && (-1 == loc)) + { + loc = text.find(search_text); + } + + // If still -1, then search_text just isn't found. if (-1 == loc) - { - mIsSelecting = FALSE; - mSelectionEnd = 0; - mSelectionStart = 0; - return; - } + { + mIsSelecting = FALSE; + mSelectionEnd = 0; + mSelectionStart = 0; + return; + } - setCursorPos(loc); - - mIsSelecting = TRUE; - mSelectionEnd = mCursorPos; - mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); + setCursorPos(loc); + + mIsSelecting = TRUE; + mSelectionEnd = mCursorPos; + mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, - BOOL case_insensitive, BOOL wrap) + BOOL case_insensitive, BOOL wrap) { - BOOL replaced = FALSE; + BOOL replaced = FALSE; - if (search_text_in.empty()) - { - return replaced; - } + if (search_text_in.empty()) + { + return replaced; + } - LLWString search_text = utf8str_to_wstring(search_text_in); - if (mIsSelecting) - { - LLWString text = getWText(); - LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + LLWString search_text = utf8str_to_wstring(search_text_in); + if (mIsSelecting) + { + LLWString text = getWText(); + LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); - if (case_insensitive) - { - LLWStringUtil::toLower(selected_text); - LLWStringUtil::toLower(search_text); - } + if (case_insensitive) + { + LLWStringUtil::toLower(selected_text); + LLWStringUtil::toLower(search_text); + } - if (selected_text == search_text) - { - insertText(replace_text); - replaced = TRUE; - } - } + if (selected_text == search_text) + { + insertText(replace_text); + replaced = TRUE; + } + } - selectNext(search_text_in, case_insensitive, wrap); - return replaced; + selectNext(search_text_in, case_insensitive, wrap); + return replaced; } void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive) { - startOfDoc(); - selectNext(search_text, case_insensitive, FALSE); + startOfDoc(); + selectNext(search_text, case_insensitive, FALSE); - BOOL replaced = TRUE; - while ( replaced ) - { - replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); - } + BOOL replaced = TRUE; + while ( replaced ) + { + replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); + } } S32 LLTextEditor::prevWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) - { - cursorPos--; - } - while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) - { - cursorPos--; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) + { + cursorPos--; + } + while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) + { + cursorPos--; + } + return cursorPos; } S32 LLTextEditor::nextWordPos(S32 cursorPos) const { - LLWString wtext(getWText()); - while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) - { - cursorPos++; - } - while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) - { - cursorPos++; - } - return cursorPos; + LLWString wtext(getWText()); + while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) + { + cursorPos++; + } + while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) + { + cursorPos++; + } + return cursorPos; } -const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { - static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; + static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; - index_segment->setStart(mCursorPos); - index_segment->setEnd(mCursorPos); + index_segment->setStart(mCursorPos); + index_segment->setEnd(mCursorPos); - // find segment index at character to left of cursor (or rightmost edge of selection) - segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); + // find segment index at character to left of cursor (or rightmost edge of selection) + segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); - if (it != mSegments.end()) - { - return *it; - } - else - { - return LLTextSegmentPtr(); - } + if (it != mSegments.end()) + { + return *it; + } + else + { + return LLTextSegmentPtr(); + } } void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const { - S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; - S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; + S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; - return getSegmentsInRange(segments, left, right, true); + return getSegmentsInRange(segments, left, right, true); } void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const { - segment_set_t::const_iterator first_it = getSegIterContaining(start); - segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); - if (end_it != mSegments.end()) ++end_it; + segment_set_t::const_iterator first_it = getSegIterContaining(start); + segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); + if (end_it != mSegments.end()) ++end_it; - for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) - { - LLTextSegmentPtr segment = *it; - if (include_partial - || (segment->getStart() >= start - && segment->getEnd() <= end)) - { - segments_out.push_back(segment); - } - } + for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) + { + LLTextSegmentPtr segment = *it; + if (include_partial + || (segment->getStart() >= start + && segment->getEnd() <= end)) + { + segments_out.push_back(segment); + } + } } void LLTextEditor::setShowEmojiHelper(bool show) { - if (!mShowEmojiHelper) - { - LLEmojiHelper::instance().hideHelper(this); - } + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } - mShowEmojiHelper = show; + mShowEmojiHelper = show; } BOOL LLTextEditor::selectionContainsLineBreaks() { - if (hasSelection()) - { - S32 left = llmin(mSelectionStart, mSelectionEnd); - S32 right = left + llabs(mSelectionStart - mSelectionEnd); + if (hasSelection()) + { + S32 left = llmin(mSelectionStart, mSelectionEnd); + S32 right = left + llabs(mSelectionStart - mSelectionEnd); - LLWString wtext = getWText(); - for( S32 i = left; i < right; i++ ) - { - if (wtext[i] == '\n') - { - return TRUE; - } - } - } - return FALSE; + LLWString wtext = getWText(); + for( S32 i = left; i < right; i++ ) + { + if (wtext[i] == '\n') + { + return TRUE; + } + } + } + return FALSE; } S32 LLTextEditor::indentLine( S32 pos, S32 spaces ) { - // Assumes that pos is at the start of the line - // spaces may be positive (indent) or negative (unindent). - // Returns the actual number of characters added or removed. - - llassert(pos >= 0); - llassert(pos <= getLength() ); - - S32 delta_spaces = 0; - - if (spaces >= 0) - { - // Indent - for(S32 i=0; i < spaces; i++) - { - delta_spaces += addChar(pos, ' '); - } - } - else - { - // Unindent - for(S32 i=0; i < -spaces; i++) - { - LLWString wtext = getWText(); - if (wtext[pos] == ' ') - { - delta_spaces += remove( pos, 1, FALSE ); - } - } - } - - return delta_spaces; + // Assumes that pos is at the start of the line + // spaces may be positive (indent) or negative (unindent). + // Returns the actual number of characters added or removed. + + llassert(pos >= 0); + llassert(pos <= getLength() ); + + S32 delta_spaces = 0; + + if (spaces >= 0) + { + // Indent + for(S32 i=0; i < spaces; i++) + { + delta_spaces += addChar(pos, ' '); + } + } + else + { + // Unindent + for(S32 i=0; i < -spaces; i++) + { + LLWString wtext = getWText(); + if (wtext[pos] == ' ') + { + delta_spaces += remove( pos, 1, FALSE ); + } + } + } + + return delta_spaces; } void LLTextEditor::indentSelectedLines( S32 spaces ) { - if( hasSelection() ) - { - LLWString text = getWText(); - S32 left = llmin( mSelectionStart, mSelectionEnd ); - S32 right = left + llabs( mSelectionStart - mSelectionEnd ); - BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); - S32 cur = left; - - // Expand left to start of line - while( (cur > 0) && (text[cur] != '\n') ) - { - cur--; - } - left = cur; - if( cur > 0 ) - { - left++; - } - - // Expand right to end of line - if( text[right - 1] == '\n' ) - { - right--; - } - else - { - while( (text[right] != '\n') && (right <= getLength() ) ) - { - right++; - } - } - - // Disabling parsing on the fly to avoid updating text segments - // until all indentation commands are executed. - mParseOnTheFly = FALSE; - - // Find each start-of-line and indent it - do - { - if( text[cur] == '\n' ) - { - cur++; - } - - S32 delta_spaces = indentLine( cur, spaces ); - if( delta_spaces > 0 ) - { - cur += delta_spaces; - } - right += delta_spaces; - - text = getWText(); - - // Find the next new line - while( (cur < right) && (text[cur] != '\n') ) - { - cur++; - } - } - while( cur < right ); - - mParseOnTheFly = TRUE; - - if( (right < getLength()) && (text[right] == '\n') ) - { - right++; - } - - // Set the selection and cursor - if( cursor_on_right ) - { - mSelectionStart = left; - mSelectionEnd = right; - } - else - { - mSelectionStart = right; - mSelectionEnd = left; - } - setCursorPos(mSelectionEnd); - } + if( hasSelection() ) + { + LLWString text = getWText(); + S32 left = llmin( mSelectionStart, mSelectionEnd ); + S32 right = left + llabs( mSelectionStart - mSelectionEnd ); + BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); + S32 cur = left; + + // Expand left to start of line + while( (cur > 0) && (text[cur] != '\n') ) + { + cur--; + } + left = cur; + if( cur > 0 ) + { + left++; + } + + // Expand right to end of line + if( text[right - 1] == '\n' ) + { + right--; + } + else + { + while( (text[right] != '\n') && (right <= getLength() ) ) + { + right++; + } + } + + // Disabling parsing on the fly to avoid updating text segments + // until all indentation commands are executed. + mParseOnTheFly = false; + + // Find each start-of-line and indent it + do + { + if( text[cur] == '\n' ) + { + cur++; + } + + S32 delta_spaces = indentLine( cur, spaces ); + if( delta_spaces > 0 ) + { + cur += delta_spaces; + } + right += delta_spaces; + + text = getWText(); + + // Find the next new line + while( (cur < right) && (text[cur] != '\n') ) + { + cur++; + } + } + while( cur < right ); + + mParseOnTheFly = true; + + if( (right < getLength()) && (text[right] == '\n') ) + { + right++; + } + + // Set the selection and cursor + if( cursor_on_right ) + { + mSelectionStart = left; + mSelectionEnd = right; + } + else + { + mSelectionStart = right; + mSelectionEnd = left; + } + setCursorPos(mSelectionEnd); + } } //virtual BOOL LLTextEditor::canSelectAll() const { - return TRUE; + return TRUE; } // virtual void LLTextEditor::selectAll() { - mSelectionStart = getLength(); - mSelectionEnd = 0; - setCursorPos(mSelectionEnd); - updatePrimary(); + mSelectionStart = getLength(); + mSelectionEnd = 0; + setCursorPos(mSelectionEnd); + updatePrimary(); } void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos) { - setCursorPos(prev_cursor_pos); - startSelection(); - setCursorPos(next_cursor_pos); - endSelection(); + setCursorPos(prev_cursor_pos); + startSelection(); + setCursorPos(next_cursor_pos); + endSelection(); } void LLTextEditor::insertEmoji(llwchar emoji) { - LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); - insert(mCursorPos, LLWString(1, emoji), false, segment); - setCursorPos(mCursorPos + 1); + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmojiLarge(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); } void LLTextEditor::handleEmojiCommit(llwchar emoji) { - S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) - { - remove(shortCodePos, mCursorPos - shortCodePos, true); - setCursorPos(shortCodePos); + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - insertEmoji(emoji); - } + insertEmoji(emoji); + } } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // set focus first, in case click callbacks want to change it - // RN: do we really need to have a tab stop? - if (hasTabStop()) - { - setFocus( TRUE ); - } - - // Let scrollbar have first dibs - handled = LLTextBase::handleMouseDown(x, y, mask); - - if( !handled ) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; - if( start_select ) - { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, true ); - - if (hasSelection()) - { - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - } - else - { - setCursorAtLocalPos( x, y, true ); - startSelection(); - } - } - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if (handled && !gFocusMgr.getMouseCapture()) - { - gFocusMgr.setMouseCapture( this ); - } - return handled; + BOOL handled = FALSE; + + // set focus first, in case click callbacks want to change it + // RN: do we really need to have a tab stop? + if (hasTabStop()) + { + setFocus( TRUE ); + } + + // Let scrollbar have first dibs + handled = LLTextBase::handleMouseDown(x, y, mask); + + if( !handled ) + { + if (!(mask & MASK_SHIFT)) + { + deselect(); + } + + BOOL start_select = TRUE; + if( start_select ) + { + // If we're not scrolling (handled by child), then we're selecting + if (mask & MASK_SHIFT) + { + S32 old_cursor_pos = mCursorPos; + setCursorAtLocalPos( x, y, true ); + + if (hasSelection()) + { + mSelectionEnd = mCursorPos; + } + else + { + mSelectionStart = old_cursor_pos; + mSelectionEnd = mCursorPos; + } + // assume we're starting a drag select + mIsSelecting = TRUE; + } + else + { + setCursorAtLocalPos( x, y, true ); + startSelection(); + } + } + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if (handled && !gFocusMgr.getMouseCapture()) + { + gFocusMgr.setMouseCapture( this ); + } + return handled; } BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - bool show_menu = false; + bool show_menu = false; - // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection()) - { - S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); - if (click_pos > mSelectionStart && click_pos < mSelectionEnd) - { - show_menu = true; - } - } + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection()) + { + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) + { + show_menu = true; + } + } - // Let segments handle the click, if nothing does, show editor menu - if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) - { - show_menu = true; - } + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } - if (show_menu && getShowContextMenu()) - { - showContextMenu(x, y); - } + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } - return TRUE; + return TRUE; } BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop()) - { - setFocus(TRUE); - } + if (hasTabStop()) + { + setFocus(TRUE); + } - if (!LLTextBase::handleMouseDown(x, y, mask)) - { - if( canPastePrimary() ) - { - setCursorAtLocalPos( x, y, true ); - // does not rely on focus being set - pastePrimary(); - } - } - return TRUE; + if (!LLTextBase::handleMouseDown(x, y, mask)) + { + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, true ); + // does not rely on focus being set + pastePrimary(); + } + } + return TRUE; } BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - mSelectionEnd = mCursorPos; - } - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - if( !handled ) - { - // Pass to children - handled = LLTextBase::handleHover(x, y, mask); - } - - if( handled ) - { - // Delay cursor flashing - resetCursorBlink(); - } - - if( !handled ) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + if(hasMouseCapture() ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + mSelectionEnd = mCursorPos; + } + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + if( !handled ) + { + // Pass to children + handled = LLTextBase::handleHover(x, y, mask); + } + + if( handled ) + { + // Delay cursor flashing + resetCursorBlink(); + } + + if( !handled ) + { + getWindow()->setCursor(UI_CURSOR_IBEAM); + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // if I'm not currently selecting text - if (!(mIsSelecting && hasMouseCapture())) - { - // let text segments handle mouse event - handled = LLTextBase::handleMouseUp(x, y, mask); - } - - if( !handled ) - { - if( mIsSelecting ) - { - if(mScroller) - { - mScroller->autoScroll(x, y); - } - S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); - S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); - setCursorAtLocalPos( clamped_x, clamped_y, true ); - endSelection(); - } - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; - } - - // Delay cursor flashing - resetCursorBlink(); - - if( hasMouseCapture() ) - { - gFocusMgr.setMouseCapture( NULL ); - - handled = TRUE; - } - - return handled; + BOOL handled = FALSE; + + // if I'm not currently selecting text + if (!(mIsSelecting && hasMouseCapture())) + { + // let text segments handle mouse event + handled = LLTextBase::handleMouseUp(x, y, mask); + } + + if( !handled ) + { + if( mIsSelecting ) + { + if(mScroller) + { + mScroller->autoScroll(x, y); + } + S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); + S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); + setCursorAtLocalPos( clamped_x, clamped_y, true ); + endSelection(); + } + + // take selection to 'primary' clipboard + updatePrimary(); + + handled = TRUE; + } + + // Delay cursor flashing + resetCursorBlink(); + + if( hasMouseCapture() ) + { + gFocusMgr.setMouseCapture( NULL ); + + handled = TRUE; + } + + return handled; } BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // let scrollbar and text segments have first dibs - handled = LLTextBase::handleDoubleClick(x, y, mask); + // let scrollbar and text segments have first dibs + handled = LLTextBase::handleDoubleClick(x, y, mask); - if( !handled ) - { - setCursorAtLocalPos( x, y, false ); - deselect(); + if( !handled ) + { + setCursorAtLocalPos( x, y, false ); + deselect(); - LLWString text = getWText(); - - if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) - { - if (!setCursorPos(mCursorPos - 1)) break; - } - startSelection(); + LLWString text = getWText(); - while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) - { - if (!setCursorPos(mCursorPos + 1)) break; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - setCursorPos(mCursorPos + 1); - mSelectionEnd = mCursorPos; - } + if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + // Select word the cursor is over + while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) + { + if (!setCursorPos(mCursorPos - 1)) break; + } + startSelection(); + + while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) + { + if (!setCursorPos(mCursorPos + 1)) break; + } + + mSelectionEnd = mCursorPos; + } + else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) + { + // Select the character the cursor is over + startSelection(); + setCursorPos(mCursorPos + 1); + mSelectionEnd = mCursorPos; + } - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; + // We don't want handleMouseUp() to "finish" the selection (and thereby + // set mSelectionEnd to where the mouse is), so we finish the selection here. + mIsSelecting = FALSE; - // delay cursor flashing - resetCursorBlink(); + // delay cursor flashing + resetCursorBlink(); - // take selection to 'primary' clipboard - updatePrimary(); + // take selection to 'primary' clipboard + updatePrimary(); - handled = TRUE; - } + handled = TRUE; + } - return handled; + return handled; } @@ -969,228 +973,232 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { - if (!mReadOnly && mShowEmojiHelper) - { - // Any change to our contents should always hide the helper - LLEmojiHelper::instance().hideHelper(this); - } - - S32 delta = 0; - if( cmd->execute(this, &delta) ) - { - // Delete top of undo stack - undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - std::for_each(mUndoStack.begin(), enditer, DeletePointer()); - mUndoStack.erase(mUndoStack.begin(), enditer); - // 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 - { - // Operation failed, so don't put it on the undo stack. - delete cmd; - } - - return delta; + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + + S32 delta = 0; + if( cmd->execute(this, &delta) ) + { + // Delete top of undo stack + undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + std::for_each(mUndoStack.begin(), enditer, DeletePointer()); + mUndoStack.erase(mUndoStack.begin(), enditer); + // Push the new command is now on the top (front) of the undo stack. + mUndoStack.push_front(cmd); + mLastCmd = cmd; + + bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay()); + if (need_to_rollback) + { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + + // 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 + { + // Operation failed, so don't put it on the undo stack. + delete cmd; + } + + return delta; } S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment) { - return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); + return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); } S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) { - S32 end_pos = getEditableIndex(pos + length, true); - BOOL removedChar = FALSE; + S32 end_pos = getEditableIndex(pos + length, true); + BOOL removedChar = FALSE; + + segment_vec_t segments_to_remove; + // store text segments + getSegmentsInRange(segments_to_remove, pos, pos + length, false); - segment_vec_t segments_to_remove; - // store text segments - getSegmentsInRange(segments_to_remove, pos, pos + length, false); - - if (pos <= end_pos) - { - removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); - } + if (pos <= end_pos) + { + removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); + } - return removedChar; + return removedChar; } S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { - if ((S32)getLength() == pos) - { - return addChar(pos, wc); - } - else - { - return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); - } + if ((S32)getLength() == pos) + { + return addChar(pos, wc); + } + else + { + return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); + } } // Remove a single character from the text. Tries to remove // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if (!getEnabled()) - { - return; - } - - if (mCursorPos > 0) - { - S32 chars_to_remove = 1; - - LLWString text = getWText(); - if (text[mCursorPos - 1] == ' ') - { - // Try to remove a "tab" - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - if (offset > 0) - { - chars_to_remove = offset % SPACES_PER_TAB; - if (chars_to_remove == 0) - { - chars_to_remove = SPACES_PER_TAB; - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - if (text[mCursorPos - i - 1] != ' ') - { - // Fewer than a full tab's worth of spaces, so - // just delete a single character. - chars_to_remove = 1; - break; - } - } - } - } - - for (S32 i = 0; i < chars_to_remove; i++) - { - setCursorPos(mCursorPos - 1); - remove(mCursorPos, 1, false); - } - - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (!getEnabled()) + { + return; + } + + if (mCursorPos > 0) + { + S32 chars_to_remove = 1; + + LLWString text = getWText(); + if (text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, false); + } + + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Remove a single character from the text S32 LLTextEditor::removeChar(S32 pos) { - return remove(pos, 1, false); + return remove(pos, 1, false); } void LLTextEditor::removeChar() { - if (!getEnabled()) - { - return; - } + if (!getEnabled()) + { + return; + } - if (mCursorPos > 0) - { - setCursorPos(mCursorPos - 1); - removeChar(mCursorPos); - tryToShowEmojiHelper(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } + if (mCursorPos > 0) + { + setCursorPos(mCursorPos - 1); + removeChar(mCursorPos); + tryToShowEmojiHelper(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } } // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { - if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength) - { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - 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 - { - return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); - } + if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength) + { + LLUI::getInstance()->reportBadKeystroke(); + return 0; + } + + if (mLastCmd && mLastCmd->canExtend(pos)) + { + if (mPrevalidator) + { + // 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 (!mPrevalidator.validate(test_string)) + { + LLUI::getInstance()->reportBadKeystroke(); + mPrevalidator.showLastErrorUsingTimeout(); + return 0; + } + } + + S32 delta = 0; + mLastCmd->extendAndExecute(this, pos, wc, &delta); + + return delta; + } + + return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); } void LLTextEditor::addChar(llwchar wc) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } - - setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - tryToShowEmojiHelper(); - - if (!mReadOnly && mAutoreplaceCallback != NULL) - { - // autoreplace the text, if necessary - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) - { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } + if (!getEnabled()) + { + return; + } + + if (hasSelection()) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + tryToShowEmojiHelper(); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = mCursorPos; + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + + if (replacement_length > 0 || !replacement_string.empty()) + { + remove(replacement_start, replacement_length, true); + insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); + setCursorPos(new_cursor_pos); + } + } } void LLTextEditor::showEmojiHelper() @@ -1226,791 +1234,796 @@ void LLTextEditor::tryToShowEmojiHelper() void LLTextEditor::addLineBreakChar(BOOL group_together) { - if( !getEnabled() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(TRUE); - } - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - removeChar(mCursorPos); - } + if( !getEnabled() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(TRUE); + } + else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + removeChar(mCursorPos); + } + + LLStyleConstSP sp(new LLStyle(LLStyle::Params())); + LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); - LLStyleConstSP sp(new LLStyle(LLStyle::Params())); - LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); + S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); - - setCursorPos(mCursorPos + pos); + setCursorPos(mCursorPos + pos); } BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - if( mask & MASK_SHIFT ) - { - handled = TRUE; - - switch( key ) - { - case KEY_LEFT: - if( 0 < mCursorPos ) - { - startSelection(); - setCursorPos(mCursorPos - 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(prevWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - startSelection(); - setCursorPos(mCursorPos + 1); - if( mask & MASK_CONTROL ) - { - setCursorPos(nextWordPos(mCursorPos)); - } - mSelectionEnd = mCursorPos; - } - break; - - case KEY_UP: - startSelection(); - changeLine( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_UP: - startSelection(); - changePage( -1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_HOME: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(0); - } - else - { - startOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - case KEY_DOWN: - startSelection(); - changeLine( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_PAGE_DOWN: - startSelection(); - changePage( 1 ); - mSelectionEnd = mCursorPos; - break; - - case KEY_END: - startSelection(); - if( mask & MASK_CONTROL ) - { - setCursorPos(getLength()); - } - else - { - endOfLine(); - } - mSelectionEnd = mCursorPos; - break; - - default: - handled = FALSE; - break; - } - } - - if( handled ) - { - // take selection to 'primary' clipboard - updatePrimary(); - } - - return handled; + BOOL handled = FALSE; + + if( mask & MASK_SHIFT ) + { + handled = TRUE; + + switch( key ) + { + case KEY_LEFT: + if( 0 < mCursorPos ) + { + startSelection(); + setCursorPos(mCursorPos - 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(prevWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + startSelection(); + setCursorPos(mCursorPos + 1); + if( mask & MASK_CONTROL ) + { + setCursorPos(nextWordPos(mCursorPos)); + } + mSelectionEnd = mCursorPos; + } + break; + + case KEY_UP: + startSelection(); + changeLine( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_UP: + startSelection(); + changePage( -1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_HOME: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(0); + } + else + { + startOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + case KEY_DOWN: + startSelection(); + changeLine( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_PAGE_DOWN: + startSelection(); + changePage( 1 ); + mSelectionEnd = mCursorPos; + break; + + case KEY_END: + startSelection(); + if( mask & MASK_CONTROL ) + { + setCursorPos(getLength()); + } + else + { + endOfLine(); + } + mSelectionEnd = mCursorPos; + break; + + default: + handled = FALSE; + break; + } + } + + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + + return handled; } BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) { - BOOL handled = FALSE; - - // Ignore capslock key - if( MASK_NONE == mask ) - { - handled = TRUE; - switch( key ) - { - case KEY_UP: - changeLine( -1 ); - break; - - case KEY_PAGE_UP: - changePage( -1 ); - break; - - case KEY_HOME: - startOfLine(); - break; - - case KEY_DOWN: - changeLine( 1 ); - deselect(); - break; - - case KEY_PAGE_DOWN: - changePage( 1 ); - break; - - case KEY_END: - endOfLine(); - break; - - case KEY_LEFT: - if( hasSelection() ) - { - setCursorPos(llmin( mSelectionStart, mSelectionEnd )); - } - else - { - if( 0 < mCursorPos ) - { - setCursorPos(mCursorPos - 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - case KEY_RIGHT: - if( hasSelection() ) - { - setCursorPos(llmax( mSelectionStart, mSelectionEnd )); - } - else - { - if( mCursorPos < getLength() ) - { - setCursorPos(mCursorPos + 1); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled) - { - deselect(); - } - - return handled; + BOOL handled = FALSE; + + // Ignore capslock key + if( MASK_NONE == mask ) + { + handled = TRUE; + switch( key ) + { + case KEY_UP: + changeLine( -1 ); + break; + + case KEY_PAGE_UP: + changePage( -1 ); + break; + + case KEY_HOME: + startOfLine(); + break; + + case KEY_DOWN: + changeLine( 1 ); + deselect(); + break; + + case KEY_PAGE_DOWN: + changePage( 1 ); + break; + + case KEY_END: + endOfLine(); + break; + + case KEY_LEFT: + if( hasSelection() ) + { + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); + } + else + { + if( 0 < mCursorPos ) + { + setCursorPos(mCursorPos - 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + case KEY_RIGHT: + if( hasSelection() ) + { + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); + } + else + { + if( mCursorPos < getLength() ) + { + setCursorPos(mCursorPos + 1); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled) + { + deselect(); + } + + return handled; } void LLTextEditor::deleteSelection(BOOL group_with_next_op ) { - if( getEnabled() && hasSelection() ) - { - S32 pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - - remove( pos, length, group_with_next_op ); + if( getEnabled() && hasSelection() ) + { + S32 pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); - deselect(); - setCursorPos(pos); - } + remove( pos, length, group_with_next_op ); + + deselect(); + setCursorPos(pos); + } } // virtual BOOL LLTextEditor::canCut() const { - return !mReadOnly && hasSelection(); + return !mReadOnly && hasSelection(); } // cut selection to clipboard void LLTextEditor::cut() { - if( !canCut() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); - deleteSelection( FALSE ); + if( !canCut() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); + deleteSelection( FALSE ); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canCopy() const { - return hasSelection(); + return hasSelection(); } // copy selection to clipboard void LLTextEditor::copy() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); } BOOL LLTextEditor::canPaste() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(); + return !mReadOnly && LLClipboard::instance().isTextAvailable(); } // paste from clipboard void LLTextEditor::paste() { - bool is_primary = false; - pasteHelper(is_primary); + bool is_primary = false; + pasteHelper(is_primary); } // paste from primary void LLTextEditor::pastePrimary() { - bool is_primary = true; - pasteHelper(is_primary); + bool is_primary = true; + pasteHelper(is_primary); } // paste from primary (itsprimary==true) or clipboard (itsprimary==false) void LLTextEditor::pasteHelper(bool is_primary) { - mParseOnTheFly = FALSE; - bool can_paste_it; - if (is_primary) - { - can_paste_it = canPastePrimary(); - } - else - { - can_paste_it = canPaste(); - } + struct BoolReset + { + BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; } + ~BoolReset() { *mValuePtr = true; } + bool* mValuePtr; + } reset(mParseOnTheFly); - if (!can_paste_it) - { - return; - } + bool can_paste_it; + if (is_primary) + { + can_paste_it = canPastePrimary(); + } + else + { + can_paste_it = canPaste(); + } - LLWString paste; - LLClipboard::instance().pasteFromClipboard(paste, is_primary); + if (!can_paste_it) + { + return; + } - if (paste.empty()) - { - return; - } + LLWString paste; + LLClipboard::instance().pasteFromClipboard(paste, is_primary); - // Delete any selected characters (the paste replaces them) - if( (!is_primary) && hasSelection() ) - { - deleteSelection(TRUE); - } + if (paste.empty()) + { + return; + } + + // Delete any selected characters (the paste replaces them) + if( (!is_primary) && hasSelection() ) + { + deleteSelection(TRUE); + } - // Clean up string (replace tabs and remove characters that our fonts don't support). - LLWString clean_string(paste); - cleanStringForPaste(clean_string); + // Clean up string (replace tabs and remove characters that our fonts don't support). + LLWString clean_string(paste); + cleanStringForPaste(clean_string); - // Insert the new text into the existing text. + // Insert the new text into the existing text. - //paste text with linebreaks. - pasteTextWithLinebreaks(clean_string); + //paste text with linebreaks. + pasteTextWithLinebreaks(clean_string); - deselect(); + deselect(); - onKeyStroke(); - mParseOnTheFly = TRUE; + onKeyStroke(); } // Clean up string (replace tabs and remove characters that our fonts don't support). void LLTextEditor::cleanStringForPaste(LLWString & clean_string) { - std::string clean_string_utf = wstring_to_utf8str(clean_string); - std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); - clean_string = utf8str_to_wstring(clean_string_utf); - - LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); - if( mAllowEmbeddedItems ) - { - const llwchar LF = 10; - S32 len = clean_string.length(); - for( S32 i = 0; i < len; i++ ) - { - llwchar wc = clean_string[i]; - if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) - { - clean_string[i] = LL_UNKNOWN_CHAR; - } - else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) - { - clean_string[i] = pasteEmbeddedItem(wc); - } - } - } + std::string clean_string_utf = wstring_to_utf8str(clean_string); + std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); + clean_string = utf8str_to_wstring(clean_string_utf); + + LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); + if( mAllowEmbeddedItems ) + { + const llwchar LF = 10; + S32 len = clean_string.length(); + for( S32 i = 0; i < len; i++ ) + { + llwchar wc = clean_string[i]; + if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) + { + clean_string[i] = LL_UNKNOWN_CHAR; + } + else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) + { + clean_string[i] = pasteEmbeddedItem(wc); + } + } + } } void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string) { - std::basic_string<llwchar>::size_type start = 0; - std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); - - while((pos != -1) && (pos != clean_string.length() -1)) - { - if(pos!=start) - { - std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); - } - addLineBreakChar(TRUE); // Add a line break and group with the next addition. - - start = pos+1; - pos = clean_string.find('\n',start); - } - - if (pos != start) - { - std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); - setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); - } - else - { - addLineBreakChar(FALSE); // Add a line break and end the grouping. - } + std::basic_string<llwchar>::size_type start = 0; + std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); + + while((pos != -1) && (pos != clean_string.length() -1)) + { + if(pos!=start) + { + std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); + } + addLineBreakChar(TRUE); // Add a line break and group with the next addition. + + start = pos+1; + pos = clean_string.find('\n',start); + } + + if (pos != start) + { + std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); + setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); + } + else + { + addLineBreakChar(FALSE); // Add a line break and end the grouping. + } } // copy selection to primary void LLTextEditor::copyPrimary() { - if( !canCopy() ) - { - return; - } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - S32 length = llabs( mSelectionStart - mSelectionEnd ); - LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); } BOOL LLTextEditor::canPastePrimary() const { - return !mReadOnly && LLClipboard::instance().isTextAvailable(true); + return !mReadOnly && LLClipboard::instance().isTextAvailable(true); } void LLTextEditor::updatePrimary() { - if (canCopy()) - { - copyPrimary(); - } -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - if( mask & MASK_CONTROL ) - { - handled = TRUE; - - switch( key ) - { - case KEY_HOME: - if( mask & MASK_SHIFT ) - { - startSelection(); - setCursorPos(0); - mSelectionEnd = mCursorPos; - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - startOfDoc(); - } - break; - - case KEY_END: - { - if( mask & MASK_SHIFT ) - { - startSelection(); - } - else - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - } - endOfDoc(); - if( mask & MASK_SHIFT ) - { - mSelectionEnd = mCursorPos; - } - break; - } - - case KEY_RIGHT: - if( mCursorPos < getLength() ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(nextWordPos(mCursorPos + 1)); - } - break; - - - case KEY_LEFT: - if( mCursorPos > 0 ) - { - // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down - // all move the cursor as if clicking, so should deselect. - deselect(); - - setCursorPos(prevWordPos(mCursorPos - 1)); - } - break; - - default: - handled = FALSE; - break; - } - } - - if (handled && !gFocusMgr.getMouseCapture()) - { - updatePrimary(); - } - - return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) - { - BOOL handled = TRUE; - - if (mReadOnly) return FALSE; - - switch( key ) - { - case KEY_INSERT: - if (mask == MASK_NONE) - { - gKeyboard->toggleInsertMode(); - } - break; - - case KEY_BACKSPACE: - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( 0 < mCursorPos ) - { - removeCharOrTab(); - } - else - { - LLUI::getInstance()->reportBadKeystroke(); - } - break; - - - case KEY_RETURN: - if (mask == MASK_NONE) - { - if( hasSelection() && !mKeepSelectionOnReturn ) - { - deleteSelection(FALSE); - } - if (mAutoIndent) - { - autoIndent(); - } - } - else - { - handled = FALSE; - break; - } - break; - - case KEY_TAB: - if (mask & MASK_CONTROL) - { - handled = FALSE; - break; - } - if( hasSelection() && selectionContainsLineBreaks() ) - { - indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); - } - else - { - if( hasSelection() ) - { - deleteSelection(FALSE); - } - - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) - { - addChar( ' ' ); - } - } - break; - - default: - handled = FALSE; - break; - } - - if (handled) - { - onKeyStroke(); - } - return handled; + if (canCopy()) + { + copyPrimary(); + } } - -void LLTextEditor::unindentLineBeforeCloseBrace() +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) { - if( mCursorPos >= 1 ) - { - LLWString text = getWText(); - if( ' ' == text[ mCursorPos - 1 ] ) - { - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); + BOOL handled = FALSE; + + if( mask & MASK_CONTROL ) + { + handled = TRUE; + + switch( key ) + { + case KEY_HOME: + if( mask & MASK_SHIFT ) + { + startSelection(); + setCursorPos(0); + mSelectionEnd = mCursorPos; + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + startOfDoc(); + } + break; + + case KEY_END: + { + if( mask & MASK_SHIFT ) + { + startSelection(); + } + else + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + } + endOfDoc(); + if( mask & MASK_SHIFT ) + { + mSelectionEnd = mCursorPos; + } + break; + } + + case KEY_RIGHT: + if( mCursorPos < getLength() ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(nextWordPos(mCursorPos + 1)); + } + break; + + + case KEY_LEFT: + if( mCursorPos > 0 ) + { + // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down + // all move the cursor as if clicking, so should deselect. + deselect(); + + setCursorPos(prevWordPos(mCursorPos - 1)); + } + break; + + default: + handled = FALSE; + break; + } + } + + if (handled && !gFocusMgr.getMouseCapture()) + { + updatePrimary(); + } + + return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) + { + BOOL handled = TRUE; + + if (mReadOnly) return FALSE; + + switch( key ) + { + case KEY_INSERT: + if (mask == MASK_NONE) + { + gKeyboard->toggleInsertMode(); + } + break; + + case KEY_BACKSPACE: + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( 0 < mCursorPos ) + { + removeCharOrTab(); + } + else + { + LLUI::getInstance()->reportBadKeystroke(); + } + break; + + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( hasSelection() && !mKeepSelectionOnReturn ) + { + deleteSelection(FALSE); + } + if (mAutoIndent) + { + autoIndent(); + } + } + else + { + handled = FALSE; + break; + } + break; + + case KEY_TAB: + if (mask & MASK_CONTROL) + { + handled = FALSE; + break; + } + if( hasSelection() && selectionContainsLineBreaks() ) + { + indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); + } + else + { + if( hasSelection() ) + { + deleteSelection(FALSE); + } + + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for( S32 i=0; i < spaces_needed; i++ ) + { + addChar( ' ' ); + } + } + break; - // Jump over spaces in the current line - while ((' ' == text[line_start]) && (line_start < mCursorPos)) - { - line_start++; - } + default: + handled = FALSE; + break; + } - // Make sure there is nothing but ' ' before the Brace we are unindenting - if (line_start == mCursorPos) - { - removeCharOrTab(); - } - } - } + if (handled) + { + onKeyStroke(); + } + return handled; +} + + +void LLTextEditor::unindentLineBeforeCloseBrace() +{ + if( mCursorPos >= 1 ) + { + LLWString text = getWText(); + if( ' ' == text[ mCursorPos - 1 ] ) + { + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + + // Jump over spaces in the current line + while ((' ' == text[line_start]) && (line_start < mCursorPos)) + { + line_start++; + } + + // Make sure there is nothing but ' ' before the Brace we are unindenting + if (line_start == mCursorPos) + { + removeCharOrTab(); + } + } + } } BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { - BOOL handled = FALSE; - - // Special case for TAB. If want to move to next field, report - // not handled and let the parent take care of field movement. - if (KEY_TAB == key && mTabsToNextField) - { - return FALSE; - } - - if (mReadOnly && mScroller) - { - handled = (mScroller && mScroller->handleKeyHere( key, mask )) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask); - } - else - { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) - { - return TRUE; - } - - if (mEnableTooltipPaste && - LLToolTipMgr::instance().toolTipVisible() && + BOOL handled = FALSE; + + // Special case for TAB. If want to move to next field, report + // not handled and let the parent take care of field movement. + if (KEY_TAB == key && mTabsToNextField) + { + return FALSE; + } + + if (mReadOnly && mScroller) + { + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); + } + else + { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + + if (mEnableTooltipPaste && + LLToolTipMgr::instance().toolTipVisible() && LLToolTipMgr::instance().isTooltipPastable() && - KEY_TAB == key) - { // Paste the first line of a tooltip into the editor - std::string message; - LLToolTipMgr::instance().getToolTipMessage(message); - LLWString tool_tip_text(utf8str_to_wstring(message)); - - if (tool_tip_text.size() > 0) - { - // Delete any selected characters (the tooltip text replaces them) - if(hasSelection()) - { - deleteSelection(TRUE); - } - - std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); - if (pos != -1) - { // Extract the first line of the tooltip - tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); - } - - // Add the text - cleanStringForPaste(tool_tip_text); - pasteTextWithLinebreaks(tool_tip_text); - handled = TRUE; - } - } - else - { // Normal key handling - handled = handleNavigationKey( key, mask ) - || handleSelectionKey(key, mask) - || handleControlKey(key, mask) - || handleSpecialKey(key, mask); - } - } - - if( handled ) - { - resetCursorBlink(); - needsScroll(); - - if (mShowEmojiHelper) - { - // Dismiss the helper whenever we handled a key that it didn't - LLEmojiHelper::instance().hideHelper(this); - } - } - - return handled; + KEY_TAB == key) + { // Paste the first line of a tooltip into the editor + std::string message; + LLToolTipMgr::instance().getToolTipMessage(message); + LLWString tool_tip_text(utf8str_to_wstring(message)); + + if (tool_tip_text.size() > 0) + { + // Delete any selected characters (the tooltip text replaces them) + if(hasSelection()) + { + deleteSelection(TRUE); + } + + std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); + if (pos != -1) + { // Extract the first line of the tooltip + tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); + } + + // Add the text + cleanStringForPaste(tool_tip_text); + pasteTextWithLinebreaks(tool_tip_text); + handled = TRUE; + } + } + else + { // Normal key handling + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); + } + } + + if( handled ) + { + resetCursorBlink(); + needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } + } + + return handled; } BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) { - if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL - { - return FALSE; - } + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } - BOOL handled = FALSE; + BOOL handled = FALSE; - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { + // Handle most keys only if the text editor is writeable. + if( !mReadOnly ) + { if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) { return TRUE; } if( mAutoIndent && '}' == uni_char ) - { - unindentLineBeforeCloseBrace(); - } + { + unindentLineBeforeCloseBrace(); + } - // TODO: KLW Add auto show of tool tip on ( - addChar( uni_char ); + // TODO: KLW Add auto show of tool tip on ( + addChar( uni_char ); - // Keys that add characters temporarily hide the cursor - getWindow()->hideCursorUntilMouseMove(); + // Keys that add characters temporarily hide the cursor + getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } + handled = TRUE; + } - if( handled ) - { - resetCursorBlink(); + if( handled ) + { + resetCursorBlink(); - // Most keystrokes will make the selection box go away, but not all will. - deselect(); + // Most keystrokes will make the selection box go away, but not all will. + deselect(); - onKeyStroke(); - } + onKeyStroke(); + } - return handled; + return handled; } // virtual BOOL LLTextEditor::canDoDelete() const { - return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); + return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); } void LLTextEditor::doDelete() { - if( !canDoDelete() ) - { - return; - } - if( hasSelection() ) - { - deleteSelection(FALSE); - } - else - if( mCursorPos < getLength() ) - { - S32 i; - S32 chars_to_remove = 1; - LLWString text = getWText(); - if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) - { - // Try to remove a full tab's worth of spaces - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - if( chars_to_remove == 0 ) - { - chars_to_remove = SPACES_PER_TAB; - } - - for( i = 0; i < chars_to_remove; i++ ) - { - if( text[mCursorPos + i] != ' ' ) - { - chars_to_remove = 1; - break; - } - } - } - - for( i = 0; i < chars_to_remove; i++ ) - { - setCursorPos(mCursorPos + 1); - removeChar(); - } - - } - - onKeyStroke(); + if( !canDoDelete() ) + { + return; + } + if( hasSelection() ) + { + deleteSelection(FALSE); + } + else + if( mCursorPos < getLength() ) + { + S32 i; + S32 chars_to_remove = 1; + LLWString text = getWText(); + if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) + { + // Try to remove a full tab's worth of spaces + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + if( chars_to_remove == 0 ) + { + chars_to_remove = SPACES_PER_TAB; + } + + for( i = 0; i < chars_to_remove; i++ ) + { + if( text[mCursorPos + i] != ' ' ) + { + chars_to_remove = 1; + break; + } + } + } + + for( i = 0; i < chars_to_remove; i++ ) + { + setCursorPos(mCursorPos + 1); + removeChar(); + } + + } + + onKeyStroke(); } //---------------------------------------------------------------------------- @@ -2018,624 +2031,624 @@ void LLTextEditor::doDelete() void LLTextEditor::blockUndo() { - mBaseDocIsPristine = FALSE; - mLastCmd = NULL; - std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - mUndoStack.clear(); + mBaseDocIsPristine = FALSE; + mLastCmd = NULL; + std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); + mUndoStack.clear(); } // virtual BOOL LLTextEditor::canUndo() const { - return !mReadOnly && mLastCmd != NULL; + return !mReadOnly && mLastCmd != NULL; } void LLTextEditor::undo() { - if( !canUndo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - pos = mLastCmd->undo(this); - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.end()) - ++iter; - if (iter != mUndoStack.end()) - mLastCmd = *iter; - else - mLastCmd = NULL; + if( !canUndo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + pos = mLastCmd->undo(this); + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.end()) + ++iter; + if (iter != mUndoStack.end()) + mLastCmd = *iter; + else + mLastCmd = NULL; - } while( mLastCmd && mLastCmd->groupWithNext() ); + } while( mLastCmd && mLastCmd->groupWithNext() ); - setCursorPos(pos); + setCursorPos(pos); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::canRedo() const { - return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); + return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); } void LLTextEditor::redo() { - if( !canRedo() ) - { - return; - } - deselect(); - S32 pos = 0; - do - { - if( !mLastCmd ) - { - mLastCmd = mUndoStack.back(); - } - else - { - undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); - if (iter != mUndoStack.begin()) - mLastCmd = *(--iter); - else - mLastCmd = NULL; - } - - if( mLastCmd ) - { - pos = mLastCmd->redo(this); - } - } while( - mLastCmd && - mLastCmd->groupWithNext() && - (mLastCmd != mUndoStack.front()) ); - - setCursorPos(pos); - - onKeyStroke(); + if( !canRedo() ) + { + return; + } + deselect(); + S32 pos = 0; + do + { + if( !mLastCmd ) + { + mLastCmd = mUndoStack.back(); + } + else + { + undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); + if (iter != mUndoStack.begin()) + mLastCmd = *(--iter); + else + mLastCmd = NULL; + } + + if( mLastCmd ) + { + pos = mLastCmd->redo(this); + } + } while( + mLastCmd && + mLastCmd->groupWithNext() && + (mLastCmd != mUndoStack.front()) ); + + setCursorPos(pos); + + onKeyStroke(); } void LLTextEditor::onFocusReceived() { - LLTextBase::onFocusReceived(); - updateAllowingLanguageInput(); + LLTextBase::onFocusReceived(); + updateAllowingLanguageInput(); } void LLTextEditor::focusLostHelper() { - updateAllowingLanguageInput(); + updateAllowingLanguageInput(); - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - if (mCommitOnFocusLost) - { - onCommit(); - } + if (mCommitOnFocusLost) + { + onCommit(); + } - // Make sure cursor is shown again - getWindow()->showCursorFromMouseMove(); + // Make sure cursor is shown again + getWindow()->showCursorFromMouseMove(); } void LLTextEditor::onFocusLost() { - focusLostHelper(); - LLTextBase::onFocusLost(); + focusLostHelper(); + LLTextBase::onFocusLost(); } void LLTextEditor::onCommit() { - setControlValue(getValue()); - LLTextBase::onCommit(); + setControlValue(getValue()); + LLTextBase::onCommit(); } void LLTextEditor::setEnabled(BOOL enabled) { - // just treat enabled as read-only flag - bool read_only = !enabled; - if (read_only != mReadOnly) - { - //mReadOnly = read_only; - LLTextBase::setReadOnly(read_only); - updateSegments(); - updateAllowingLanguageInput(); - } + // just treat enabled as read-only flag + bool read_only = !enabled; + if (read_only != mReadOnly) + { + //mReadOnly = read_only; + LLTextBase::setReadOnly(read_only); + updateSegments(); + updateAllowingLanguageInput(); + } } void LLTextEditor::showContextMenu(S32 x, S32 y) { - LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); - if (!menu) - { - llassert(LLMenuGL::sMenuContainer != NULL); - menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml", - LLMenuGL::sMenuContainer, - LLMenuHolderGL::child_registry_t::instance()); + LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); + if (!menu) + { + llassert(LLMenuGL::sMenuContainer != NULL); + menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml", + LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); if(!menu) { LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; return; } - mContextMenuHandle = menu->getHandle(); - } - - // Route menu to this class - // previously this was done in ::handleRightMoseDown: - //if(hasTabStop()) - // setFocus(TRUE) - why? weird... - // and then inside setFocus - // .... - // gEditMenuHandler = this; - // .... - // but this didn't work in all cases and just weird... - //why not here? - // (all this was done for EXT-4443) - - gEditMenuHandler = this; - - S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - - setCursorAtLocalPos(x, y, false); - if (hasSelection()) - { - if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) - { - deselect(); - } - else - { - setCursorPos(llmax(mSelectionStart, mSelectionEnd)); - } - } - - bool use_spellcheck = getSpellCheck(), is_misspelled = false; - if (use_spellcheck) - { - mSuggestionList.clear(); - - // If the cursor is on a misspelled word, retrieve suggestions for it - std::string misspelled_word = getMisspelledWord(mCursorPos); - if ((is_misspelled = !misspelled_word.empty()) == true) - { - LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); - } - } - - menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); - menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); - menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); - menu->show(screen_x, screen_y, this); + mContextMenuHandle = menu->getHandle(); + } + + // Route menu to this class + // previously this was done in ::handleRightMoseDown: + //if(hasTabStop()) + // setFocus(TRUE) - why? weird... + // and then inside setFocus + // .... + // gEditMenuHandler = this; + // .... + // but this didn't work in all cases and just weird... + //why not here? + // (all this was done for EXT-4443) + + gEditMenuHandler = this; + + S32 screen_x, screen_y; + localPointToScreen(x, y, &screen_x, &screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } void LLTextEditor::drawPreeditMarker() { - static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); - static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); - static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); - static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); - static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); - static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); - static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); - static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); + static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); + static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); + static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); + static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); + static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); + static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); + static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); + static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); - if (!hasPreeditString()) - { - return; - } + if (!hasPreeditString()) + { + return; + } const LLWString textString(getWText()); - const llwchar *text = textString.c_str(); - const S32 text_len = getLength(); - const S32 num_lines = getLineCount(); - - S32 cur_line = getFirstVisibleLine(); - if (cur_line >= num_lines) - { - return; - } - - const S32 line_height = mFont->getLineHeight(); - - S32 line_start = getLineStart(cur_line); - S32 line_y = mVisibleTextRect.mTop - line_height; - while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) - { - S32 next_start = -1; - S32 line_end = text_len; - - if ((cur_line + 1) < num_lines) - { - next_start = getLineStart(cur_line + 1); - line_end = next_start; - } - if ( text[line_end-1] == '\n' ) - { - --line_end; - } - - // Does this line contain preedits? - if (line_start >= mPreeditPositions.back()) - { - // We have passed the preedits. - break; - } - if (line_end > mPreeditPositions.front()) - { - for (U32 i = 0; i < mPreeditStandouts.size(); i++) - { - S32 left = mPreeditPositions[i]; - S32 right = mPreeditPositions[i + 1]; - if (right <= line_start || left >= line_end) - { - continue; - } - - line_info& line = mLineInfoList[cur_line]; - LLRect text_rect(line.mRect); - text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents - text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - - S32 preedit_left = text_rect.mLeft; - if (left > line_start) - { - preedit_left += mFont->getWidth(text, line_start, left - line_start); - } - S32 preedit_right = text_rect.mLeft; - if (right < line_end) - { - preedit_right += mFont->getWidth(text, line_start, right - line_start); - } - else - { - preedit_right += mFont->getWidth(text, line_start, line_end - line_start); - } - - if (mPreeditStandouts[i]) - { - gl_rect_2d(preedit_left + preedit_standout_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_standout_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, - (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); - } - else - { - gl_rect_2d(preedit_left + preedit_marker_gap, - text_rect.mBottom + mFont->getDescenderHeight() - 1, - preedit_right - preedit_marker_gap - 1, - text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, - (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); - } - } - } - - // move down one line - line_y -= line_height; - line_start = next_start; - cur_line++; - } + const llwchar *text = textString.c_str(); + const S32 text_len = getLength(); + const S32 num_lines = getLineCount(); + + S32 cur_line = getFirstVisibleLine(); + if (cur_line >= num_lines) + { + return; + } + + const S32 line_height = mFont->getLineHeight(); + + S32 line_start = getLineStart(cur_line); + S32 line_y = mVisibleTextRect.mTop - line_height; + while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // Does this line contain preedits? + if (line_start >= mPreeditPositions.back()) + { + // We have passed the preedits. + break; + } + if (line_end > mPreeditPositions.front()) + { + for (U32 i = 0; i < mPreeditStandouts.size(); i++) + { + S32 left = mPreeditPositions[i]; + S32 right = mPreeditPositions[i + 1]; + if (right <= line_start || left >= line_end) + { + continue; + } + + line_info& line = mLineInfoList[cur_line]; + LLRect text_rect(line.mRect); + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + + S32 preedit_left = text_rect.mLeft; + if (left > line_start) + { + preedit_left += mFont->getWidth(text, line_start, left - line_start); + } + S32 preedit_right = text_rect.mLeft; + if (right < line_end) + { + preedit_right += mFont->getWidth(text, line_start, right - line_start); + } + else + { + preedit_right += mFont->getWidth(text, line_start, line_end - line_start); + } + + if (mPreeditStandouts[i]) + { + gl_rect_2d(preedit_left + preedit_standout_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_standout_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, + (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); + } + else + { + gl_rect_2d(preedit_left + preedit_marker_gap, + text_rect.mBottom + mFont->getDescenderHeight() - 1, + preedit_right - preedit_marker_gap - 1, + text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, + (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); + } + } + } + + // move down one line + line_y -= line_height; + line_start = next_start; + cur_line++; + } } void LLTextEditor::draw() { - { - // pad clipping rectangle so that cursor can draw at full width - // when at left edge of mVisibleTextRect - LLRect clip_rect(mVisibleTextRect); - clip_rect.stretch(1); - LLLocalClipRect clip(clip_rect); - } + { + // pad clipping rectangle so that cursor can draw at full width + // when at left edge of mVisibleTextRect + LLRect clip_rect(mVisibleTextRect); + clip_rect.stretch(1); + LLLocalClipRect clip(clip_rect); + } - LLTextBase::draw(); + LLTextBase::draw(); drawPreeditMarker(); - //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret - // when in readonly mode - mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); + //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret + // when in readonly mode + mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); } // Start or stop the editor from accepting text-editing keystrokes // see also LLLineEditor void LLTextEditor::setFocus( BOOL new_state ) { - BOOL old_state = hasFocus(); + BOOL old_state = hasFocus(); - // Don't change anything if the focus state didn't change - if (new_state == old_state) return; + // Don't change anything if the focus state didn't change + if (new_state == old_state) return; - // Notify early if we are losing focus. - if (!new_state) - { - getWindow()->allowLanguageTextInput(this, FALSE); - } + // Notify early if we are losing focus. + if (!new_state) + { + getWindow()->allowLanguageTextInput(this, FALSE); + } - LLTextBase::setFocus( new_state ); + LLTextBase::setFocus( new_state ); - if( new_state ) - { - // Route menu to this class - gEditMenuHandler = this; + if( new_state ) + { + // Route menu to this class + gEditMenuHandler = this; - // Don't start the cursor flashing right away - resetCursorBlink(); - } - else - { - // Route menu back to the default - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } + // Don't start the cursor flashing right away + resetCursorBlink(); + } + else + { + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } - endSelection(); - } + endSelection(); + } } // public void LLTextEditor::setCursorAndScrollToEnd() { - deselect(); - endOfDoc(); + deselect(); + endOfDoc(); } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) -{ - *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); - *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ + *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); + *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); } void LLTextEditor::autoIndent() { - // Count the number of spaces in the current line - S32 line = getLineNumFromDocIndex(mCursorPos, false); - S32 line_start = getLineStart(line); - S32 space_count = 0; - S32 i; + // Count the number of spaces in the current line + S32 line = getLineNumFromDocIndex(mCursorPos, false); + S32 line_start = getLineStart(line); + S32 space_count = 0; + S32 i; - LLWString text = getWText(); - S32 offset = getLineOffsetFromDocIndex(mCursorPos); - while(( ' ' == text[line_start] ) && (space_count < offset)) - { - space_count++; - line_start++; - } + LLWString text = getWText(); + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + while(( ' ' == text[line_start] ) && (space_count < offset)) + { + space_count++; + line_start++; + } - // If we're starting a braced section, indent one level. - if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) - { - space_count += SPACES_PER_TAB; - } + // If we're starting a braced section, indent one level. + if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) + { + space_count += SPACES_PER_TAB; + } - // Insert that number of spaces on the new line + // Insert that number of spaces on the new line - //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); - addLineBreakChar(); + //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); + addLineBreakChar(); - for( i = 0; i < space_count; i++ ) - { - addChar( ' ' ); - } + for( i = 0; i < space_count; i++ ) + { + addChar( ' ' ); + } } // Inserts new text at the cursor position void LLTextEditor::insertText(const std::string &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } + + setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); - - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::insertText(LLWString &new_text) { - BOOL enabled = getEnabled(); - setEnabled( TRUE ); + BOOL enabled = getEnabled(); + setEnabled( TRUE ); - // Delete any selected characters (the insertion replaces them) - if( hasSelection() ) - { - deleteSelection(TRUE); - } + // Delete any selected characters (the insertion replaces them) + if( hasSelection() ) + { + deleteSelection(TRUE); + } - setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); + setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); - setEnabled( enabled ); + setEnabled( enabled ); } void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo) { - // Save old state - S32 selection_start = mSelectionStart; - S32 selection_end = mSelectionEnd; - BOOL was_selecting = mIsSelecting; - S32 cursor_pos = mCursorPos; - S32 old_length = getLength(); - BOOL cursor_was_at_end = (mCursorPos == old_length); + // Save old state + S32 selection_start = mSelectionStart; + S32 selection_end = mSelectionEnd; + BOOL was_selecting = mIsSelecting; + S32 cursor_pos = mCursorPos; + S32 old_length = getLength(); + BOOL cursor_was_at_end = (mCursorPos == old_length); - deselect(); + deselect(); - setCursorPos(old_length); + setCursorPos(old_length); - LLWString widget_wide_text = utf8str_to_wstring(text); + LLWString widget_wide_text = utf8str_to_wstring(text); - LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); - insert(getLength(), widget_wide_text, FALSE, segment); + LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); + insert(getLength(), widget_wide_text, FALSE, segment); - // Set the cursor and scroll position - if( selection_start != selection_end ) - { - mSelectionStart = selection_start; - mSelectionEnd = selection_end; + // Set the cursor and scroll position + if( selection_start != selection_end ) + { + mSelectionStart = selection_start; + mSelectionEnd = selection_end; - mIsSelecting = was_selecting; - setCursorPos(cursor_pos); - } - else if( cursor_was_at_end ) - { - setCursorPos(getLength()); - } - else - { - setCursorPos(cursor_pos); - } + mIsSelecting = was_selecting; + setCursorPos(cursor_pos); + } + else if( cursor_was_at_end ) + { + setCursorPos(getLength()); + } + else + { + setCursorPos(cursor_pos); + } - if (!allow_undo) - { - blockUndo(); - } + if (!allow_undo) + { + blockUndo(); + } } void LLTextEditor::removeTextFromEnd(S32 num_chars) { - if (num_chars <= 0) return; + if (num_chars <= 0) return; - remove(getLength() - num_chars, num_chars, FALSE); + remove(getLength() - num_chars, num_chars, FALSE); - S32 len = getLength(); - setCursorPos (llclamp(mCursorPos, 0, len)); - mSelectionStart = llclamp(mSelectionStart, 0, len); - mSelectionEnd = llclamp(mSelectionEnd, 0, len); + S32 len = getLength(); + setCursorPos (llclamp(mCursorPos, 0, len)); + mSelectionStart = llclamp(mSelectionStart, 0, len); + mSelectionEnd = llclamp(mSelectionEnd, 0, len); - needsScroll(); + needsScroll(); } //---------------------------------------------------------------------------- void LLTextEditor::onSpellCheckPerformed() { - if (isPristine()) - { - mBaseDocIsPristine = FALSE; - } + if (isPristine()) + { + mBaseDocIsPristine = FALSE; + } } void LLTextEditor::makePristine() { - mPristineCmd = mLastCmd; - mBaseDocIsPristine = !mLastCmd; + mPristineCmd = mLastCmd; + mBaseDocIsPristine = !mLastCmd; - // Create a clean partition in the undo stack. We don't want a single command to extend from - // the "pre-pristine" state to the "post-pristine" state. - if( mLastCmd ) - { - mLastCmd->blockExtensions(); - } + // Create a clean partition in the undo stack. We don't want a single command to extend from + // the "pre-pristine" state to the "post-pristine" state. + if( mLastCmd ) + { + mLastCmd->blockExtensions(); + } } BOOL LLTextEditor::isPristine() const { - if( mPristineCmd ) - { - return (mPristineCmd == mLastCmd); - } - else - { - // No undo stack, so check if the version before and commands were done was the original version - return !mLastCmd && mBaseDocIsPristine; - } + if( mPristineCmd ) + { + return (mPristineCmd == mLastCmd); + } + else + { + // No undo stack, so check if the version before and commands were done was the original version + return !mLastCmd && mBaseDocIsPristine; + } } BOOL LLTextEditor::tryToRevertToPristineState() { - if( !isPristine() ) - { - deselect(); - S32 i = 0; - while( !isPristine() && canUndo() ) - { - undo(); - i--; - } - - while( !isPristine() && canRedo() ) - { - redo(); - i++; - } - - if( !isPristine() ) - { - // failed, so go back to where we started - while( i > 0 ) - { - undo(); - i--; - } - } - } - - return isPristine(); // TRUE => success + if( !isPristine() ) + { + deselect(); + S32 i = 0; + while( !isPristine() && canUndo() ) + { + undo(); + i--; + } + + while( !isPristine() && canRedo() ) + { + redo(); + i++; + } + + if( !isPristine() ) + { + // failed, so go back to where we started + while( i > 0 ) + { + undo(); + i--; + } + } + } + + return isPristine(); // TRUE => success } void LLTextEditor::updateLinkSegments() { - LLWString wtext = getWText(); - - // update any segments that contain a link - for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegment *segment = *it; - if (segment && segment->getStyle() && segment->getStyle()->isLink()) - { - LLStyleConstSP style = segment->getStyle(); - LLStyleSP new_style(new LLStyle(*style)); - LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - - segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); - LLTextSegment *next_segment = *next_it; - if (next_segment) - { - LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); - std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); - LLUrlMatch match; - - if ( LLUrlRegistry::instance().findUrl(link_check, match)) - { - if(match.getQuery() == wstring_to_utf8str(next_url_label)) - { - continue; - } - } - } - - // if the link's label (what the user can edit) is a valid Url, - // then update the link's HREF to be the same as the label text. - // This lets users edit Urls in-place. - if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) - { - std::string new_url = wstring_to_utf8str(url_label); - LLStringUtil::trim(new_url); - new_style->setLinkHREF(new_url); - LLStyleConstSP sp(new_style); - segment->setStyle(sp); - } - } - } + LLWString wtext = getWText(); + + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + LLStyleConstSP style = segment->getStyle(); + LLStyleSP new_style(new LLStyle(*style)); + LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + + segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); + LLTextSegment *next_segment = *next_it; + if (next_segment) + { + LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); + std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); + LLUrlMatch match; + + if ( LLUrlRegistry::instance().findUrl(link_check, match)) + { + if(match.getQuery() == wstring_to_utf8str(next_url_label)) + { + continue; + } + } + } + + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) + { + std::string new_url = wstring_to_utf8str(url_label); + LLStringUtil::trim(new_url); + new_style->setLinkHREF(new_url); + LLStyleConstSP sp(new_style); + segment->setStyle(sp); + } + } + } } void LLTextEditor::onMouseCaptureLost() { - endSelection(); + endSelection(); } /////////////////////////////////////////////////////////////////// @@ -2643,135 +2656,135 @@ void LLTextEditor::onMouseCaptureLost() BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) { - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // <EmbeddedItemList chunk> - // Text length <bytes without \0>\n - // <text without \0> (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; - return FALSE; - } - - if( 1 != version ) - { - LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { + std::istringstream instream(buffer); + + // Version 1 format: + // Linden text version 1\n + // {\n + // <EmbeddedItemList chunk> + // Text length <bytes without \0>\n + // <text without \0> (text may contain ext_char_values) + // }\n + + char tbuf[MAX_STRING]; /* Flawfinder: ignore */ + + S32 version = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) + { + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; + return FALSE; + } + + if( 1 != version ) + { + LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; + return FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( 0 != sscanf(tbuf, "{") ) + { + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; + return FALSE; + } + + S32 text_len = 0; + instream.getline(tbuf, MAX_STRING); + if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) + { + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; + return FALSE; + } + + if( text_len > mMaxTextByteLength ) + { + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; + return FALSE; + } + + BOOL success = TRUE; + + char* text = new char[ text_len + 1]; + if (text == NULL) + { LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Memory allocation failure." << LL_ENDL; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - startOfDoc(); - deselect(); - - return success; + LL_ERRS() << "Memory allocation failure." << LL_ENDL; + return FALSE; + } + instream.get(text, text_len + 1, '\0'); + text[text_len] = '\0'; + if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ + { + LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ + success = FALSE; + } + + instream.getline(tbuf, MAX_STRING); + if( success && (0 != sscanf(tbuf, "}")) ) + { + LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; + success = FALSE; + } + + if( success ) + { + // Actually set the text + setText( LLStringExplicit(text) ); + } + + delete[] text; + + startOfDoc(); + deselect(); + + return success; } BOOL LLTextEditor::exportBuffer(std::string &buffer ) { - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; + std::ostringstream outstream(buffer); + + outstream << "Linden text version 1\n"; + outstream << "{\n"; - outstream << llformat("Text length %d\n", getLength() ); - outstream << getText(); - outstream << "}\n"; + outstream << llformat("Text length %d\n", getLength() ); + outstream << getText(); + outstream << "}\n"; - return TRUE; + return TRUE; } void LLTextEditor::updateAllowingLanguageInput() { - LLWindow* window = getWindow(); - if (!window) - { - // test app, no window available - return; - } - if (hasFocus() && !mReadOnly) - { - window->allowLanguageTextInput(this, TRUE); - } - else - { - window->allowLanguageTextInput(this, FALSE); - } + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } + if (hasFocus() && !mReadOnly) + { + window->allowLanguageTextInput(this, TRUE); + } + else + { + window->allowLanguageTextInput(this, FALSE); + } } // Preedit is managed off the undo/redo command stack. BOOL LLTextEditor::hasPreeditString() const { - return (mPreeditPositions.size() > 1); + return (mPreeditPositions.size() > 1); } void LLTextEditor::resetPreedit() { if (hasSelection()) { - if (hasPreeditString()) + if (hasPreeditString()) { LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); @@ -2781,277 +2794,277 @@ void LLTextEditor::resetPreedit() deleteSelection(TRUE); } } - if (hasPreeditString()) - { - if (hasSelection()) - { - LL_WARNS() << "Preedit and selection!" << LL_ENDL; - deselect(); - } + if (hasPreeditString()) + { + if (hasSelection()) + { + LL_WARNS() << "Preedit and selection!" << LL_ENDL; + deselect(); + } - setCursorPos(mPreeditPositions.front()); - removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); - insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); + setCursorPos(mPreeditPositions.front()); + removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); + insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); - mPreeditWString.clear(); - mPreeditOverwrittenWString.clear(); - mPreeditPositions.clear(); + mPreeditWString.clear(); + mPreeditOverwrittenWString.clear(); + mPreeditPositions.clear(); - // A call to updatePreedit should soon follow under a - // normal course of operation, so we don't need to - // maintain internal variables such as line start - // positions now. - } + // A call to updatePreedit should soon follow under a + // normal course of operation, so we don't need to + // maintain internal variables such as line start + // positions now. + } } void LLTextEditor::updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) { - // Just in case. - if (mReadOnly) - { - return; - } + // Just in case. + if (mReadOnly) + { + return; + } - getWindow()->hideCursorUntilMouseMove(); + getWindow()->hideCursorUntilMouseMove(); - S32 insert_preedit_at = mCursorPos; + S32 insert_preedit_at = mCursorPos; + + mPreeditWString = preedit_string; + mPreeditPositions.resize(preedit_segment_lengths.size() + 1); + S32 position = insert_preedit_at; + for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) + { + mPreeditPositions[i] = position; + position += preedit_segment_lengths[i]; + } + mPreeditPositions.back() = position; - mPreeditWString = preedit_string; - mPreeditPositions.resize(preedit_segment_lengths.size() + 1); - S32 position = insert_preedit_at; - for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) - { - mPreeditPositions[i] = position; - position += preedit_segment_lengths[i]; - } - mPreeditPositions.back() = position; + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); + removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); + } + else + { + mPreeditOverwrittenWString.clear(); + } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); - removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); - } - else - { - mPreeditOverwrittenWString.clear(); - } - - segment_vec_t segments; - //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. - insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); + segment_vec_t segments; + //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. + insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); - mPreeditStandouts = preedit_standouts; + mPreeditStandouts = preedit_standouts; - setCursorPos(insert_preedit_at + caret_position); + setCursorPos(insert_preedit_at + caret_position); - // Update of the preedit should be caused by some key strokes. - resetCursorBlink(); + // Update of the preedit should be caused by some key strokes. + resetCursorBlink(); - onKeyStroke(); + onKeyStroke(); } BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const { - if (control) - { - LLRect control_rect_screen; - localRectToScreen(mVisibleTextRect, &control_rect_screen); - LLUI::getInstance()->screenRectToGL(control_rect_screen, control); - } - - S32 preedit_left_position, preedit_right_position; - if (hasPreeditString()) - { - preedit_left_position = mPreeditPositions.front(); - preedit_right_position = mPreeditPositions.back(); - } - else - { - preedit_left_position = preedit_right_position = mCursorPos; - } - - const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); - if (query < preedit_left_position || query > preedit_right_position) - { - return FALSE; - } - - const S32 first_visible_line = getFirstVisibleLine(); - if (query < getLineStart(first_visible_line)) - { - return FALSE; - } - - S32 current_line = first_visible_line; - S32 current_line_start, current_line_end; - for (;;) - { - current_line_start = getLineStart(current_line); - current_line_end = getLineStart(current_line + 1); - if (query >= current_line_start && query < current_line_end) - { - break; - } - if (current_line_start == current_line_end) - { - // We have reached on the last line. The query position must be here. - break; - } - current_line++; - } + if (control) + { + LLRect control_rect_screen; + localRectToScreen(mVisibleTextRect, &control_rect_screen); + LLUI::getInstance()->screenRectToGL(control_rect_screen, control); + } + + S32 preedit_left_position, preedit_right_position; + if (hasPreeditString()) + { + preedit_left_position = mPreeditPositions.front(); + preedit_right_position = mPreeditPositions.back(); + } + else + { + preedit_left_position = preedit_right_position = mCursorPos; + } + + const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); + if (query < preedit_left_position || query > preedit_right_position) + { + return FALSE; + } + + const S32 first_visible_line = getFirstVisibleLine(); + if (query < getLineStart(first_visible_line)) + { + return FALSE; + } + + S32 current_line = first_visible_line; + S32 current_line_start, current_line_end; + for (;;) + { + current_line_start = getLineStart(current_line); + current_line_end = getLineStart(current_line + 1); + if (query >= current_line_start && query < current_line_end) + { + break; + } + if (current_line_start == current_line_end) + { + // We have reached on the last line. The query position must be here. + break; + } + current_line++; + } const LLWString textString(getWText()); - const llwchar * const text = textString.c_str(); - const S32 line_height = mFont->getLineHeight(); - - if (coord) - { - const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); - const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; - S32 query_screen_x, query_screen_y; - localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); - LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); - } - - if (bounds) - { - S32 preedit_left = mVisibleTextRect.mLeft; - if (preedit_left_position > current_line_start) - { - preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); - } - - S32 preedit_right = mVisibleTextRect.mLeft; - if (preedit_right_position < current_line_end) - { - preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); - } - else - { - preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); - } - - const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; - const S32 preedit_bottom = preedit_top - line_height; - - const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); - LLRect preedit_rect_screen; - localRectToScreen(preedit_rect_local, &preedit_rect_screen); - LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); - } - - return TRUE; + const llwchar * const text = textString.c_str(); + const S32 line_height = mFont->getLineHeight(); + + if (coord) + { + const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); + const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; + S32 query_screen_x, query_screen_y; + localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); + LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); + } + + if (bounds) + { + S32 preedit_left = mVisibleTextRect.mLeft; + if (preedit_left_position > current_line_start) + { + preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); + } + + S32 preedit_right = mVisibleTextRect.mLeft; + if (preedit_right_position < current_line_end) + { + preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); + } + else + { + preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); + } + + const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; + const S32 preedit_bottom = preedit_top - line_height; + + const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); + LLRect preedit_rect_screen; + localRectToScreen(preedit_rect_local, &preedit_rect_screen); + LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); + } + + return TRUE; } void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const { - if (hasSelection()) - { - *position = llmin(mSelectionStart, mSelectionEnd); - *length = llabs(mSelectionStart - mSelectionEnd); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasSelection()) + { + *position = llmin(mSelectionStart, mSelectionEnd); + *length = llabs(mSelectionStart - mSelectionEnd); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const { - if (hasPreeditString()) - { - *position = mPreeditPositions.front(); - *length = mPreeditPositions.back() - mPreeditPositions.front(); - } - else - { - *position = mCursorPos; - *length = 0; - } + if (hasPreeditString()) + { + *position = mPreeditPositions.front(); + *length = mPreeditPositions.back() - mPreeditPositions.front(); + } + else + { + *position = mCursorPos; + *length = 0; + } } void LLTextEditor::markAsPreedit(S32 position, S32 length) { - deselect(); - setCursorPos(position); - if (hasPreeditString()) - { - LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; - } - mPreeditWString = LLWString( getWText(), position, length ); - if (length > 0) - { - mPreeditPositions.resize(2); - mPreeditPositions[0] = position; - mPreeditPositions[1] = position + length; - mPreeditStandouts.resize(1); - mPreeditStandouts[0] = FALSE; - } - else - { - mPreeditPositions.clear(); - mPreeditStandouts.clear(); - } - if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - { - mPreeditOverwrittenWString = mPreeditWString; - } - else - { - mPreeditOverwrittenWString.clear(); - } + deselect(); + setCursorPos(position); + if (hasPreeditString()) + { + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; + } + mPreeditWString = LLWString( getWText(), position, length ); + if (length > 0) + { + mPreeditPositions.resize(2); + mPreeditPositions[0] = position; + mPreeditPositions[1] = position + length; + mPreeditStandouts.resize(1); + mPreeditStandouts[0] = FALSE; + } + else + { + mPreeditPositions.clear(); + mPreeditStandouts.clear(); + } + if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) + { + mPreeditOverwrittenWString = mPreeditWString; + } + else + { + mPreeditOverwrittenWString.clear(); + } } S32 LLTextEditor::getPreeditFontSize() const { - return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } BOOL LLTextEditor::isDirty() const { - if(mReadOnly) - { - return FALSE; - } + if(mReadOnly) + { + return FALSE; + } - if( mPristineCmd ) - { - return ( mPristineCmd == mLastCmd ); - } - else - { - return ( NULL != mLastCmd ); - } + if( mPristineCmd ) + { + return ( mPristineCmd == mLastCmd ); + } + else + { + return ( NULL != mLastCmd ); + } } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) { - mKeystrokeSignal.connect(callback); + mKeystrokeSignal.connect(callback); } void LLTextEditor::onKeyStroke() { - mKeystrokeSignal(this); + mKeystrokeSignal(this); - mSpellCheckStart = mSpellCheckEnd = -1; - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual void LLTextEditor::clear() { - getViewModel()->setDisplay(LLWStringUtil::null); - clearSegments(); + getViewModel()->setDisplay(LLWStringUtil::null); + clearSegments(); } bool LLTextEditor::canLoadOrSaveToFile() { - return !mReadOnly; + return !mReadOnly; } S32 LLTextEditor::spacesPerTab() { - return SPACES_PER_TAB; + return SPACES_PER_TAB; } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 521405ec25..e917f65fbd 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -47,305 +47,305 @@ class LLUICtrlFactory; class LLScrollContainer; class LLTextEditor : - public LLTextBase, - protected LLPreeditor + public LLTextBase, + protected LLPreeditor { 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, - commit_on_focus_lost, - show_context_menu, - show_emoji_helper, - enable_tooltip_paste, - auto_indent; - - //colors - Optional<LLUIColor> default_color; - - Params(); - }; - - void initFromParams(const Params&); + struct Params : public LLInitParam::Block<Params, LLTextBase::Params> + { + Optional<std::string> default_text; + Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator; + + Optional<bool> embedded_items, + ignore_tab, + commit_on_focus_lost, + show_context_menu, + show_emoji_helper, + enable_tooltip_paste, + auto_indent; + + //colors + Optional<LLUIColor> default_color; + + Params(); + }; + + void initFromParams(const Params&); protected: - LLTextEditor(const Params&); - friend class LLUICtrlFactory; + LLTextEditor(const Params&); + friend class LLUICtrlFactory; public: - // - // Constants - // - static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; - static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; - static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; + // + // Constants + // + static const llwchar FIRST_EMBEDDED_CHAR = 0x100000; + static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff; + static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1; - virtual ~LLTextEditor(); + virtual ~LLTextEditor(); - typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t; + typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t; - void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); - void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} + void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} - static S32 spacesPerTab(); + static S32 spacesPerTab(); - void insertEmoji(llwchar emoji); - void handleEmojiCommit(llwchar emoji); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); - // mousehandler overrides - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - 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); + // mousehandler overrides + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + 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 handleKeyHere(KEY key, MASK mask ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleKeyHere(KEY key, MASK mask ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void onMouseCaptureLost(); + virtual void onMouseCaptureLost(); - // view overrides - virtual void draw(); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void onCommit(); - virtual void setEnabled(BOOL enabled); + // view overrides + virtual void draw(); + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onCommit(); + virtual void setEnabled(BOOL enabled); - // uictrl overrides - virtual void clear(); - virtual void setFocus( BOOL b ); - virtual BOOL isDirty() const; + // uictrl overrides + virtual void clear(); + virtual void setFocus( BOOL b ); + virtual BOOL isDirty() const; - // LLEditMenuHandler interface - virtual void undo(); - virtual BOOL canUndo() const; - virtual void redo(); - virtual BOOL canRedo() const; + // LLEditMenuHandler interface + virtual void undo(); + virtual BOOL canUndo() const; + virtual void redo(); + virtual BOOL canRedo() const; - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + virtual void cut(); + virtual BOOL canCut() const; + virtual void copy(); + virtual BOOL canCopy() const; + virtual void paste(); + virtual BOOL canPaste() const; - virtual void updatePrimary(); - virtual void copyPrimary(); - virtual void pastePrimary(); - virtual BOOL canPastePrimary() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + virtual void doDelete(); + virtual BOOL canDoDelete() const; + virtual void selectAll(); + virtual BOOL canSelectAll() const; - void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); - virtual bool canLoadOrSaveToFile(); + virtual bool canLoadOrSaveToFile(); - 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 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); - // Undo/redo stack - void blockUndo(); + // Undo/redo stack + void blockUndo(); - // Text editing - virtual void makePristine(); - BOOL isPristine() const; - BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } + // Text editing + virtual void makePristine(); + BOOL isPristine() const; + BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - // Autoreplace (formerly part of LLLineEditor) - typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; - autoreplace_callback_t mAutoreplaceCallback; - void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // Autoreplace (formerly part of LLLineEditor) + typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } - /*virtual*/ void onSpellCheckPerformed(); + /*virtual*/ void onSpellCheckPerformed(); - // - // Text manipulation - // + // + // Text manipulation + // - // inserts text at cursor - void insertText(const std::string &text); - void insertText(LLWString &text); + // inserts text at cursor + void insertText(const std::string &text); + void insertText(LLWString &text); - void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); - // Non-undoable - void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); + void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); + // Non-undoable + void setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params = LLStyle::Params()); - // Removes text from the end of document - // Does not change highlight or cursor position. - void removeTextFromEnd(S32 num_chars); + // Removes text from the end of document + // Does not change highlight or cursor position. + void removeTextFromEnd(S32 num_chars); - BOOL tryToRevertToPristineState(); + BOOL tryToRevertToPristineState(); - void setCursorAndScrollToEnd(); + void setCursorAndScrollToEnd(); - void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); + void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ); - // Hacky methods to make it into a word-wrapping, potentially scrolling, - // read-only text box. - void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } + // Hacky methods to make it into a word-wrapping, potentially scrolling, + // read-only text box. + void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } - // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + // Hack to handle Notecards + virtual BOOL importBuffer(const char* buffer, S32 length ); + virtual BOOL exportBuffer(std::string& buffer ); - const LLUUID& getSourceID() const { return mSourceID; } + const LLUUID& getSourceID() const { return mSourceID; } - const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; - void getSelectedSegments(segment_vec_t& segments) const; + const LLTextSegmentPtr getPreviousSegment() const; + const LLTextSegmentPtr getLastSegment() const; + void getSelectedSegments(segment_vec_t& segments) const; - void setShowContextMenu(bool show) { mShowContextMenu = show; } - bool getShowContextMenu() const { return mShowContextMenu; } + void setShowContextMenu(bool show) { mShowContextMenu = show; } + bool getShowContextMenu() const { return mShowContextMenu; } - void showEmojiHelper(); - void setShowEmojiHelper(bool show); - bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void showEmojiHelper(); + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } - void setPassDelete(BOOL b) { mPassDelete = b; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: - void showContextMenu(S32 x, S32 y); - void drawPreeditMarker(); - - void assignEmbedded(const std::string &s); - - void removeCharOrTab(); - - void indentSelectedLines( S32 spaces ); - S32 indentLine( S32 pos, S32 spaces ); - void unindentLineBeforeCloseBrace(); - - virtual BOOL handleSpecialKey(const KEY key, const MASK mask); - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSelectionKey(const KEY key, const MASK mask); - BOOL handleControlKey(const KEY key, const MASK mask); - - BOOL selectionContainsLineBreaks(); - void deleteSelection(BOOL transient_operation); - - S32 prevWordPos(S32 cursorPos) const; - S32 nextWordPos(S32 cursorPos) const; - - void autoIndent(); - - void findEmbeddedItemSegments(S32 start, S32 end); - void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; - - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - - - // Here's the method that takes and applies text commands. - S32 execute(TextCmd* cmd); - - // Undoable operations - void addChar(llwchar c); // at mCursorPos - S32 addChar(S32 pos, llwchar wc); - void addLineBreakChar(BOOL group_together = FALSE); - S32 overwriteChar(S32 pos, llwchar wc); - void removeChar(); - S32 removeChar(S32 pos); - S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); - S32 remove(S32 pos, S32 length, bool group_with_next_op); - - void tryToShowEmojiHelper(); - void focusLostHelper(); - void updateAllowingLanguageInput(); - BOOL hasPreeditString() const; - - // Overrides LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual void getSelectionRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } - // - // Protected data - // - // Probably deserves serious thought to hiding as many of these - // as possible behind protected accessor methods. - // - - // Use these to determine if a click on an embedded item is a drag or not. - S32 mMouseDownX; - S32 mMouseDownY; - - LLWString mPreeditWString; - LLWString mPreeditOverwrittenWString; - std::vector<S32> mPreeditPositions; - std::vector<BOOL> mPreeditStandouts; + void showContextMenu(S32 x, S32 y); + void drawPreeditMarker(); + + void assignEmbedded(const std::string &s); + + void removeCharOrTab(); + + void indentSelectedLines( S32 spaces ); + S32 indentLine( S32 pos, S32 spaces ); + void unindentLineBeforeCloseBrace(); + + virtual BOOL handleSpecialKey(const KEY key, const MASK mask); + BOOL handleNavigationKey(const KEY key, const MASK mask); + BOOL handleSelectionKey(const KEY key, const MASK mask); + BOOL handleControlKey(const KEY key, const MASK mask); + + BOOL selectionContainsLineBreaks(); + void deleteSelection(BOOL transient_operation); + + S32 prevWordPos(S32 cursorPos) const; + S32 nextWordPos(S32 cursorPos) const; + + void autoIndent(); + + void findEmbeddedItemSegments(S32 start, S32 end); + void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; + + virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } + + + // Here's the method that takes and applies text commands. + S32 execute(TextCmd* cmd); + + // Undoable operations + void addChar(llwchar c); // at mCursorPos + S32 addChar(S32 pos, llwchar wc); + void addLineBreakChar(BOOL group_together = FALSE); + S32 overwriteChar(S32 pos, llwchar wc); + void removeChar(); + S32 removeChar(S32 pos); + S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); + S32 remove(S32 pos, S32 length, bool group_with_next_op); + + void tryToShowEmojiHelper(); + void focusLostHelper(); + void updateAllowingLanguageInput(); + BOOL hasPreeditString() const; + + // Overrides LLPreeditor + virtual void resetPreedit(); + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); + virtual void markAsPreedit(S32 position, S32 length); + virtual void getPreeditRange(S32 *position, S32 *length) const; + virtual void getSelectionRange(S32 *position, S32 *length) const; + virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; + virtual S32 getPreeditFontSize() const; + virtual LLWString getPreeditString() const { return getWText(); } + // + // Protected data + // + // Probably deserves serious thought to hiding as many of these + // as possible behind protected accessor methods. + // + + // Use these to determine if a click on an embedded item is a drag or not. + S32 mMouseDownX; + S32 mMouseDownY; + + LLWString mPreeditWString; + LLWString mPreeditOverwrittenWString; + std::vector<S32> mPreeditPositions; + std::vector<BOOL> mPreeditStandouts; protected: - LLUIColor mDefaultColor; + LLUIColor mDefaultColor; - bool mAutoIndent; - bool mParseOnTheFly; + bool mAutoIndent; + bool mParseOnTheFly; - void updateLinkSegments(); - void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } - class LLViewBorder* mBorder; + void updateLinkSegments(); + void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } + class LLViewBorder* mBorder; private: - // - // Methods - // - void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); - void pasteTextWithLinebreaks(LLWString & clean_string); + // + // Methods + // + void pasteHelper(bool is_primary); + void cleanStringForPaste(LLWString & clean_string); + void pasteTextWithLinebreaks(LLWString & clean_string); - void onKeyStroke(); + void onKeyStroke(); - // Concrete TextCmd sub-classes used by the LLTextEditor base class - class TextCmdInsert; - class TextCmdAddChar; - class TextCmdOverwriteChar; - class TextCmdRemove; + // Concrete TextCmd sub-classes used by the LLTextEditor base class + class TextCmdInsert; + class TextCmdAddChar; + class TextCmdOverwriteChar; + class TextCmdRemove; - BOOL mBaseDocIsPristine; - TextCmd* mPristineCmd; + BOOL mBaseDocIsPristine; + TextCmd* mPristineCmd; - TextCmd* mLastCmd; + TextCmd* mLastCmd; - typedef std::deque<TextCmd*> undo_stack_t; - undo_stack_t mUndoStack; + typedef std::deque<TextCmd*> undo_stack_t; + undo_stack_t mUndoStack; - BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces - BOOL mCommitOnFocusLost; - BOOL mTakesFocus; + BOOL mTabsToNextField; // if true, tab moves focus to next field, else inserts spaces + BOOL mCommitOnFocusLost; + BOOL mTakesFocus; - BOOL mAllowEmbeddedItems; - bool mShowContextMenu; - bool mShowEmojiHelper; - bool mEnableTooltipPaste; - bool mPassDelete; - bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + BOOL mAllowEmbeddedItems; + bool mShowContextMenu; + bool mShowEmojiHelper; + bool mEnableTooltipPaste; + bool mPassDelete; + bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter - LLUUID mSourceID; + LLUUID mSourceID; - LLCoordGL mLastIMEPosition; // Last position of the IME editor + LLCoordGL mLastIMEPosition; // Last position of the IME editor - keystroke_signal_t mKeystrokeSignal; - LLTextValidate::validate_func_t mPrevalidateFunc; + keystroke_signal_t mKeystrokeSignal; + LLTextValidate::Validator mPrevalidator; - LLHandle<LLContextMenu> mContextMenuHandle; + LLHandle<LLContextMenu> mContextMenuHandle; }; // end class LLTextEditor // Build time optimization, generate once in .cpp file #ifndef LLTEXTEDITOR_CPP extern template class LLTextEditor* LLView::getChild<class LLTextEditor>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_TEXTEDITOR_H diff --git a/indra/llui/lltextparser.cpp b/indra/llui/lltextparser.cpp index 0b36241da0..7bb7c7f7bb 100644 --- a/indra/llui/lltextparser.cpp +++ b/indra/llui/lltextparser.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltextparser.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,198 +42,198 @@ // LLTextParser::LLTextParser() -: mLoaded(false) +: mLoaded(false) {} S32 LLTextParser::findPattern(const std::string &text, LLSD highlight) { - if (!highlight.has("pattern")) return -1; - - std::string pattern=std::string(highlight["pattern"]); - std::string ltext=text; - - if (!(bool)highlight["case_sensitive"]) - { - ltext = utf8str_tolower(text); - pattern= utf8str_tolower(pattern); - } - - size_t found=std::string::npos; - - switch ((S32)highlight["condition"]) - { - case CONTAINS: - found = ltext.find(pattern); - break; - case MATCHES: - found = (! ltext.compare(pattern) ? 0 : std::string::npos); - break; - case STARTS_WITH: - found = (! ltext.find(pattern) ? 0 : std::string::npos); - break; - case ENDS_WITH: - S32 pos = ltext.rfind(pattern); - if (pos >= 0 && (ltext.length()-pattern.length()==pos)) found = pos; - break; - } - return found; + if (!highlight.has("pattern")) return -1; + + std::string pattern=std::string(highlight["pattern"]); + std::string ltext=text; + + if (!(bool)highlight["case_sensitive"]) + { + ltext = utf8str_tolower(text); + pattern= utf8str_tolower(pattern); + } + + size_t found=std::string::npos; + + switch ((S32)highlight["condition"]) + { + case CONTAINS: + found = ltext.find(pattern); + break; + case MATCHES: + found = (! ltext.compare(pattern) ? 0 : std::string::npos); + break; + case STARTS_WITH: + found = (! ltext.find(pattern) ? 0 : std::string::npos); + break; + case ENDS_WITH: + S32 pos = ltext.rfind(pattern); + if (pos >= 0 && (ltext.length()-pattern.length()==pos)) found = pos; + break; + } + return found; } LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLColor4 &color, EHighlightPosition part, S32 index) { - loadKeywords(); - - //evil recursive string atomizer. - LLSD ret_llsd, start_llsd, middle_llsd, end_llsd; - - for (S32 i=index;i<mHighlights.size();i++) - { - S32 condition = mHighlights[i]["condition"]; - if ((S32)mHighlights[i]["highlight"]==PART && condition!=MATCHES) - { - if ( (condition==STARTS_WITH && part==START) || - (condition==ENDS_WITH && part==END) || - condition==CONTAINS || part==WHOLE ) - { - S32 start = findPattern(text,mHighlights[i]); - if (start >= 0 ) - { - S32 end = std::string(mHighlights[i]["pattern"]).length(); - S32 len = text.length(); - EHighlightPosition newpart; - if (start==0) - { - start_llsd[0]["text"] =text.substr(0,end); - start_llsd[0]["color"]=mHighlights[i]["color"]; - - if (end < len) - { - if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE; - end_llsd=parsePartialLineHighlights(text.substr( end ),color,newpart,i); - } - } - else - { - if (part==START || part==WHOLE) newpart=START; else newpart=MIDDLE; - - start_llsd=parsePartialLineHighlights(text.substr(0,start),color,newpart,i+1); - - if (end < len) - { - middle_llsd[0]["text"] =text.substr(start,end); - middle_llsd[0]["color"]=mHighlights[i]["color"]; - - if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE; - - end_llsd=parsePartialLineHighlights(text.substr( (start+end) ),color,newpart,i); - } - else - { - end_llsd[0]["text"] =text.substr(start,end); - end_llsd[0]["color"]=mHighlights[i]["color"]; - } - } - - S32 retcount=0; - - //FIXME These loops should be wrapped into a subroutine. - for (LLSD::array_iterator iter = start_llsd.beginArray(); - iter != start_llsd.endArray();++iter) - { - LLSD highlight = *iter; - ret_llsd[retcount++]=highlight; - } - - for (LLSD::array_iterator iter = middle_llsd.beginArray(); - iter != middle_llsd.endArray();++iter) - { - LLSD highlight = *iter; - ret_llsd[retcount++]=highlight; - } - - for (LLSD::array_iterator iter = end_llsd.beginArray(); - iter != end_llsd.endArray();++iter) - { - LLSD highlight = *iter; - ret_llsd[retcount++]=highlight; - } - - return ret_llsd; - } - } - } - } - - //No patterns found. Just send back what was passed in. - ret_llsd[0]["text"] =text; - LLSD color_sd = color.getValue(); - ret_llsd[0]["color"]=color_sd; - return ret_llsd; + loadKeywords(); + + //evil recursive string atomizer. + LLSD ret_llsd, start_llsd, middle_llsd, end_llsd; + + for (S32 i=index;i<mHighlights.size();i++) + { + S32 condition = mHighlights[i]["condition"]; + if ((S32)mHighlights[i]["highlight"]==PART && condition!=MATCHES) + { + if ( (condition==STARTS_WITH && part==START) || + (condition==ENDS_WITH && part==END) || + condition==CONTAINS || part==WHOLE ) + { + S32 start = findPattern(text,mHighlights[i]); + if (start >= 0 ) + { + S32 end = std::string(mHighlights[i]["pattern"]).length(); + S32 len = text.length(); + EHighlightPosition newpart; + if (start==0) + { + start_llsd[0]["text"] =text.substr(0,end); + start_llsd[0]["color"]=mHighlights[i]["color"]; + + if (end < len) + { + if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE; + end_llsd=parsePartialLineHighlights(text.substr( end ),color,newpart,i); + } + } + else + { + if (part==START || part==WHOLE) newpart=START; else newpart=MIDDLE; + + start_llsd=parsePartialLineHighlights(text.substr(0,start),color,newpart,i+1); + + if (end < len) + { + middle_llsd[0]["text"] =text.substr(start,end); + middle_llsd[0]["color"]=mHighlights[i]["color"]; + + if (part==END || part==WHOLE) newpart=END; else newpart=MIDDLE; + + end_llsd=parsePartialLineHighlights(text.substr( (start+end) ),color,newpart,i); + } + else + { + end_llsd[0]["text"] =text.substr(start,end); + end_llsd[0]["color"]=mHighlights[i]["color"]; + } + } + + S32 retcount=0; + + //FIXME These loops should be wrapped into a subroutine. + for (LLSD::array_iterator iter = start_llsd.beginArray(); + iter != start_llsd.endArray();++iter) + { + LLSD highlight = *iter; + ret_llsd[retcount++]=highlight; + } + + for (LLSD::array_iterator iter = middle_llsd.beginArray(); + iter != middle_llsd.endArray();++iter) + { + LLSD highlight = *iter; + ret_llsd[retcount++]=highlight; + } + + for (LLSD::array_iterator iter = end_llsd.beginArray(); + iter != end_llsd.endArray();++iter) + { + LLSD highlight = *iter; + ret_llsd[retcount++]=highlight; + } + + return ret_llsd; + } + } + } + } + + //No patterns found. Just send back what was passed in. + ret_llsd[0]["text"] =text; + LLSD color_sd = color.getValue(); + ret_llsd[0]["color"]=color_sd; + return ret_llsd; } bool LLTextParser::parseFullLineHighlights(const std::string &text, LLColor4 *color) { - loadKeywords(); - - for (S32 i=0;i<mHighlights.size();i++) - { - if ((S32)mHighlights[i]["highlight"]==ALL || (S32)mHighlights[i]["condition"]==MATCHES) - { - if (findPattern(text,mHighlights[i]) >= 0 ) - { - LLSD color_llsd = mHighlights[i]["color"]; - color->setValue(color_llsd); - return TRUE; - } - } - } - return FALSE; //No matches found. + loadKeywords(); + + for (S32 i=0;i<mHighlights.size();i++) + { + if ((S32)mHighlights[i]["highlight"]==ALL || (S32)mHighlights[i]["condition"]==MATCHES) + { + if (findPattern(text,mHighlights[i]) >= 0 ) + { + LLSD color_llsd = mHighlights[i]["color"]; + color->setValue(color_llsd); + return TRUE; + } + } + } + return FALSE; //No matches found. } std::string LLTextParser::getFileName() { - std::string path=gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, ""); - - if (!path.empty()) - { - path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "highlights.xml"); - } - return path; + std::string path=gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, ""); + + if (!path.empty()) + { + path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "highlights.xml"); + } + return path; } void LLTextParser::loadKeywords() { - if (mLoaded) - {// keywords already loaded - return; - } - std::string filename=getFileName(); - if (!filename.empty()) - { - llifstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::fromXML(mHighlights, file); - } - file.close(); - mLoaded = true; - } + if (mLoaded) + {// keywords already loaded + return; + } + std::string filename=getFileName(); + if (!filename.empty()) + { + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(mHighlights, file); + } + file.close(); + mLoaded = true; + } } bool LLTextParser::saveToDisk(LLSD highlights) { - mHighlights=highlights; - std::string filename=getFileName(); - if (filename.empty()) - { - LL_WARNS() << "LLTextParser::saveToDisk() no valid user directory." << LL_ENDL; - return FALSE; - } - llofstream file; - file.open(filename.c_str()); - LLSDSerialize::toPrettyXML(mHighlights, file); - file.close(); - return TRUE; + mHighlights=highlights; + std::string filename=getFileName(); + if (filename.empty()) + { + LL_WARNS() << "LLTextParser::saveToDisk() no valid user directory." << LL_ENDL; + return FALSE; + } + llofstream file; + file.open(filename.c_str()); + LLSDSerialize::toPrettyXML(mHighlights, file); + file.close(); + return TRUE; } diff --git a/indra/llui/lltextparser.h b/indra/llui/lltextparser.h index 3d71e40452..20fcc07e4c 100644 --- a/indra/llui/lltextparser.h +++ b/indra/llui/lltextparser.h @@ -1,25 +1,25 @@ -/** +/** * @file llTextParser.h * @brief GUI for user-defined highlights * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @@ -37,26 +37,26 @@ class LLColor4; class LLTextParser : public LLSingleton<LLTextParser> { - LLSINGLETON(LLTextParser); + LLSINGLETON(LLTextParser); public: - typedef enum e_condition_type { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH } EConditionType; - typedef enum e_highlight_type { PART, ALL } EHighlightType; - typedef enum e_highlight_position { WHOLE, START, MIDDLE, END } EHighlightPosition; - typedef enum e_dialog_action { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE } EDialogAction; + typedef enum e_condition_type { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH } EConditionType; + typedef enum e_highlight_type { PART, ALL } EHighlightType; + typedef enum e_highlight_position { WHOLE, START, MIDDLE, END } EHighlightPosition; + typedef enum e_dialog_action { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE } EDialogAction; - LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color, EHighlightPosition part=WHOLE, S32 index=0); - bool parseFullLineHighlights(const std::string &text, LLColor4 *color); + LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color, EHighlightPosition part=WHOLE, S32 index=0); + bool parseFullLineHighlights(const std::string &text, LLColor4 *color); private: - S32 findPattern(const std::string &text, LLSD highlight); - std::string getFileName(); - void loadKeywords(); - bool saveToDisk(LLSD highlights); + S32 findPattern(const std::string &text, LLSD highlight); + std::string getFileName(); + void loadKeywords(); + bool saveToDisk(LLSD highlights); public: - LLSD mHighlights; - bool mLoaded; + LLSD mHighlights; + bool mLoaded; }; #endif diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp index 78049319bc..8ffce1b8b4 100644 --- a/indra/llui/lltextutil.cpp +++ b/indra/llui/lltextutil.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltextutil.cpp * @brief Misc text-related auxiliary methods * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,30 +30,30 @@ #include "lltextbox.h" #include "llurlmatch.h" -boost::function<bool(LLUrlMatch*,LLTextBase*)> LLTextUtil::TextHelpers::iconCallbackCreationFunction = 0; +boost::function<bool(LLUrlMatch*,LLTextBase*)> LLTextUtil::TextHelpers::iconCallbackCreationFunction = 0; void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& hl) { - static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", LLColor4::green); + static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", LLColor4::green); - std::string text_uc = text; - LLStringUtil::toUpper(text_uc); + std::string text_uc = text; + LLStringUtil::toUpper(text_uc); - size_t hl_begin = 0, hl_len = hl.size(); + size_t hl_begin = 0, hl_len = hl.size(); - if (hl_len == 0 || (hl_begin = text_uc.find(hl)) == std::string::npos) - { - txtbox->setText(text, normal_style); - return; - } + if (hl_len == 0 || (hl_begin = text_uc.find(hl)) == std::string::npos) + { + txtbox->setText(text, normal_style); + return; + } - LLStyle::Params hl_style = normal_style; - hl_style.color = sFilterTextColor; + LLStyle::Params hl_style = normal_style; + hl_style.color = sFilterTextColor; - txtbox->setText(LLStringUtil::null); // clear text - txtbox->appendText(text.substr(0, hl_begin), false, normal_style); - txtbox->appendText(text.substr(hl_begin, hl_len), false, hl_style); - txtbox->appendText(text.substr(hl_begin + hl_len), false, normal_style); + txtbox->setText(LLStringUtil::null); // clear text + txtbox->appendText(text.substr(0, hl_begin), false, normal_style); + txtbox->appendText(text.substr(hl_begin, hl_len), false, hl_style); + txtbox->appendText(text.substr(hl_begin + hl_len), false, normal_style); } void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& greyed) @@ -78,34 +78,34 @@ void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& n bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted) { - if (match == 0 || text_base == 0) - return false; - - if(match->getID() != LLUUID::null && TextHelpers::iconCallbackCreationFunction) - { - bool segment_created = TextHelpers::iconCallbackCreationFunction(match,text_base); - if(segment_created) - return true; - } - - // output an optional icon before the Url - if (is_content_trusted && !match->getIcon().empty() ) - { - LLUIImagePtr image = LLUI::getUIImage(match->getIcon()); - if (image) - { - LLStyle::Params icon; - icon.image = image; - // Text will be replaced during rendering with the icon, - // but string cannot be empty or the segment won't be - // added (or drawn). - text_base->appendImageSegment(icon); - - return true; - } - } - - return false; + if (match == 0 || text_base == 0) + return false; + + if(match->getID() != LLUUID::null && TextHelpers::iconCallbackCreationFunction) + { + bool segment_created = TextHelpers::iconCallbackCreationFunction(match,text_base); + if(segment_created) + return true; + } + + // output an optional icon before the Url + if (is_content_trusted && !match->getIcon().empty() ) + { + LLUIImagePtr image = LLUI::getUIImage(match->getIcon()); + if (image) + { + LLStyle::Params icon; + icon.image = image; + // Text will be replaced during rendering with the icon, + // but string cannot be empty or the segment won't be + // added (or drawn). + text_base->appendImageSegment(icon); + + return true; + } + } + + return false; } // EOF diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h index 1adc3516f7..f3838e59fa 100644 --- a/indra/llui/lltextutil.h +++ b/indra/llui/lltextutil.h @@ -1,25 +1,25 @@ -/** +/** * @file lltextutil.h * @brief Misc text-related auxiliary methods * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,48 +36,48 @@ class LLTextBase; namespace LLTextUtil { - /** - * Set value for text box, highlighting substring hl_uc. - * - * Used to highlight filter matches. - * - * @param txtbox Text box to set value for - * @param normal_style Style to use for non-highlighted text - * @param text Text to set - * @param hl Upper-cased string to highlight - */ - void textboxSetHighlightedVal( - LLTextBox *txtbox, - const LLStyle::Params& normal_style, - const std::string& text, - const std::string& hl); + /** + * Set value for text box, highlighting substring hl_uc. + * + * Used to highlight filter matches. + * + * @param txtbox Text box to set value for + * @param normal_style Style to use for non-highlighted text + * @param text Text to set + * @param hl Upper-cased string to highlight + */ + void textboxSetHighlightedVal( + LLTextBox *txtbox, + const LLStyle::Params& normal_style, + const std::string& text, + const std::string& hl); + + void textboxSetGreyedVal( + LLTextBox *txtbox, + const LLStyle::Params& normal_style, + const std::string& text, + const std::string& greyed); - void textboxSetGreyedVal( - LLTextBox *txtbox, - const LLStyle::Params& normal_style, - const std::string& text, - const std::string& greyed); + /** + * Adds icon before url if need. + * + * @param[in] match an object with results of matching + * @param[in] text_base pointer to UI text object + * @param[in] is_content_trusted true if context is trusted + * @return reference to string with formatted phone number + */ + bool processUrlMatch(LLUrlMatch* match, LLTextBase* text_base, bool is_content_trusted); - /** - * Adds icon before url if need. - * - * @param[in] match an object with results of matching - * @param[in] text_base pointer to UI text object - * @param[in] is_content_trusted true if context is trusted - * @return reference to string with formatted phone number - */ - bool processUrlMatch(LLUrlMatch* match, LLTextBase* text_base, bool is_content_trusted); + class TextHelpers + { - class TextHelpers - { + //we need this special callback since we need to create LLAvataIconCtrls while parsing + //avatar/group url but can't create LLAvataIconCtrl from LLUI + public: + static boost::function<bool(LLUrlMatch*,LLTextBase*)> iconCallbackCreationFunction; + }; - //we need this special callback since we need to create LLAvataIconCtrls while parsing - //avatar/group url but can't create LLAvataIconCtrl from LLUI - public: - static boost::function<bool(LLUrlMatch*,LLTextBase*)> iconCallbackCreationFunction; - }; - } #endif // LL_LLTEXTUTIL_H diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index bfe0a5bb5d..9e27ed6232 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -27,330 +27,452 @@ // Text editor widget to let users enter a single line. #include "linden_common.h" - + #include "lltextvalidate.h" + +#include "llnotificationsutil.h" +#include "lltrans.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); - declare("ascii_with_newline", validateASCIIWithNewLine); - } - - // 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 validateNonNegativeS32NoSpace(const LLWString &str) - { - LLLocale locale(LLLocale::USER_LOCALE); - - LLWString test_str = str; - S32 len = test_str.length(); - bool success = TRUE; - if(0 < len) - { - if('-' == test_str[0]) - { - success = FALSE; - } - S32 i = 0; - while(success && (i < len)) - { - if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++])) - { - success = FALSE; - } - } - } - if (success) - { - S32 val = strtol(wstring_to_utf8str(test_str).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; - } - - bool validateASCIINoLeadingSpace(const LLWString &str) - { - if (LLStringOps::isSpace(str[0])) - { - return FALSE; - } - return validateASCII(str); - } - - // Used for multiline text stored on the server. - // Example is landmark description in Places SP. - bool validateASCIIWithNewLine(const LLWString &str) - { - bool rv = TRUE; - S32 len = str.length(); - while(len--) - { - if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f) - { - rv = FALSE; - break; - } - } - return rv; - } + +static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); } +static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); } + +static LLSD llsd(const std::string& str) { return LLSD(str); } +static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); } +template <class CHAR> +LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(1, ch)); } + +void ValidatorImpl::setLastErrorShowTime() +{ + mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime(); +} + +void Validator::showLastErrorUsingTimeout(U32 timeout) +{ + if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout) + { + mImpl->setLastErrorShowTime(); + std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues()); + LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason)); + } } + +// 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. +class ValidatorFloat : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + // May be a comma or period, depending on the locale + CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint(); + + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if ((decimal_point != ch) && !LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorFloatImpl; +Validator validateFloat(validatorFloatImpl); + +// 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. +class ValidatorInt : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR> &str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + S32 i = 0; + + // First character can be a negative sign + if ('-' == trimmed.front()) + { + i++; + } + + for (; i < len; i++) + { + CHAR ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorIntImpl; +Validator validateInt(validatorIntImpl); + +class ValidatorPositiveS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if (('-' == ch) || ('0' == ch)) + { + return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val <= 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorPositiveS32Impl; +Validator validatePositiveS32(validatorPositiveS32Impl); + +class ValidatorNonNegativeS32 : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> trimmed = str; + LLStringUtilBase<CHAR>::trim(trimmed); + S32 len = trimmed.length(); + if (0 < len) + { + CHAR ch = trimmed.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = trimmed[i]; + if (!LLStringOps::isDigit(ch)) + { + return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(trimmed); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32Impl; +Validator validateNonNegativeS32(validatorNonNegativeS32Impl); + +class ValidatorNonNegativeS32NoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + std::basic_string<CHAR> test_str = str; + S32 len = test_str.length(); + if (0 < len) + { + CHAR ch = test_str.front(); + + if ('-' == ch) + { + return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch))); + } + + for (S32 i = 0; i < len; ++i) + { + ch = test_str[i]; + if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch)) + { + return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch))); + } + } + } + + S32 val = strtol(test_str); + if (val < 0) + { + return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str))); + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorNonNegativeS32NoSpaceImpl; +Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl); + +class ValidatorAlphaNum : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch)) + { + return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumImpl; +Validator validateAlphaNum(validatorAlphaNumImpl); + +class ValidatorAlphaNumSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + LLLocale locale(LLLocale::USER_LOCALE); + + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (!LLStringOps::isAlnum(ch) && (' ' != ch)) + { + return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorAlphaNumSpaceImpl; +Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl); + +// 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. +class ValidatorASCIIPrintableNoPipe : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f || ch == '|' || + (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoPipeImpl; +Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl); + +// Used for avatar names +class ValidatorASCIIPrintableNoSpace : public ValidatorImpl +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) || + (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch))) + { + return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIPrintableNoSpaceImpl; +Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl); + +class ValidatorASCII : public ValidatorImpl +{ +protected: + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if (ch < 0x20 || ch > 0x7f) + { + return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIImpl; +Validator validateASCII(validatorASCIIImpl); + +class ValidatorASCIINoLeadingSpace : public ValidatorASCII +{ + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + if (LLStringOps::isSpace(str.front())) + { + return false; + } + + return ValidatorASCII::validate<CHAR>(str); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIINoLeadingSpaceImpl; +Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl); + +class ValidatorASCIIWithNewLine : public ValidatorImpl +{ + // Used for multiline text stored on the server. + // Example is landmark description in Places SP. + template <class CHAR> + bool validate(const std::basic_string<CHAR>& str) + { + S32 len = str.length(); + while (len--) + { + CHAR ch = str[len]; + + if ((ch < 0x20 && ch != 0xA) || ch > 0x7f) + { + return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch))); + } + } + + return resetError(); + } + +public: + /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); } + /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); } +} validatorASCIIWithNewLineImpl; +Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl); + +void Validators::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); + declare("ascii_with_newline", validateASCIIWithNewLine); +} + +} // namespace LLTextValidate diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index e2b6c313d6..2c2941de7f 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -34,27 +34,68 @@ 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 validateNonNegativeS32NoSpace(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); - bool validateASCIINoLeadingSpace(const LLWString &str); - bool validateASCIIWithNewLine(const LLWString &str); -} + class ValidatorImpl + { + public: + ValidatorImpl() {} + virtual ~ValidatorImpl() {} + virtual bool validate(const std::string& str) = 0; + virtual bool validate(const LLWString& str) = 0; + + bool setError(std::string name, LLSD values = LLSD()) { return mLastErrorName = name, mLastErrorValues = values, false; } + bool resetError() { return mLastErrorName.clear(), mLastErrorValues.clear(), true; } + const std::string& getLastErrorName() const { return mLastErrorName; } + const LLSD& getLastErrorValues() const { return mLastErrorValues; } + + void setLastErrorShowTime(); + U32 getLastErrorShowTime() const { return mLastErrorShowTime; } + + protected: + std::string mLastErrorName; + LLSD mLastErrorValues; + U32 mLastErrorShowTime { 0 }; + }; + + class Validator + { + public: + Validator() : mImpl(nullptr) {} + Validator(ValidatorImpl& impl) : mImpl(&impl) {} + Validator(const Validator& validator) : mImpl(validator.mImpl) {} + Validator(const Validator* validator) : mImpl(validator->mImpl) {} + + bool validate(const std::string& str) const { return !mImpl || mImpl->validate(str); } + bool validate(const LLWString& str) const { return !mImpl || mImpl->validate(str); } + + operator bool() const { return mImpl; } + + static const U32 SHOW_LAST_ERROR_TIMEOUT_SEC = 30; + void showLastErrorUsingTimeout(U32 timeout = SHOW_LAST_ERROR_TIMEOUT_SEC); + + private: + ValidatorImpl* mImpl; + }; + + // Available validators + extern Validator validateFloat; + extern Validator validateInt; + extern Validator validatePositiveS32; + extern Validator validateNonNegativeS32; + extern Validator validateNonNegativeS32NoSpace; + extern Validator validateAlphaNum; + extern Validator validateAlphaNumSpace; + extern Validator validateASCIIPrintableNoPipe; + extern Validator validateASCIIPrintableNoSpace; + extern Validator validateASCII; + extern Validator validateASCIINoLeadingSpace; + extern Validator validateASCIIWithNewLine; + + // Add available validators to the internal map + struct Validators : public LLInitParam::TypeValuesHelper<Validator, Validators> + { + static void declareValues(); + }; +}; #endif diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp index 516057f8fd..3d404293c6 100644 --- a/indra/llui/lltimectrl.cpp +++ b/indra/llui/lltimectrl.cpp @@ -49,385 +49,406 @@ const U32 HOURS_MAX = 12; const U32 MINUTES_PER_HOUR = 60; const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR; +class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl +{ +public: + // virtual + bool validate(const std::string& str) override + { + std::string hours = LLTimeCtrl::getHoursString(str); + if (!LLTimeCtrl::isHoursStringValid(hours)) + return setError("ValidatorInvalidHours", LLSD().with("STR", hours)); + + std::string minutes = LLTimeCtrl::getMinutesString(str); + if (!LLTimeCtrl::isMinutesStringValid(minutes)) + return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes)); + + std::string ampm = LLTimeCtrl::getAMPMString(str); + if (!LLTimeCtrl::isPMAMStringValid(ampm)) + return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm)); + + return resetError(); + } + + // virtual + bool validate(const LLWString& wstr) override + { + std::string str = wstring_to_utf8str(wstr); + + return validate(str); + } +} validateTimeImpl; +LLTextValidate::Validator validateTime(validateTimeImpl); LLTimeCtrl::Params::Params() -: label_width("label_width"), - snap_to("snap_to"), - allow_text_entry("allow_text_entry", true), - text_enabled_color("text_enabled_color"), - text_disabled_color("text_disabled_color"), - up_button("up_button"), - down_button("down_button") +: label_width("label_width"), + snap_to("snap_to"), + allow_text_entry("allow_text_entry", true), + text_enabled_color("text_enabled_color"), + text_disabled_color("text_disabled_color"), + up_button("up_button"), + down_button("down_button") {} LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p) -: LLUICtrl(p), - mLabelBox(NULL), - mTextEnabledColor(p.text_enabled_color()), - mTextDisabledColor(p.text_disabled_color()), - mTime(0), - mSnapToMin(5) +: LLUICtrl(p), + mLabelBox(NULL), + mTextEnabledColor(p.text_enabled_color()), + mTextDisabledColor(p.text_disabled_color()), + mTime(0), + mSnapToMin(5) { - static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0); - static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0); - static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0); - S32 centered_top = getRect().getHeight(); - S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height; - S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40)); - S32 editor_left = label_width + spinctrl_spacing; - - //================= Label =================// - if( !p.label().empty() ) - { - LLRect label_rect( 0, centered_top, label_width, centered_bottom ); - LLTextBox::Params params; - params.name("TimeCtrl Label"); - params.rect(label_rect); - params.initial_value(p.label()); - if (p.font.isProvided()) - { - params.font(p.font); - } - mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mLabelBox); - - editor_left = label_rect.mRight + spinctrl_spacing; - } - - S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing; - - //================= Editor ================// - LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom ); - LLLineEditor::Params params; - params.name("SpinCtrl Editor"); - params.rect(editor_rect); - if (p.font.isProvided()) - { - params.font(p.font); - } - - params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - params.max_length.chars(8); - params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1)); - mEditor = LLUICtrlFactory::create<LLLineEditor> (params); - mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); - mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1)); - mEditor->setText(LLStringExplicit("12:00 AM")); - addChild(mEditor); - - //================= Spin Buttons ==========// - LLButton::Params up_button_params(p.up_button); - up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height); - - up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this)); - up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this)); - mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params); - addChild(mUpBtn); - - LLButton::Params down_button_params(p.down_button); - down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height); - down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this)); - down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this)); - mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params); - addChild(mDownBtn); - - setUseBoundingRect( TRUE ); + static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0); + static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0); + static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0); + S32 centered_top = getRect().getHeight(); + S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height; + S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40)); + S32 editor_left = label_width + spinctrl_spacing; + + //================= Label =================// + if( !p.label().empty() ) + { + LLRect label_rect( 0, centered_top, label_width, centered_bottom ); + LLTextBox::Params params; + params.name("TimeCtrl Label"); + params.rect(label_rect); + params.initial_value(p.label()); + if (p.font.isProvided()) + { + params.font(p.font); + } + mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mLabelBox); + + editor_left = label_rect.mRight + spinctrl_spacing; + } + + S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing; + + //================= Editor ================// + LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom ); + LLLineEditor::Params params; + params.name("SpinCtrl Editor"); + params.rect(editor_rect); + if (p.font.isProvided()) + { + params.font(p.font); + } + + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + params.max_length.chars(8); + params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1)); + mEditor = LLUICtrlFactory::create<LLLineEditor> (params); + mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace); + mEditor->setPrevalidate(validateTime); + mEditor->setText(LLStringExplicit("12:00 AM")); + addChild(mEditor); + + //================= Spin Buttons ==========// + LLButton::Params up_button_params(p.up_button); + up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height); + + up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this)); + up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this)); + mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params); + addChild(mUpBtn); + + LLButton::Params down_button_params(p.down_button); + down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height); + down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this)); + down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this)); + mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params); + addChild(mDownBtn); + + setUseBoundingRect( TRUE ); } F32 LLTimeCtrl::getTime24() const { - // 0.0 - 23.99; - return mTime / 60.0f; + // 0.0 - 23.99; + return mTime / 60.0f; } U32 LLTimeCtrl::getHours24() const { - return (U32) getTime24(); + return (U32) getTime24(); } U32 LLTimeCtrl::getMinutes() const { - return mTime % MINUTES_PER_HOUR; + return mTime % MINUTES_PER_HOUR; } void LLTimeCtrl::setTime24(F32 time) { - time = llclamp(time, 0.0f, 23.99f); // fix out of range values - mTime = ll_round(time * MINUTES_PER_HOUR); // fixes values like 4.99999 + time = llclamp(time, 0.0f, 23.99f); // fix out of range values + mTime = ll_round(time * MINUTES_PER_HOUR); // fixes values like 4.99999 - updateText(); + updateText(); } BOOL LLTimeCtrl::handleKeyHere(KEY key, MASK mask) { - if (mEditor->hasFocus()) - { - if(key == KEY_UP) - { - onUpBtn(); - return TRUE; - } - if(key == KEY_DOWN) - { - onDownBtn(); - return TRUE; - } - if (key == KEY_RETURN) - { - onCommit(); - return TRUE; - } - } - return FALSE; + if (mEditor->hasFocus()) + { + if(key == KEY_UP) + { + onUpBtn(); + return TRUE; + } + if(key == KEY_DOWN) + { + onDownBtn(); + return TRUE; + } + if (key == KEY_RETURN) + { + onCommit(); + return TRUE; + } + } + return FALSE; } void LLTimeCtrl::onUpBtn() { - switch(getEditingPart()) - { - case HOURS: - increaseHours(); - break; - case MINUTES: - increaseMinutes(); - break; - case DAYPART: - switchDayPeriod(); - break; - default: - break; - } - - updateText(); - onCommit(); + switch(getEditingPart()) + { + case HOURS: + increaseHours(); + break; + case MINUTES: + increaseMinutes(); + break; + case DAYPART: + switchDayPeriod(); + break; + default: + break; + } + + updateText(); + onCommit(); } void LLTimeCtrl::onDownBtn() { - switch(getEditingPart()) - { - case HOURS: - decreaseHours(); - break; - case MINUTES: - decreaseMinutes(); - break; - case DAYPART: - switchDayPeriod(); - break; - default: - break; - } - - updateText(); - onCommit(); + switch(getEditingPart()) + { + case HOURS: + decreaseHours(); + break; + case MINUTES: + decreaseMinutes(); + break; + case DAYPART: + switchDayPeriod(); + break; + default: + break; + } + + updateText(); + onCommit(); } void LLTimeCtrl::onFocusLost() { - updateText(); - onCommit(); - LLUICtrl::onFocusLost(); + updateText(); + onCommit(); + LLUICtrl::onFocusLost(); } void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor) { - std::string time_str = line_editor->getText(); - U32 h12 = parseHours(getHoursString(time_str)); - U32 m = parseMinutes(getMinutesString(time_str)); - bool pm = parseAMPM(getAMPMString(time_str)); - - if (h12 == 12) - { - h12 = 0; - } + std::string time_str = line_editor->getText(); + U32 h12 = parseHours(getHoursString(time_str)); + U32 m = parseMinutes(getMinutesString(time_str)); + bool pm = parseAMPM(getAMPMString(time_str)); - U32 h24 = pm ? h12 + 12 : h12; + if (h12 == 12) + { + h12 = 0; + } - mTime = h24 * MINUTES_PER_HOUR + m; -} - -bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr) -{ - std::string str = wstring_to_utf8str(wstr); + U32 h24 = pm ? h12 + 12 : h12; - return isHoursStringValid(getHoursString(str)) && - isMinutesStringValid(getMinutesString(str)) && - isPMAMStringValid(getAMPMString(str)); + mTime = h24 * MINUTES_PER_HOUR + m; } void LLTimeCtrl::increaseMinutes() { - mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin); + mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin); } void LLTimeCtrl::increaseHours() { - mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY; + mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY; } void LLTimeCtrl::decreaseMinutes() { - if (mTime < mSnapToMin) - { - mTime = MINUTES_PER_DAY - mTime; - } + if (mTime < mSnapToMin) + { + mTime = MINUTES_PER_DAY - mTime; + } - mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin; + mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin; } void LLTimeCtrl::decreaseHours() { - if (mTime < MINUTES_PER_HOUR) - { - mTime = 23 * MINUTES_PER_HOUR + mTime; - } - else - { - mTime -= MINUTES_PER_HOUR; - } + if (mTime < MINUTES_PER_HOUR) + { + mTime = 23 * MINUTES_PER_HOUR + mTime; + } + else + { + mTime -= MINUTES_PER_HOUR; + } } bool LLTimeCtrl::isPM() const { - return mTime >= (MINUTES_PER_DAY / 2); + return mTime >= (MINUTES_PER_DAY / 2); } void LLTimeCtrl::switchDayPeriod() { - if (isPM()) - { - mTime -= MINUTES_PER_DAY / 2; - } - else - { - mTime += MINUTES_PER_DAY / 2; - } + if (isPM()) + { + mTime -= MINUTES_PER_DAY / 2; + } + else + { + mTime += MINUTES_PER_DAY / 2; + } } void LLTimeCtrl::updateText() { - U32 h24 = getHours24(); - U32 m = getMinutes(); - U32 h12 = h24 > 12 ? h24 - 12 : h24; + U32 h24 = getHours24(); + U32 m = getMinutes(); + U32 h12 = h24 > 12 ? h24 - 12 : h24; - if (h12 == 0) - h12 = 12; + if (h12 == 0) + h12 = 12; - mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM")); + mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM")); } LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart() { - S32 cur_pos = mEditor->getCursor(); - std::string time_str = mEditor->getText(); - - S32 colon_index = time_str.find_first_of(':'); - - if (cur_pos <= colon_index) - { - return HOURS; - } - else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN)) - { - return MINUTES; - } - else if (cur_pos > (S32)(time_str.length() - AMPM_LEN)) - { - return DAYPART; - } - - return NONE; + S32 cur_pos = mEditor->getCursor(); + std::string time_str = mEditor->getText(); + + S32 colon_index = time_str.find_first_of(':'); + + if (cur_pos <= colon_index) + { + return HOURS; + } + else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN)) + { + return MINUTES; + } + else if (cur_pos > (S32)(time_str.length() - AMPM_LEN)) + { + return DAYPART; + } + + return NONE; } // static std::string LLTimeCtrl::getHoursString(const std::string& str) { - size_t colon_index = str.find_first_of(':'); - std::string hours_str = str.substr(0, colon_index); + size_t colon_index = str.find_first_of(':'); + std::string hours_str = str.substr(0, colon_index); - return hours_str; + return hours_str; } // static std::string LLTimeCtrl::getMinutesString(const std::string& str) { - size_t colon_index = str.find_first_of(':'); - ++colon_index; + size_t colon_index = str.find_first_of(':'); + ++colon_index; - int minutes_len = str.length() - colon_index - AMPM_LEN; - std::string minutes_str = str.substr(colon_index, minutes_len); + int minutes_len = str.length() - colon_index - AMPM_LEN; + std::string minutes_str = str.substr(colon_index, minutes_len); - return minutes_str; + return minutes_str; } // static std::string LLTimeCtrl::getAMPMString(const std::string& str) { - return str.substr(str.size() - 2, 2); // returns last two characters + return str.substr(str.size() - 2, 2); // returns last two characters } // static bool LLTimeCtrl::isHoursStringValid(const std::string& str) { - U32 hours; - if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3) - return true; + U32 hours; + if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3) + return true; - return false; + return false; } // static bool LLTimeCtrl::isMinutesStringValid(const std::string& str) { - U32 minutes; - if (!LLStringUtil::convertToU32(str, minutes) || ((minutes <= MINUTES_MAX) && str.length() < 3)) - return true; + U32 minutes; + if (!LLStringUtil::convertToU32(str, minutes) || ((minutes <= MINUTES_MAX) && str.length() < 3)) + return true; - return false; + return false; } // static bool LLTimeCtrl::isPMAMStringValid(const std::string& str) { - S32 len = str.length(); + S32 len = str.length(); - bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A'); + bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A'); - return valid; + return valid; } // static U32 LLTimeCtrl::parseHours(const std::string& str) { - U32 hours; - if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX)) - { - return hours; - } - else - { - return HOURS_MIN; - } + U32 hours; + if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX)) + { + return hours; + } + else + { + return HOURS_MIN; + } } // static U32 LLTimeCtrl::parseMinutes(const std::string& str) { - U32 minutes; - // not sure of this fix - clang doesnt like compare minutes U32 to >= MINUTES_MIN (0) but MINUTES_MIN can change - if (LLStringUtil::convertToU32(str, minutes) && ((S32)minutes >= MINUTES_MIN) && ((S32)minutes <= MINUTES_MAX)) - { - return minutes; - } - else - { - return MINUTES_MIN; - } + U32 minutes; + // not sure of this fix - clang doesnt like compare minutes U32 to >= MINUTES_MIN (0) but MINUTES_MIN can change + if (LLStringUtil::convertToU32(str, minutes) && ((S32)minutes >= MINUTES_MIN) && ((S32)minutes <= MINUTES_MAX)) + { + return minutes; + } + else + { + return MINUTES_MIN; + } } // static bool LLTimeCtrl::parseAMPM(const std::string& str) { - return str == "PM"; + return str == "PM"; } diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h index b5f268c76a..a2c016ab6f 100644 --- a/indra/llui/lltimectrl.h +++ b/indra/llui/lltimectrl.h @@ -37,95 +37,93 @@ class LLLineEditor; class LLTimeCtrl : public LLUICtrl { - LOG_CLASS(LLTimeCtrl); + LOG_CLASS(LLTimeCtrl); public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<S32> label_width; - Optional<S32> snap_to; - Optional<bool> allow_text_entry; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<S32> label_width; + Optional<S32> snap_to; + Optional<bool> allow_text_entry; - Optional<LLUIColor> text_enabled_color; - Optional<LLUIColor> text_disabled_color; + Optional<LLUIColor> text_enabled_color; + Optional<LLUIColor> text_disabled_color; - Optional<LLButton::Params> up_button; - Optional<LLButton::Params> down_button; + Optional<LLButton::Params> up_button; + Optional<LLButton::Params> down_button; - Params(); - }; + Params(); + }; - F32 getTime24() const; // 0.0 - 24.0 - U32 getHours24() const; // 0 - 23 - U32 getMinutes() const; // 0 - 59 + F32 getTime24() const; // 0.0 - 24.0 + U32 getHours24() const; // 0 - 23 + U32 getMinutes() const; // 0 - 59 - void setTime24(F32 time); // 0.0 - 23.98(3) + void setTime24(F32 time); // 0.0 - 23.98(3) -protected: - LLTimeCtrl(const Params&); - friend class LLUICtrlFactory; - -private: + static std::string getHoursString(const std::string& str); + static std::string getMinutesString(const std::string& str); + static std::string getAMPMString(const std::string& str); - enum EDayPeriod - { - AM, - PM - }; + static bool isHoursStringValid(const std::string& str); + static bool isMinutesStringValid(const std::string& str); + static bool isPMAMStringValid(const std::string& str); - enum EEditingPart - { - HOURS, - MINUTES, - DAYPART, - NONE - }; + static U32 parseHours(const std::string& str); + static U32 parseMinutes(const std::string& str); + static bool parseAMPM(const std::string& str); - virtual void onFocusLost(); - virtual BOOL handleKeyHere(KEY key, MASK mask); +protected: + LLTimeCtrl(const Params&); + friend class LLUICtrlFactory; - void onUpBtn(); - void onDownBtn(); - void onTextEntry(LLLineEditor* line_editor); +private: - bool isTimeStringValid(const LLWString& wstr); + enum EDayPeriod + { + AM, + PM + }; - void increaseMinutes(); - void increaseHours(); + enum EEditingPart + { + HOURS, + MINUTES, + DAYPART, + NONE + }; - void decreaseMinutes(); - void decreaseHours(); + virtual void onFocusLost(); + virtual BOOL handleKeyHere(KEY key, MASK mask); - bool isPM() const; - void switchDayPeriod(); + void onUpBtn(); + void onDownBtn(); + void onTextEntry(LLLineEditor* line_editor); - void updateText(); + void increaseMinutes(); + void increaseHours(); - EEditingPart getEditingPart(); + void decreaseMinutes(); + void decreaseHours(); - static std::string getHoursString(const std::string& str); - static std::string getMinutesString(const std::string& str); - static std::string getAMPMString(const std::string& str); + bool isPM() const; + void switchDayPeriod(); - static bool isHoursStringValid(const std::string& str); - static bool isMinutesStringValid(const std::string& str); - static bool isPMAMStringValid(const std::string& str); + void updateText(); - static U32 parseHours(const std::string& str); - static U32 parseMinutes(const std::string& str); - static bool parseAMPM(const std::string& str); + EEditingPart getEditingPart(); - class LLTextBox* mLabelBox; + class LLTextBox* mLabelBox; - class LLLineEditor* mEditor; - LLUIColor mTextEnabledColor; - LLUIColor mTextDisabledColor; + class LLLineEditor* mEditor; + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; - class LLButton* mUpBtn; - class LLButton* mDownBtn; + class LLButton* mUpBtn; + class LLButton* mDownBtn; - U32 mTime; // minutes since midnight: 0 - 1439 - U32 mSnapToMin; // interval in minutes to snap to + U32 mTime; // minutes since midnight: 0 - 1439 + U32 mSnapToMin; // interval in minutes to snap to - BOOL mAllowEdit; + BOOL mAllowEdit; }; #endif /* LLTIMECTRL_H_ */ diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp index 3e56e0a589..636df7a87e 100644 --- a/indra/llui/lltoggleablemenu.cpp +++ b/indra/llui/lltoggleablemenu.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltoggleablemenu.cpp * @brief Menu toggled by a button press * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,76 +33,76 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu"); LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p) -: LLMenuGL(p), - mButtonRect(), - mVisibilityChangeSignal(NULL), - mClosedByButtonClick(false) +: LLMenuGL(p), + mButtonRect(), + mVisibilityChangeSignal(NULL), + mClosedByButtonClick(false) { } LLToggleableMenu::~LLToggleableMenu() { - delete mVisibilityChangeSignal; + delete mVisibilityChangeSignal; } boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb) { - if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t(); - return mVisibilityChangeSignal->connect(cb); + if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t(); + return mVisibilityChangeSignal->connect(cb); } // virtual void LLToggleableMenu::onVisibilityChange (BOOL curVisibilityIn) { - S32 x,y; - LLUI::getInstance()->getMousePositionLocal(LLUI::getInstance()->getRootView(), &x, &y); + S32 x,y; + LLUI::getInstance()->getMousePositionLocal(LLUI::getInstance()->getRootView(), &x, &y); - // STORM-1879: also check MouseCapture to see if the button was really + // STORM-1879: also check MouseCapture to see if the button was really // clicked (otherwise the VisibilityChange was triggered via keyboard shortcut) - if (!curVisibilityIn && mButtonRect.pointInRect(x, y) && gFocusMgr.getMouseCapture()) - { - mClosedByButtonClick = true; - } - - if (mVisibilityChangeSignal) - { - (*mVisibilityChangeSignal)(this, - LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick)); - } + if (!curVisibilityIn && mButtonRect.pointInRect(x, y) && gFocusMgr.getMouseCapture()) + { + mClosedByButtonClick = true; + } + + if (mVisibilityChangeSignal) + { + (*mVisibilityChangeSignal)(this, + LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick)); + } } void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view) { - LLRect screen; - current_view->localRectToScreen(rect, &screen); - mButtonRect = screen; + LLRect screen; + current_view->localRectToScreen(rect, &screen); + mButtonRect = screen; } void LLToggleableMenu::setButtonRect(LLView* current_view) { - LLRect rect = current_view->getLocalRect(); - setButtonRect(rect, current_view); + LLRect rect = current_view->getLocalRect(); + setButtonRect(rect, current_view); } -bool LLToggleableMenu::toggleVisibility() +bool LLToggleableMenu::toggleVisibility() { - if (mClosedByButtonClick) - { - mClosedByButtonClick = false; - return false; - } - - if (getVisible()) - { - setVisible(FALSE); - mClosedByButtonClick = false; - return false; - } - - return true; + if (mClosedByButtonClick) + { + mClosedByButtonClick = false; + return false; + } + + if (getVisible()) + { + setVisible(FALSE); + mClosedByButtonClick = false; + return false; + } + + return true; } bool LLToggleableMenu::addChild(LLView* view, S32 tab_group) { - return addContextChild(view, tab_group); + return addContextChild(view, tab_group); } diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h index 55a6483021..1cf37ad647 100644 --- a/indra/llui/lltoggleablemenu.h +++ b/indra/llui/lltoggleablemenu.h @@ -1,25 +1,25 @@ -/** +/** * @file lltoggleablemenu.h * @brief Menu toggled by a button press * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,37 +35,37 @@ public: //adding blank params to work around registration issue //where LLToggleableMenu was owning the LLMenuGL param //and menu.xml was never loaded - struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> - {}; + struct Params : public LLInitParam::Block<Params, LLMenuGL::Params> + {}; protected: - LLToggleableMenu(const Params&); - friend class LLUICtrlFactory; + LLToggleableMenu(const Params&); + friend class LLUICtrlFactory; public: - ~LLToggleableMenu(); + ~LLToggleableMenu(); + + boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb ); + virtual void onVisibilityChange (BOOL curVisibilityIn); - virtual void onVisibilityChange (BOOL curVisibilityIn); + virtual bool addChild (LLView* view, S32 tab_group = 0); - virtual bool addChild (LLView* view, S32 tab_group = 0); + const LLRect& getButtonRect() const { return mButtonRect; } - const LLRect& getButtonRect() const { return mButtonRect; } + // Converts the given local button rect to a screen rect + void setButtonRect(const LLRect& rect, LLView* current_view); + void setButtonRect(LLView* current_view); - // Converts the given local button rect to a screen rect - void setButtonRect(const LLRect& rect, LLView* current_view); - void setButtonRect(LLView* current_view); + // Returns "true" if menu was not closed by button click + // and is not still visible. If menu is visible toggles + // its visibility off. + bool toggleVisibility(); - // Returns "true" if menu was not closed by button click - // and is not still visible. If menu is visible toggles - // its visibility off. - bool toggleVisibility(); - - LLHandle<LLToggleableMenu> getHandle() { return getDerivedHandle<LLToggleableMenu>(); } + LLHandle<LLToggleableMenu> getHandle() { return getDerivedHandle<LLToggleableMenu>(); } protected: - bool mClosedByButtonClick; - LLRect mButtonRect; - commit_signal_t* mVisibilityChangeSignal; + bool mClosedByButtonClick; + LLRect mButtonRect; + commit_signal_t* mVisibilityChangeSignal; }; #endif // LL_LLTOGGLEABLEMENU_H diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 204b8b9984..8a6cb683d2 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lltoolbar.cpp * @author Richard Nelson * @brief User customizable toolbar class @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,17 +41,17 @@ namespace LLToolBarEnums { - LLView::EOrientation getOrientation(SideType sideType) - { - LLView::EOrientation orientation = LLLayoutStack::HORIZONTAL; + LLView::EOrientation getOrientation(SideType sideType) + { + LLView::EOrientation orientation = LLLayoutStack::HORIZONTAL; - if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT)) - { - orientation = LLLayoutStack::VERTICAL; - } + if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT)) + { + orientation = LLLayoutStack::VERTICAL; + } - return orientation; - } + return orientation; + } } using namespace LLToolBarEnums; @@ -59,217 +59,217 @@ using namespace LLToolBarEnums; namespace LLInitParam { - void TypeValues<ButtonType>::declareValues() - { - declare("icons_with_text", BTNTYPE_ICONS_WITH_TEXT); - declare("icons_only", BTNTYPE_ICONS_ONLY); - } - - void TypeValues<SideType>::declareValues() - { - declare("bottom", SIDE_BOTTOM); - declare("left", SIDE_LEFT); - declare("right", SIDE_RIGHT); - declare("top", SIDE_TOP); - } + void TypeValues<ButtonType>::declareValues() + { + declare("icons_with_text", BTNTYPE_ICONS_WITH_TEXT); + declare("icons_only", BTNTYPE_ICONS_ONLY); + } + + void TypeValues<SideType>::declareValues() + { + declare("bottom", SIDE_BOTTOM); + declare("left", SIDE_LEFT); + declare("right", SIDE_RIGHT); + declare("top", SIDE_TOP); + } } LLToolBar::Params::Params() -: button_display_mode("button_display_mode"), - commands("command"), - side("side", SIDE_TOP), - button_icon("button_icon"), - button_icon_and_text("button_icon_and_text"), - read_only("read_only", false), - wrap("wrap", true), - pad_left("pad_left"), - pad_top("pad_top"), - pad_right("pad_right"), - pad_bottom("pad_bottom"), - pad_between("pad_between"), - min_girth("min_girth"), - button_panel("button_panel") +: button_display_mode("button_display_mode"), + commands("command"), + side("side", SIDE_TOP), + button_icon("button_icon"), + button_icon_and_text("button_icon_and_text"), + read_only("read_only", false), + wrap("wrap", true), + pad_left("pad_left"), + pad_top("pad_top"), + pad_right("pad_right"), + pad_bottom("pad_bottom"), + pad_between("pad_between"), + min_girth("min_girth"), + button_panel("button_panel") {} LLToolBar::LLToolBar(const LLToolBar::Params& p) -: LLUICtrl(p), - mReadOnly(p.read_only), - mButtonType(p.button_display_mode), - mSideType(p.side), - mWrap(p.wrap), - mNeedsLayout(false), - mModified(false), - mButtonPanel(NULL), - mCenteringStack(NULL), - mPadLeft(p.pad_left), - mPadRight(p.pad_right), - mPadTop(p.pad_top), - mPadBottom(p.pad_bottom), - mPadBetween(p.pad_between), - mMinGirth(p.min_girth), - mPopupMenuHandle(), - mRightMouseTargetButton(NULL), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), - mHandleDropCallback(NULL), - mButtonAddSignal(NULL), - mButtonEnterSignal(NULL), - mButtonLeaveSignal(NULL), - mButtonRemoveSignal(NULL), - mDragAndDropTarget(false), - mCaretIcon(NULL), - mCenterPanel(NULL) +: LLUICtrl(p), + mReadOnly(p.read_only), + mButtonType(p.button_display_mode), + mSideType(p.side), + mWrap(p.wrap), + mNeedsLayout(false), + mModified(false), + mButtonPanel(NULL), + mCenteringStack(NULL), + mPadLeft(p.pad_left), + mPadRight(p.pad_right), + mPadTop(p.pad_top), + mPadBottom(p.pad_bottom), + mPadBetween(p.pad_between), + mMinGirth(p.min_girth), + mPopupMenuHandle(), + mRightMouseTargetButton(NULL), + mStartDragItemCallback(NULL), + mHandleDragItemCallback(NULL), + mHandleDropCallback(NULL), + mButtonAddSignal(NULL), + mButtonEnterSignal(NULL), + mButtonLeaveSignal(NULL), + mButtonRemoveSignal(NULL), + mDragAndDropTarget(false), + mCaretIcon(NULL), + mCenterPanel(NULL) { - mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; - mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; + mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; + mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; } LLToolBar::~LLToolBar() { - auto menu = mPopupMenuHandle.get(); - if (menu) - { - menu->die(); - mPopupMenuHandle.markDead(); - } - delete mButtonAddSignal; - delete mButtonEnterSignal; - delete mButtonLeaveSignal; - delete mButtonRemoveSignal; + auto menu = mPopupMenuHandle.get(); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } + delete mButtonAddSignal; + delete mButtonEnterSignal; + delete mButtonLeaveSignal; + delete mButtonRemoveSignal; } void LLToolBar::createContextMenu() { - if (!mPopupMenuHandle.get()) - { - // Setup bindings specific to this instance for the context menu options - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg; - commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2)); - commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this)); - - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg; - enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2)); - - // Create the context menu - llassert(LLMenuGL::sMenuContainer != NULL); - LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); - - if (menu) - { - menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); - mPopupMenuHandle = menu->getHandle(); - mRemoveButtonHandle = menu->getChild<LLView>("Remove button")->getHandle(); - } - else - { - LL_WARNS() << "Unable to load toolbars context menu." << LL_ENDL; - } - } - - if (mRemoveButtonHandle.get()) - { - // Disable/Enable the "Remove button" menu item depending on whether or not a button was clicked - mRemoveButtonHandle.get()->setEnabled(mRightMouseTargetButton != NULL); - } + if (!mPopupMenuHandle.get()) + { + // Setup bindings specific to this instance for the context menu options + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg; + commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2)); + commit_reg.add("Toolbars.RemoveSelectedCommand", boost::bind(&LLToolBar::onRemoveSelectedCommand, this)); + + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg; + enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2)); + + // Create the context menu + llassert(LLMenuGL::sMenuContainer != NULL); + LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + + if (menu) + { + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); + mPopupMenuHandle = menu->getHandle(); + mRemoveButtonHandle = menu->getChild<LLView>("Remove button")->getHandle(); + } + else + { + LL_WARNS() << "Unable to load toolbars context menu." << LL_ENDL; + } + } + + if (mRemoveButtonHandle.get()) + { + // Disable/Enable the "Remove button" menu item depending on whether or not a button was clicked + mRemoveButtonHandle.get()->setEnabled(mRightMouseTargetButton != NULL); + } } void LLToolBar::initFromParams(const LLToolBar::Params& p) { - // Initialize the base object - LLUICtrl::initFromParams(p); - - LLView::EOrientation orientation = getOrientation(p.side); - - LLLayoutStack::Params centering_stack_p; - centering_stack_p.name = "centering_stack"; - centering_stack_p.rect = getLocalRect(); - centering_stack_p.follows.flags = FOLLOWS_ALL; - centering_stack_p.orientation = orientation; - centering_stack_p.mouse_opaque = false; - - mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p); - addChild(mCenteringStack); - - LLLayoutPanel::Params border_panel_p; - border_panel_p.name = "border_panel"; - border_panel_p.rect = getLocalRect(); - border_panel_p.auto_resize = true; - border_panel_p.user_resize = false; - border_panel_p.mouse_opaque = false; - - mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); - - LLLayoutPanel::Params center_panel_p; - center_panel_p.name = "center_panel"; - center_panel_p.rect = getLocalRect(); - center_panel_p.auto_resize = false; - center_panel_p.user_resize = false; - center_panel_p.mouse_opaque = false; - mCenterPanel = LLUICtrlFactory::create<LLCenterLayoutPanel>(center_panel_p); - mCenteringStack->addChild(mCenterPanel); - - LLPanel::Params button_panel_p(p.button_panel); - button_panel_p.rect = mCenterPanel->getLocalRect(); - button_panel_p.follows.flags = FOLLOWS_BOTTOM|FOLLOWS_LEFT; - mButtonPanel = LLUICtrlFactory::create<LLPanel>(button_panel_p); - mCenterPanel->setButtonPanel(mButtonPanel); - mCenterPanel->addChild(mButtonPanel); - - mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); - - for (const auto& id : p.commands) - { - addCommand(id); - } - - mNeedsLayout = true; + // Initialize the base object + LLUICtrl::initFromParams(p); + + LLView::EOrientation orientation = getOrientation(p.side); + + LLLayoutStack::Params centering_stack_p; + centering_stack_p.name = "centering_stack"; + centering_stack_p.rect = getLocalRect(); + centering_stack_p.follows.flags = FOLLOWS_ALL; + centering_stack_p.orientation = orientation; + centering_stack_p.mouse_opaque = false; + + mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p); + addChild(mCenteringStack); + + LLLayoutPanel::Params border_panel_p; + border_panel_p.name = "border_panel"; + border_panel_p.rect = getLocalRect(); + border_panel_p.auto_resize = true; + border_panel_p.user_resize = false; + border_panel_p.mouse_opaque = false; + + mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); + + LLLayoutPanel::Params center_panel_p; + center_panel_p.name = "center_panel"; + center_panel_p.rect = getLocalRect(); + center_panel_p.auto_resize = false; + center_panel_p.user_resize = false; + center_panel_p.mouse_opaque = false; + mCenterPanel = LLUICtrlFactory::create<LLCenterLayoutPanel>(center_panel_p); + mCenteringStack->addChild(mCenterPanel); + + LLPanel::Params button_panel_p(p.button_panel); + button_panel_p.rect = mCenterPanel->getLocalRect(); + button_panel_p.follows.flags = FOLLOWS_BOTTOM|FOLLOWS_LEFT; + mButtonPanel = LLUICtrlFactory::create<LLPanel>(button_panel_p); + mCenterPanel->setButtonPanel(mButtonPanel); + mCenterPanel->addChild(mButtonPanel); + + mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p)); + + for (const auto& id : p.commands) + { + addCommand(id); + } + + mNeedsLayout = true; } bool LLToolBar::addCommand(const LLCommandId& commandId, int rank) { - LLCommand * command = LLCommandManager::instance().getCommand(commandId); - if (!command) return false; - - // Create the button and do the things that don't need ordering - LLToolBarButton* button = createButton(commandId); - mButtonPanel->addChild(button); - mButtonMap.insert(std::make_pair(commandId.uuid(), button)); - - // Insert the command and button in the right place in their respective lists - if ((rank >= mButtonCommands.size()) || (rank == RANK_NONE)) - { - // In that case, back load - mButtonCommands.push_back(command->id()); - mButtons.push_back(button); - } - else - { - // Insert in place: iterate to the right spot... - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - command_id_list_t::iterator it_command = mButtonCommands.begin(); - while (rank > 0) - { - ++it_button; - ++it_command; - rank--; - } - // ...then insert - mButtonCommands.insert(it_command, command->id()); - mButtons.insert(it_button,button); - } - - mNeedsLayout = true; - - updateLayoutAsNeeded(); - - - if (mButtonAddSignal) - { - (*mButtonAddSignal)(button); - } - - return true; + LLCommand * command = LLCommandManager::instance().getCommand(commandId); + if (!command) return false; + + // Create the button and do the things that don't need ordering + LLToolBarButton* button = createButton(commandId); + mButtonPanel->addChild(button); + mButtonMap.insert(std::make_pair(commandId.uuid(), button)); + + // Insert the command and button in the right place in their respective lists + if ((rank >= mButtonCommands.size()) || (rank == RANK_NONE)) + { + // In that case, back load + mButtonCommands.push_back(command->id()); + mButtons.push_back(button); + } + else + { + // Insert in place: iterate to the right spot... + std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); + command_id_list_t::iterator it_command = mButtonCommands.begin(); + while (rank > 0) + { + ++it_button; + ++it_command; + rank--; + } + // ...then insert + mButtonCommands.insert(it_command, command->id()); + mButtons.insert(it_button,button); + } + + mNeedsLayout = true; + + updateLayoutAsNeeded(); + + + if (mButtonAddSignal) + { + (*mButtonAddSignal)(button); + } + + return true; } // Remove a command from the list @@ -278,990 +278,989 @@ bool LLToolBar::addCommand(const LLCommandId& commandId, int rank) // Returns RANK_NONE if the command is not found in the list int LLToolBar::removeCommand(const LLCommandId& commandId) { - if (!hasCommand(commandId)) return RANK_NONE; - - // First erase the map record - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - mButtonMap.erase(it); - - // Now iterate on the commands and buttons to identify the relevant records - int rank = 0; - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - command_id_list_t::iterator it_command = mButtonCommands.begin(); - while (*it_command != commandId) - { - ++it_button; - ++it_command; - ++rank; - } - - if (mButtonRemoveSignal) - { - (*mButtonRemoveSignal)(*it_button); - } - - // Delete the button and erase the command and button records - delete (*it_button); - mButtonCommands.erase(it_command); - mButtons.erase(it_button); - - mNeedsLayout = true; - - return rank; + if (!hasCommand(commandId)) return RANK_NONE; + + // First erase the map record + command_id_map::iterator it = mButtonMap.find(commandId.uuid()); + mButtonMap.erase(it); + + // Now iterate on the commands and buttons to identify the relevant records + int rank = 0; + std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); + command_id_list_t::iterator it_command = mButtonCommands.begin(); + while (*it_command != commandId) + { + ++it_button; + ++it_command; + ++rank; + } + + if (mButtonRemoveSignal) + { + (*mButtonRemoveSignal)(*it_button); + } + + // Delete the button and erase the command and button records + delete (*it_button); + mButtonCommands.erase(it_command); + mButtons.erase(it_button); + + mNeedsLayout = true; + + return rank; } void LLToolBar::clearCommandsList() { - // Clears the commands list - mButtonCommands.clear(); - // This will clear the buttons - createButtons(); + // Clears the commands list + mButtonCommands.clear(); + // This will clear the buttons + createButtons(); } bool LLToolBar::hasCommand(const LLCommandId& commandId) const { - if (commandId != LLCommandId::null) - { - command_id_map::const_iterator it = mButtonMap.find(commandId.uuid()); - return (it != mButtonMap.end()); - } + if (commandId != LLCommandId::null) + { + command_id_map::const_iterator it = mButtonMap.find(commandId.uuid()); + return (it != mButtonMap.end()); + } - return false; + return false; } bool LLToolBar::enableCommand(const LLCommandId& commandId, bool enabled) { - LLButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - command_button->setEnabled(enabled); - } - } - - return (command_button != NULL); + LLButton * command_button = NULL; + + if (commandId != LLCommandId::null) + { + command_id_map::iterator it = mButtonMap.find(commandId.uuid()); + if (it != mButtonMap.end()) + { + command_button = it->second; + command_button->setEnabled(enabled); + } + } + + return (command_button != NULL); } bool LLToolBar::stopCommandInProgress(const LLCommandId& commandId) { - // - // Note from Leslie: - // - // This implementation was largely put in place to handle EXP-1348 which is related to - // dragging and dropping the "speak" button. The "speak" button can be in one of two - // modes, i.e., either a toggle action or a push-to-talk action. Because of this it - // responds to mouse down and mouse up in different ways, based on which behavior the - // button is currently set to obey. This was the simplest way of getting the button - // to turn off the microphone for both behaviors without risking duplicate state. - // - - LLToolBarButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - LLCommand* command = LLCommandManager::instance().getCommand(commandId); - llassert(command); - - // If this command has an explicit function for execution stop - if (command->executeStopFunctionName().length() > 0) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - llassert(command_button->mIsRunningSignal); - - // Check to see if it is running - if ((*command_button->mIsRunningSignal)(command_button, command->isRunningParameters())) - { - // Trigger an additional button commit, which calls mouse down, mouse up and commit - command_button->onCommit(); - } - } - } - } - - return (command_button != NULL); + // + // Note from Leslie: + // + // This implementation was largely put in place to handle EXP-1348 which is related to + // dragging and dropping the "speak" button. The "speak" button can be in one of two + // modes, i.e., either a toggle action or a push-to-talk action. Because of this it + // responds to mouse down and mouse up in different ways, based on which behavior the + // button is currently set to obey. This was the simplest way of getting the button + // to turn off the microphone for both behaviors without risking duplicate state. + // + + LLToolBarButton * command_button = NULL; + + if (commandId != LLCommandId::null) + { + LLCommand* command = LLCommandManager::instance().getCommand(commandId); + llassert(command); + + // If this command has an explicit function for execution stop + if (command->executeStopFunctionName().length() > 0) + { + command_id_map::iterator it = mButtonMap.find(commandId.uuid()); + if (it != mButtonMap.end()) + { + command_button = it->second; + llassert(command_button->mIsRunningSignal); + + // Check to see if it is running + if ((*command_button->mIsRunningSignal)(command_button, command->isRunningParameters())) + { + // Trigger an additional button commit, which calls mouse down, mouse up and commit + command_button->onCommit(); + } + } + } + } + + return (command_button != NULL); } bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing/* = false */) { - LLButton * command_button = NULL; - - if (commandId != LLCommandId::null) - { - command_id_map::iterator it = mButtonMap.find(commandId.uuid()); - if (it != mButtonMap.end()) - { - command_button = it->second; - command_button->setFlashing((BOOL)(flash),(BOOL)(force_flashing)); - } - } - - return (command_button != NULL); + LLButton * command_button = NULL; + + if (commandId != LLCommandId::null) + { + command_id_map::iterator it = mButtonMap.find(commandId.uuid()); + if (it != mButtonMap.end()) + { + command_button = it->second; + command_button->setFlashing((BOOL)(flash),(BOOL)(force_flashing)); + } + } + + return (command_button != NULL); } BOOL LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLRect button_panel_rect; - mButtonPanel->localRectToOtherView(mButtonPanel->getLocalRect(), &button_panel_rect, this); - BOOL handle_it_here = !mReadOnly && button_panel_rect.pointInRect(x, y); - - if (handle_it_here) - { - // Determine which button the mouse was over during the click in case the context menu action - // is intended to affect the button. - mRightMouseTargetButton = NULL; - for (LLToolBarButton* button : mButtons) - { - LLRect button_rect; - button->localRectToOtherView(button->getLocalRect(), &button_rect, this); - - if (button_rect.pointInRect(x, y)) - { - mRightMouseTargetButton = button; - break; - } - } - - createContextMenu(); - - LLContextMenu * menu = (LLContextMenu *) mPopupMenuHandle.get(); - - if (menu) - { - menu->show(x, y); - - LLMenuGL::showPopup(this, menu, x, y); - } - } - - return handle_it_here; + LLRect button_panel_rect; + mButtonPanel->localRectToOtherView(mButtonPanel->getLocalRect(), &button_panel_rect, this); + BOOL handle_it_here = !mReadOnly && button_panel_rect.pointInRect(x, y); + + if (handle_it_here) + { + // Determine which button the mouse was over during the click in case the context menu action + // is intended to affect the button. + mRightMouseTargetButton = NULL; + for (LLToolBarButton* button : mButtons) + { + LLRect button_rect; + button->localRectToOtherView(button->getLocalRect(), &button_rect, this); + + if (button_rect.pointInRect(x, y)) + { + mRightMouseTargetButton = button; + break; + } + } + + createContextMenu(); + + LLContextMenu * menu = (LLContextMenu *) mPopupMenuHandle.get(); + + if (menu) + { + menu->show(x, y); + + LLMenuGL::showPopup(this, menu, x, y); + } + } + + return handle_it_here; } BOOL LLToolBar::isSettingChecked(const LLSD& userdata) { - BOOL retval = FALSE; + BOOL retval = FALSE; - const std::string setting_name = userdata.asString(); + const std::string setting_name = userdata.asString(); - if (setting_name == "icons_with_text") - { - retval = (mButtonType == BTNTYPE_ICONS_WITH_TEXT); - } - else if (setting_name == "icons_only") - { - retval = (mButtonType == BTNTYPE_ICONS_ONLY); - } + if (setting_name == "icons_with_text") + { + retval = (mButtonType == BTNTYPE_ICONS_WITH_TEXT); + } + else if (setting_name == "icons_only") + { + retval = (mButtonType == BTNTYPE_ICONS_ONLY); + } - return retval; + return retval; } void LLToolBar::onSettingEnable(const LLSD& userdata) { - llassert(!mReadOnly); - - const std::string setting_name = userdata.asString(); - - if (setting_name == "icons_with_text") - { - setButtonType(BTNTYPE_ICONS_WITH_TEXT); - } - else if (setting_name == "icons_only") - { - setButtonType(BTNTYPE_ICONS_ONLY); - } + llassert(!mReadOnly); + + const std::string setting_name = userdata.asString(); + + if (setting_name == "icons_with_text") + { + setButtonType(BTNTYPE_ICONS_WITH_TEXT); + } + else if (setting_name == "icons_only") + { + setButtonType(BTNTYPE_ICONS_ONLY); + } } void LLToolBar::onRemoveSelectedCommand() { - llassert(!mReadOnly); + llassert(!mReadOnly); - if (mRightMouseTargetButton) - { - removeCommand(mRightMouseTargetButton->getCommandId()); + if (mRightMouseTargetButton) + { + removeCommand(mRightMouseTargetButton->getCommandId()); - mRightMouseTargetButton = NULL; - } + mRightMouseTargetButton = NULL; + } } void LLToolBar::setButtonType(LLToolBarEnums::ButtonType button_type) { - bool regenerate_buttons = (mButtonType != button_type); - - mButtonType = button_type; - - if (regenerate_buttons) - { - createButtons(); - } + bool regenerate_buttons = (mButtonType != button_type); + + mButtonType = button_type; + + if (regenerate_buttons) + { + createButtons(); + } } void LLToolBar::resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth) { - // make buttons in current row all same girth - for (LLToolBarButton* button : buttons_in_row) - { - if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) - { - button->reshape(button->mWidthRange.clamp(button->getRect().getWidth()), max_row_girth); - } - else // VERTICAL - { - button->reshape(max_row_girth, button->getRect().getHeight()); - } - } + // make buttons in current row all same girth + for (LLToolBarButton* button : buttons_in_row) + { + if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) + { + button->reshape(button->mWidthRange.clamp(button->getRect().getWidth()), max_row_girth); + } + else // VERTICAL + { + button->reshape(max_row_girth, button->getRect().getHeight()); + } + } } -// Returns the position of the coordinates as a rank in the button list. +// Returns the position of the coordinates as a rank in the button list. // The rank is the position a tool dropped in (x,y) would assume in the button list. // The returned value is between 0 and mButtons.size(), 0 being the first element to the left // (or top) and mButtons.size() the last one to the right (or bottom). // Various drag data are stored in the toolbar object though are not exposed outside (and shouldn't). int LLToolBar::getRankFromPosition(S32 x, S32 y) { - if (mButtons.empty()) - { - return RANK_NONE; - } - - int rank = 0; - - // Convert the toolbar coord into button panel coords - LLView::EOrientation orientation = getOrientation(mSideType); - S32 button_panel_x = 0; - S32 button_panel_y = 0; - localPointToOtherView(x, y, &button_panel_x, &button_panel_y, mButtonPanel); - S32 dx = x - button_panel_x; - S32 dy = y - button_panel_y; - - // Simply compare the passed coord with the buttons outbound box + padding - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); - LLRect button_rect; - while (it_button != end_button) - { - button_rect = (*it_button)->getRect(); - S32 point_x = button_rect.mRight + mPadRight; - S32 point_y = button_rect.mBottom - mPadBottom; - - if ((button_panel_x < point_x) && (button_panel_y > point_y)) - { - break; - } - rank++; - ++it_button; - } - - // Update the passed coordinates to the hit button relevant corner - // (different depending on toolbar orientation) - if (rank < mButtons.size()) - { - if (orientation == LLLayoutStack::HORIZONTAL) - { - // Horizontal - S32 mid_point = (button_rect.mRight + button_rect.mLeft) / 2; - if (button_panel_x < mid_point) - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mTop + mPadTop; - } - else - { - rank++; - mDragx = button_rect.mRight + mPadRight - 1; - mDragy = button_rect.mTop + mPadTop; - } - } - else - { - // Vertical - S32 mid_point = (button_rect.mTop + button_rect.mBottom) / 2; - if (button_panel_y > mid_point) - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mTop + mPadTop; - } - else - { - rank++; - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mBottom - mPadBottom + 1; - } - } - } - else - { - // We hit passed the end of the list so put the insertion point at the end - if (orientation == LLLayoutStack::HORIZONTAL) - { - mDragx = button_rect.mRight + mPadRight; - mDragy = button_rect.mTop + mPadTop; - } - else - { - mDragx = button_rect.mLeft - mPadLeft; - mDragy = button_rect.mBottom - mPadBottom; - } - } - - // Update the "girth" of the caret, i.e. the width or height (depending of orientation) - if (orientation == LLLayoutStack::HORIZONTAL) - { - mDragGirth = button_rect.getHeight() + mPadBottom + mPadTop; - } - else - { - mDragGirth = button_rect.getWidth() + mPadLeft + mPadRight; - } - - // The delta account for the coord model change (i.e. convert back to toolbar coord) - mDragx += dx; - mDragy += dy; - - return rank; + if (mButtons.empty()) + { + return RANK_NONE; + } + + int rank = 0; + + // Convert the toolbar coord into button panel coords + LLView::EOrientation orientation = getOrientation(mSideType); + S32 button_panel_x = 0; + S32 button_panel_y = 0; + localPointToOtherView(x, y, &button_panel_x, &button_panel_y, mButtonPanel); + S32 dx = x - button_panel_x; + S32 dy = y - button_panel_y; + + // Simply compare the passed coord with the buttons outbound box + padding + std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); + std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); + LLRect button_rect; + while (it_button != end_button) + { + button_rect = (*it_button)->getRect(); + S32 point_x = button_rect.mRight + mPadRight; + S32 point_y = button_rect.mBottom - mPadBottom; + + if ((button_panel_x < point_x) && (button_panel_y > point_y)) + { + break; + } + rank++; + ++it_button; + } + + // Update the passed coordinates to the hit button relevant corner + // (different depending on toolbar orientation) + if (rank < mButtons.size()) + { + if (orientation == LLLayoutStack::HORIZONTAL) + { + // Horizontal + S32 mid_point = (button_rect.mRight + button_rect.mLeft) / 2; + if (button_panel_x < mid_point) + { + mDragx = button_rect.mLeft - mPadLeft; + mDragy = button_rect.mTop + mPadTop; + } + else + { + rank++; + mDragx = button_rect.mRight + mPadRight - 1; + mDragy = button_rect.mTop + mPadTop; + } + } + else + { + // Vertical + S32 mid_point = (button_rect.mTop + button_rect.mBottom) / 2; + if (button_panel_y > mid_point) + { + mDragx = button_rect.mLeft - mPadLeft; + mDragy = button_rect.mTop + mPadTop; + } + else + { + rank++; + mDragx = button_rect.mLeft - mPadLeft; + mDragy = button_rect.mBottom - mPadBottom + 1; + } + } + } + else + { + // We hit passed the end of the list so put the insertion point at the end + if (orientation == LLLayoutStack::HORIZONTAL) + { + mDragx = button_rect.mRight + mPadRight; + mDragy = button_rect.mTop + mPadTop; + } + else + { + mDragx = button_rect.mLeft - mPadLeft; + mDragy = button_rect.mBottom - mPadBottom; + } + } + + // Update the "girth" of the caret, i.e. the width or height (depending of orientation) + if (orientation == LLLayoutStack::HORIZONTAL) + { + mDragGirth = button_rect.getHeight() + mPadBottom + mPadTop; + } + else + { + mDragGirth = button_rect.getWidth() + mPadLeft + mPadRight; + } + + // The delta account for the coord model change (i.e. convert back to toolbar coord) + mDragx += dx; + mDragy += dy; + + return rank; } int LLToolBar::getRankFromPosition(const LLCommandId& id) { - if (!hasCommand(id)) - { - return RANK_NONE; - } - int rank = 0; - std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); - std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); - while (it_button != end_button) - { - if ((*it_button)->mId == id) - { - break; - } - rank++; - ++it_button; - } - return rank; + if (!hasCommand(id)) + { + return RANK_NONE; + } + int rank = 0; + std::list<LLToolBarButton*>::iterator it_button = mButtons.begin(); + std::list<LLToolBarButton*>::iterator end_button = mButtons.end(); + while (it_button != end_button) + { + if ((*it_button)->mId == id) + { + break; + } + rank++; + ++it_button; + } + return rank; } void LLToolBar::updateLayoutAsNeeded() { - if (!mNeedsLayout) return; - - LLView::EOrientation orientation = getOrientation(mSideType); - - // our terminology for orientation-agnostic layout is such that - // length refers to a distance in the direction we stack the buttons - // and girth refers to a distance in the direction buttons wrap - S32 max_row_girth = 0; - S32 max_row_length = 0; - - S32 max_length; - S32 cur_start; - S32 cur_row ; - S32 row_pad_start; - S32 row_pad_end; - S32 girth_pad_end; - S32 row_running_length; - - if (orientation == LLLayoutStack::HORIZONTAL) - { - max_length = getRect().getWidth() - mPadLeft - mPadRight; - row_pad_start = mPadLeft; - row_pad_end = mPadRight; - cur_row = mPadTop; - girth_pad_end = mPadBottom; - } - else // VERTICAL - { - max_length = getRect().getHeight() - mPadTop - mPadBottom; - row_pad_start = mPadTop; - row_pad_end = mPadBottom; - cur_row = mPadLeft; - girth_pad_end = mPadRight; - } - - row_running_length = row_pad_start; - cur_start = row_pad_start; - - - LLRect panel_rect = mButtonPanel->getLocalRect(); - - std::vector<LLToolBarButton*> buttons_in_row; - - for (LLToolBarButton* button : mButtons) - { - button->reshape(button->mWidthRange.getMin(), button->mDesiredHeight); - button->autoResize(); - - S32 button_clamped_width = button->mWidthRange.clamp(button->getRect().getWidth()); - S32 button_length = (orientation == LLLayoutStack::HORIZONTAL) - ? button_clamped_width - : button->getRect().getHeight(); - S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL) - ? button->getRect().getHeight() - : button_clamped_width; - - // wrap if needed - if (mWrap - && row_running_length + button_length > max_length // out of room... - && cur_start != row_pad_start) // ...and not first button in row - { - if (orientation == LLLayoutStack::VERTICAL) - { // row girth (width in this case) is clamped to allowable button widths - max_row_girth = button->mWidthRange.clamp(max_row_girth); - } - - // make buttons in current row all same girth - resizeButtonsInRow(buttons_in_row, max_row_girth); - buttons_in_row.clear(); - - max_row_length = llmax(max_row_length, row_running_length); - row_running_length = row_pad_start; - cur_start = row_pad_start; - cur_row += max_row_girth + mPadBetween; - max_row_girth = 0; - } - - LLRect button_rect; - if (orientation == LLLayoutStack::HORIZONTAL) - { - button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight()); - } - else // VERTICAL - { - button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight()); - } - button->setShape(button_rect); - - buttons_in_row.push_back(button); - - row_running_length += button_length + mPadBetween; - cur_start = row_running_length; - max_row_girth = llmax(button_girth, max_row_girth); - } - - // final resizing in "girth" direction - S32 total_girth = cur_row // current row position... - + max_row_girth // ...incremented by size of final row... - + girth_pad_end; // ...plus padding reserved on end - total_girth = llmax(total_girth,mMinGirth); - - max_row_length = llmax(max_row_length, row_running_length - mPadBetween + row_pad_end); - - resizeButtonsInRow(buttons_in_row, max_row_girth); - - // grow and optionally shift toolbar to accommodate buttons - if (orientation == LLLayoutStack::HORIZONTAL) - { - if (mSideType == SIDE_TOP) - { // shift down to maintain top edge - translate(0, getRect().getHeight() - total_girth); - } - - reshape(getRect().getWidth(), total_girth); - mButtonPanel->reshape(max_row_length, total_girth); - } - else // VERTICAL - { - if (mSideType == SIDE_RIGHT) - { // shift left to maintain right edge - translate(getRect().getWidth() - total_girth, 0); - } - - reshape(total_girth, getRect().getHeight()); - mButtonPanel->reshape(total_girth, max_row_length); - } - - // make parent fit button panel - mButtonPanel->getParent()->setShape(mButtonPanel->getLocalRect()); - - // re-center toolbar buttons - mCenteringStack->updateLayout(); - - if (!mButtons.empty()) - { - mButtonPanel->setVisible(TRUE); - mButtonPanel->setMouseOpaque(TRUE); - } - - // don't clear flag until after we've resized ourselves, to avoid laying out every frame - mNeedsLayout = false; + if (!mNeedsLayout) return; + + LLView::EOrientation orientation = getOrientation(mSideType); + + // our terminology for orientation-agnostic layout is such that + // length refers to a distance in the direction we stack the buttons + // and girth refers to a distance in the direction buttons wrap + S32 max_row_girth = 0; + S32 max_row_length = 0; + + S32 max_length; + S32 cur_start; + S32 cur_row ; + S32 row_pad_start; + S32 row_pad_end; + S32 girth_pad_end; + S32 row_running_length; + + if (orientation == LLLayoutStack::HORIZONTAL) + { + max_length = getRect().getWidth() - mPadLeft - mPadRight; + row_pad_start = mPadLeft; + row_pad_end = mPadRight; + cur_row = mPadTop; + girth_pad_end = mPadBottom; + } + else // VERTICAL + { + max_length = getRect().getHeight() - mPadTop - mPadBottom; + row_pad_start = mPadTop; + row_pad_end = mPadBottom; + cur_row = mPadLeft; + girth_pad_end = mPadRight; + } + + row_running_length = row_pad_start; + cur_start = row_pad_start; + + + LLRect panel_rect = mButtonPanel->getLocalRect(); + + std::vector<LLToolBarButton*> buttons_in_row; + + for (LLToolBarButton* button : mButtons) + { + button->reshape(button->mWidthRange.getMin(), button->mDesiredHeight); + button->autoResize(); + + S32 button_clamped_width = button->mWidthRange.clamp(button->getRect().getWidth()); + S32 button_length = (orientation == LLLayoutStack::HORIZONTAL) + ? button_clamped_width + : button->getRect().getHeight(); + S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL) + ? button->getRect().getHeight() + : button_clamped_width; + + // wrap if needed + if (mWrap + && row_running_length + button_length > max_length // out of room... + && cur_start != row_pad_start) // ...and not first button in row + { + if (orientation == LLLayoutStack::VERTICAL) + { // row girth (width in this case) is clamped to allowable button widths + max_row_girth = button->mWidthRange.clamp(max_row_girth); + } + + // make buttons in current row all same girth + resizeButtonsInRow(buttons_in_row, max_row_girth); + buttons_in_row.clear(); + + max_row_length = llmax(max_row_length, row_running_length); + row_running_length = row_pad_start; + cur_start = row_pad_start; + cur_row += max_row_girth + mPadBetween; + max_row_girth = 0; + } + + LLRect button_rect; + if (orientation == LLLayoutStack::HORIZONTAL) + { + button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight()); + } + else // VERTICAL + { + button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight()); + } + button->setShape(button_rect); + + buttons_in_row.push_back(button); + + row_running_length += button_length + mPadBetween; + cur_start = row_running_length; + max_row_girth = llmax(button_girth, max_row_girth); + } + + // final resizing in "girth" direction + S32 total_girth = cur_row // current row position... + + max_row_girth // ...incremented by size of final row... + + girth_pad_end; // ...plus padding reserved on end + total_girth = llmax(total_girth,mMinGirth); + + max_row_length = llmax(max_row_length, row_running_length - mPadBetween + row_pad_end); + + resizeButtonsInRow(buttons_in_row, max_row_girth); + + // grow and optionally shift toolbar to accommodate buttons + if (orientation == LLLayoutStack::HORIZONTAL) + { + if (mSideType == SIDE_TOP) + { // shift down to maintain top edge + translate(0, getRect().getHeight() - total_girth); + } + + reshape(getRect().getWidth(), total_girth); + mButtonPanel->reshape(max_row_length, total_girth); + } + else // VERTICAL + { + if (mSideType == SIDE_RIGHT) + { // shift left to maintain right edge + translate(getRect().getWidth() - total_girth, 0); + } + + reshape(total_girth, getRect().getHeight()); + mButtonPanel->reshape(total_girth, max_row_length); + } + + // make parent fit button panel + mButtonPanel->getParent()->setShape(mButtonPanel->getLocalRect()); + + // re-center toolbar buttons + mCenteringStack->updateLayout(); + + if (!mButtons.empty()) + { + mButtonPanel->setVisible(TRUE); + mButtonPanel->setMouseOpaque(TRUE); + } + + // don't clear flag until after we've resized ourselves, to avoid laying out every frame + mNeedsLayout = false; } void LLToolBar::draw() { - if (mButtons.empty()) - { - mButtonPanel->setVisible(FALSE); - mButtonPanel->setMouseOpaque(FALSE); - } - else - { - mButtonPanel->setVisible(TRUE); - mButtonPanel->setMouseOpaque(TRUE); - } - - // Update enable/disable state and highlight state for editable toolbars - if (!mReadOnly) - { - for (toolbar_button_list::iterator btn_it = mButtons.begin(); btn_it != mButtons.end(); ++btn_it) - { - LLToolBarButton* btn = *btn_it; - LLCommand* command = LLCommandManager::instance().getCommand(btn->mId); - - if (command && btn->mIsEnabledSignal) - { - const bool button_command_enabled = (*btn->mIsEnabledSignal)(btn, command->isEnabledParameters()); - btn->setEnabled(button_command_enabled); - } - - if (command && btn->mIsRunningSignal) - { - const bool button_command_running = (*btn->mIsRunningSignal)(btn, command->isRunningParameters()); - btn->setToggleState(button_command_running); - } - } - } - - updateLayoutAsNeeded(); - // rect may have shifted during layout - LLUI::popMatrix(); - LLUI::pushMatrix(); - LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); - - // Position the caret - if (!mCaretIcon) - { - mCaretIcon = getChild<LLIconCtrl>("caret"); - } - - LLIconCtrl* caret = mCaretIcon; - caret->setVisible(FALSE); - if (mDragAndDropTarget && !mButtonCommands.empty()) - { - LLRect caret_rect = caret->getRect(); - if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) - { - caret->setRect(LLRect(mDragx-caret_rect.getWidth()/2+1, - mDragy, - mDragx+caret_rect.getWidth()/2+1, - mDragy-mDragGirth)); - } - else - { - caret->setRect(LLRect(mDragx, - mDragy+caret_rect.getHeight()/2, - mDragx+mDragGirth, - mDragy-caret_rect.getHeight()/2)); - } - caret->setVisible(TRUE); - } - - LLUICtrl::draw(); - caret->setVisible(FALSE); - mDragAndDropTarget = false; + if (mButtons.empty()) + { + mButtonPanel->setVisible(FALSE); + mButtonPanel->setMouseOpaque(FALSE); + } + else + { + mButtonPanel->setVisible(TRUE); + mButtonPanel->setMouseOpaque(TRUE); + } + + // Update enable/disable state and highlight state for editable toolbars + if (!mReadOnly) + { + for (toolbar_button_list::iterator btn_it = mButtons.begin(); btn_it != mButtons.end(); ++btn_it) + { + LLToolBarButton* btn = *btn_it; + LLCommand* command = LLCommandManager::instance().getCommand(btn->mId); + + if (command && btn->mIsEnabledSignal) + { + const bool button_command_enabled = (*btn->mIsEnabledSignal)(btn, command->isEnabledParameters()); + btn->setEnabled(button_command_enabled); + } + + if (command && btn->mIsRunningSignal) + { + const bool button_command_running = (*btn->mIsRunningSignal)(btn, command->isRunningParameters()); + btn->setToggleState(button_command_running); + } + } + } + + updateLayoutAsNeeded(); + // rect may have shifted during layout + LLUI::popMatrix(); + LLUI::pushMatrix(); + LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); + + // Position the caret + if (!mCaretIcon) + { + mCaretIcon = getChild<LLIconCtrl>("caret"); + } + + LLIconCtrl* caret = mCaretIcon; + caret->setVisible(FALSE); + if (mDragAndDropTarget && !mButtonCommands.empty()) + { + LLRect caret_rect = caret->getRect(); + if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) + { + caret->setRect(LLRect(mDragx-caret_rect.getWidth()/2+1, + mDragy, + mDragx+caret_rect.getWidth()/2+1, + mDragy-mDragGirth)); + } + else + { + caret->setRect(LLRect(mDragx, + mDragy+caret_rect.getHeight()/2, + mDragx+mDragGirth, + mDragy-caret_rect.getHeight()/2)); + } + caret->setVisible(TRUE); + } + + LLUICtrl::draw(); + caret->setVisible(FALSE); + mDragAndDropTarget = false; } void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLUICtrl::reshape(width, height, called_from_parent); - mNeedsLayout = true; + LLUICtrl::reshape(width, height, called_from_parent); + mNeedsLayout = true; } void LLToolBar::createButtons() { - std::set<LLUUID> set_flashing; + std::set<LLUUID> set_flashing; - for (LLToolBarButton* button : mButtons) - { + for (LLToolBarButton* button : mButtons) + { if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress()) { - set_flashing.insert(button->getCommandId().uuid()); + set_flashing.insert(button->getCommandId().uuid()); + } + + if (mButtonRemoveSignal) + { + (*mButtonRemoveSignal)(button); } - if (mButtonRemoveSignal) - { - (*mButtonRemoveSignal)(button); - } - - delete button; - } - mButtons.clear(); - mButtonMap.clear(); - mRightMouseTargetButton = NULL; - - for (const LLCommandId& command_id : mButtonCommands) - { - LLToolBarButton* button = createButton(command_id); - mButtons.push_back(button); - mButtonPanel->addChild(button); - mButtonMap.insert(std::make_pair(command_id.uuid(), button)); - - if (mButtonAddSignal) - { - (*mButtonAddSignal)(button); - } - - if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end()) - { - button->setFlashing(true); - } - } - mNeedsLayout = true; + delete button; + } + mButtons.clear(); + mButtonMap.clear(); + mRightMouseTargetButton = NULL; + + for (const LLCommandId& command_id : mButtonCommands) + { + LLToolBarButton* button = createButton(command_id); + mButtons.push_back(button); + mButtonPanel->addChild(button); + mButtonMap.insert(std::make_pair(command_id.uuid(), button)); + + if (mButtonAddSignal) + { + (*mButtonAddSignal)(button); + } + + if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end()) + { + button->setFlashing(true); + } + } + mNeedsLayout = true; } void LLToolBarButton::callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param ) { - LLCommand* command = LLCommandManager::instance().getCommand(mId); + LLCommand* command = LLCommandManager::instance().getCommand(mId); - if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) - { - commit(ctrl, param); - } + if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) + { + commit(ctrl, param); + } } LLToolBarButton* LLToolBar::createButton(const LLCommandId& id) { - LLCommand* commandp = LLCommandManager::instance().getCommand(id); - if (!commandp) return NULL; - - LLToolBarButton::Params button_p; - button_p.name = commandp->name(); - button_p.label = LLTrans::getString(commandp->labelRef()); - button_p.tool_tip = LLTrans::getString(commandp->tooltipRef()); - button_p.image_overlay = LLUI::getUIImage(commandp->icon()); - button_p.button_flash_enable = commandp->isFlashingAllowed(); - button_p.overwriteFrom(mButtonParams[mButtonType]); - LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p); - - if (!mReadOnly) - { - enable_callback_t isEnabledCB; - - const std::string& isEnabledFunction = commandp->isEnabledFunctionName(); - if (isEnabledFunction.length() > 0) - { - LLUICtrl::EnableCallbackParam isEnabledParam; - isEnabledParam.function_name = isEnabledFunction; - isEnabledParam.parameter = commandp->isEnabledParameters(); - isEnabledCB = initEnableCallback(isEnabledParam); - - if (NULL == button->mIsEnabledSignal) - { - button->mIsEnabledSignal = new enable_signal_t(); - } - - button->mIsEnabledSignal->connect(isEnabledCB); - } - - LLUICtrl::CommitCallbackParam executeParam; - executeParam.function_name = commandp->executeFunctionName(); - executeParam.parameter = commandp->executeParameters(); - - // If we have a "stop" function then we map the command to mouse down / mouse up otherwise commit - const std::string& executeStopFunction = commandp->executeStopFunctionName(); - if (executeStopFunction.length() > 0) - { - LLUICtrl::CommitCallbackParam executeStopParam; - executeStopParam.function_name = executeStopFunction; - executeStopParam.parameter = commandp->executeStopParameters(); - LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam); - button->setFunctionName(commandp->executeFunctionName()); - LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL; - LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam); - - button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2)); - button->setMouseUpCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, stop_func, _1, _2)); - } - else - { - button->setFunctionName(commandp->executeFunctionName()); - LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL; - button->setCommitCallback(executeParam); - } - - // Set up "is running" query callback - const std::string& isRunningFunction = commandp->isRunningFunctionName(); - if (isRunningFunction.length() > 0) - { - LLUICtrl::EnableCallbackParam isRunningParam; - isRunningParam.function_name = isRunningFunction; - isRunningParam.parameter = commandp->isRunningParameters(); - enable_signal_t::slot_type isRunningCB = initEnableCallback(isRunningParam); - - if (NULL == button->mIsRunningSignal) - { - button->mIsRunningSignal = new enable_signal_t(); - } - - button->mIsRunningSignal->connect(isRunningCB); - } - } - - // Drag and drop behavior must work also if provided in the Toybox and, potentially, any read-only toolbar - button->setStartDragCallback(mStartDragItemCallback); - button->setHandleDragCallback(mHandleDragItemCallback); - - button->setCommandId(id); - - return button; + LLCommand* commandp = LLCommandManager::instance().getCommand(id); + if (!commandp) return NULL; + + LLToolBarButton::Params button_p; + button_p.name = commandp->name(); + button_p.label = LLTrans::getString(commandp->labelRef()); + button_p.tool_tip = LLTrans::getString(commandp->tooltipRef()); + button_p.image_overlay = LLUI::getUIImage(commandp->icon()); + button_p.button_flash_enable = commandp->isFlashingAllowed(); + button_p.overwriteFrom(mButtonParams[mButtonType]); + LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p); + + if (!mReadOnly) + { + enable_callback_t isEnabledCB; + + const std::string& isEnabledFunction = commandp->isEnabledFunctionName(); + if (isEnabledFunction.length() > 0) + { + LLUICtrl::EnableCallbackParam isEnabledParam; + isEnabledParam.function_name = isEnabledFunction; + isEnabledParam.parameter = commandp->isEnabledParameters(); + isEnabledCB = initEnableCallback(isEnabledParam); + + if (NULL == button->mIsEnabledSignal) + { + button->mIsEnabledSignal = new enable_signal_t(); + } + + button->mIsEnabledSignal->connect(isEnabledCB); + } + + LLUICtrl::CommitCallbackParam executeParam; + executeParam.function_name = commandp->executeFunctionName(); + executeParam.parameter = commandp->executeParameters(); + + // If we have a "stop" function then we map the command to mouse down / mouse up otherwise commit + const std::string& executeStopFunction = commandp->executeStopFunctionName(); + if (executeStopFunction.length() > 0) + { + LLUICtrl::CommitCallbackParam executeStopParam; + executeStopParam.function_name = executeStopFunction; + executeStopParam.parameter = commandp->executeStopParameters(); + LLUICtrl::commit_callback_t execute_func = initCommitCallback(executeParam); + button->setFunctionName(commandp->executeFunctionName()); + LL_DEBUGS("UIUsage") << "button function name a -> " << commandp->executeFunctionName() << LL_ENDL; + LLUICtrl::commit_callback_t stop_func = initCommitCallback(executeStopParam); + + button->setMouseDownCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, execute_func, _1, _2)); + button->setMouseUpCallback(boost::bind(&LLToolBarButton::callIfEnabled, button, stop_func, _1, _2)); + } + else + { + button->setFunctionName(commandp->executeFunctionName()); + LL_DEBUGS("UIUsage") << "button function name b -> " << commandp->executeFunctionName() << LL_ENDL; + button->setCommitCallback(executeParam); + } + + // Set up "is running" query callback + const std::string& isRunningFunction = commandp->isRunningFunctionName(); + if (isRunningFunction.length() > 0) + { + LLUICtrl::EnableCallbackParam isRunningParam; + isRunningParam.function_name = isRunningFunction; + isRunningParam.parameter = commandp->isRunningParameters(); + enable_signal_t::slot_type isRunningCB = initEnableCallback(isRunningParam); + + if (NULL == button->mIsRunningSignal) + { + button->mIsRunningSignal = new enable_signal_t(); + } + + button->mIsRunningSignal->connect(isRunningCB); + } + } + + // Drag and drop behavior must work also if provided in the Toybox and, potentially, any read-only toolbar + button->setStartDragCallback(mStartDragItemCallback); + button->setHandleDragCallback(mHandleDragItemCallback); + + button->setCommandId(id); + + return button; } boost::signals2::connection connectSignal(LLToolBar::button_signal_t*& signal, const LLToolBar::button_signal_t::slot_type& cb) { - if (!signal) - { - signal = new LLToolBar::button_signal_t(); - } + if (!signal) + { + signal = new LLToolBar::button_signal_t(); + } - return signal->connect(cb); + return signal->connect(cb); } boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb) { - return connectSignal(mButtonAddSignal, cb); + return connectSignal(mButtonAddSignal, cb); } boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb) { - return connectSignal(mButtonEnterSignal, cb); + return connectSignal(mButtonEnterSignal, cb); } boost::signals2::connection LLToolBar::setButtonLeaveCallback(const button_signal_t::slot_type& cb) { - return connectSignal(mButtonLeaveSignal, cb); + return connectSignal(mButtonLeaveSignal, cb); } boost::signals2::connection LLToolBar::setButtonRemoveCallback(const button_signal_t::slot_type& cb) { - return connectSignal(mButtonRemoveSignal, cb); + return connectSignal(mButtonRemoveSignal, cb); } BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - // If we have a drop callback, that means that we can handle the drop - BOOL handled = (mHandleDropCallback ? TRUE : FALSE); - - // if drop is set, it's time to call the callback to get the operation done - if (handled && drop) - { - handled = mHandleDropCallback(cargo_data, x, y ,this); - } - - // We accept only single tool drop on toolbars - *accept = (handled ? ACCEPT_YES_SINGLE : ACCEPT_NO); - - // We'll use that flag to change the visual aspect of the toolbar target on draw() - mDragAndDropTarget = false; - - // Convert drag position into insert position and rank - if (!isReadOnly() && handled && !drop) - { - if (cargo_type == DAD_WIDGET) - { - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - LLCommandId dragged_command(inv_item->getUUID()); - int orig_rank = getRankFromPosition(dragged_command); - mDragRank = getRankFromPosition(x, y); - // Don't DaD if we're dragging a command on itself - mDragAndDropTarget = ((orig_rank != RANK_NONE) && ((mDragRank == orig_rank) || ((mDragRank-1) == orig_rank)) ? false : true); - //LL_INFOS() << "Merov debug : DaD, rank = " << mDragRank << ", dragged uui = " << inv_item->getUUID() << LL_ENDL; - /* Do the following if you want to animate the button itself - LLCommandId dragged_command(inv_item->getUUID()); - removeCommand(dragged_command); - addCommand(dragged_command,rank); - */ - } - else - { - handled = FALSE; - } - } - - return handled; + // If we have a drop callback, that means that we can handle the drop + BOOL handled = (mHandleDropCallback ? TRUE : FALSE); + + // if drop is set, it's time to call the callback to get the operation done + if (handled && drop) + { + handled = mHandleDropCallback(cargo_data, x, y ,this); + } + + // We accept only single tool drop on toolbars + *accept = (handled ? ACCEPT_YES_SINGLE : ACCEPT_NO); + + // We'll use that flag to change the visual aspect of the toolbar target on draw() + mDragAndDropTarget = false; + + // Convert drag position into insert position and rank + if (!isReadOnly() && handled && !drop) + { + if (cargo_type == DAD_WIDGET) + { + LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; + LLCommandId dragged_command(inv_item->getUUID()); + int orig_rank = getRankFromPosition(dragged_command); + mDragRank = getRankFromPosition(x, y); + // Don't DaD if we're dragging a command on itself + mDragAndDropTarget = ((orig_rank != RANK_NONE) && ((mDragRank == orig_rank) || ((mDragRank-1) == orig_rank)) ? false : true); + //LL_INFOS() << "Merov debug : DaD, rank = " << mDragRank << ", dragged uui = " << inv_item->getUUID() << LL_ENDL; + /* Do the following if you want to animate the button itself + LLCommandId dragged_command(inv_item->getUUID()); + removeCommand(dragged_command); + addCommand(dragged_command,rank); + */ + } + else + { + handled = FALSE; + } + } + + return handled; } -LLToolBarButton::LLToolBarButton(const Params& p) -: LLButton(p), - mMouseDownX(0), - mMouseDownY(0), - mWidthRange(p.button_width), - mDesiredHeight(p.desired_height), - mId(""), - mIsEnabledSignal(NULL), - mIsRunningSignal(NULL), - mIsStartingSignal(NULL), - mIsDragged(false), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), - mOriginalImageSelected(p.image_selected), - mOriginalImageUnselected(p.image_unselected), - mOriginalImagePressed(p.image_pressed), - mOriginalImagePressedSelected(p.image_pressed_selected), - mOriginalLabelColor(p.label_color), - mOriginalLabelColorSelected(p.label_color_selected), - mOriginalImageOverlayColor(p.image_overlay_color), - mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color) +LLToolBarButton::LLToolBarButton(const Params& p) +: LLButton(p), + mMouseDownX(0), + mMouseDownY(0), + mWidthRange(p.button_width), + mDesiredHeight(p.desired_height), + mId(""), + mIsEnabledSignal(NULL), + mIsRunningSignal(NULL), + mIsStartingSignal(NULL), + mIsDragged(false), + mStartDragItemCallback(NULL), + mHandleDragItemCallback(NULL), + mOriginalImageSelected(p.image_selected), + mOriginalImageUnselected(p.image_unselected), + mOriginalImagePressed(p.image_pressed), + mOriginalImagePressedSelected(p.image_pressed_selected), + mOriginalLabelColor(p.label_color), + mOriginalLabelColorSelected(p.label_color_selected), + mOriginalImageOverlayColor(p.image_overlay_color), + mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color) { } LLToolBarButton::~LLToolBarButton() { - delete mIsEnabledSignal; - delete mIsRunningSignal; - delete mIsStartingSignal; + delete mIsEnabledSignal; + delete mIsRunningSignal; + delete mIsStartingSignal; } BOOL LLToolBarButton::handleMouseDown(S32 x, S32 y, MASK mask) { - mMouseDownX = x; - mMouseDownY = y; - return LLButton::handleMouseDown(x, y, mask); + mMouseDownX = x; + mMouseDownY = y; + return LLButton::handleMouseDown(x, y, mask); } BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); - static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3); - if (mouse_distance_squared > drag_threshold * drag_threshold - && hasMouseCapture() && - mStartDragItemCallback && mHandleDragItemCallback) - { - if (!mIsDragged) - { - mStartDragItemCallback(x, y, this); - mIsDragged = true; - handled = TRUE; - } - else - { - handled = mHandleDragItemCallback(x, y, mId.uuid(), LLAssetType::AT_WIDGET); - } - } - else - { - handled = LLButton::handleHover(x, y, mask); - } - - return handled; + BOOL handled = FALSE; + + S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); + if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD + && hasMouseCapture() && + mStartDragItemCallback && mHandleDragItemCallback) + { + if (!mIsDragged) + { + mStartDragItemCallback(x, y, this); + mIsDragged = true; + handled = TRUE; + } + else + { + handled = mHandleDragItemCallback(x, y, mId.uuid(), LLAssetType::AT_WIDGET); + } + } + else + { + handled = LLButton::handleHover(x, y, mask); + } + + return handled; } void LLToolBarButton::onMouseEnter(S32 x, S32 y, MASK mask) { - LLUICtrl::onMouseEnter(x, y, mask); - - // Always highlight toolbar buttons, even if they are disabled - if (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this) - { - mNeedsHighlight = TRUE; - } - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonEnterSignal) - { - (*(parent_toolbar->mButtonEnterSignal))(this); - } + LLUICtrl::onMouseEnter(x, y, mask); + + // Always highlight toolbar buttons, even if they are disabled + if (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this) + { + mNeedsHighlight = TRUE; + } + + LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); + if (parent_toolbar && parent_toolbar->mButtonEnterSignal) + { + (*(parent_toolbar->mButtonEnterSignal))(this); + } } void LLToolBarButton::onMouseLeave(S32 x, S32 y, MASK mask) { - LLButton::onMouseLeave(x, y, mask); - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonLeaveSignal) - { - (*(parent_toolbar->mButtonLeaveSignal))(this); - } + LLButton::onMouseLeave(x, y, mask); + + LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); + if (parent_toolbar && parent_toolbar->mButtonLeaveSignal) + { + (*(parent_toolbar->mButtonLeaveSignal))(this); + } } void LLToolBarButton::onMouseCaptureLost() { - mIsDragged = false; + mIsDragged = false; } void LLToolBarButton::onCommit() { - LLCommand* command = LLCommandManager::instance().getCommand(mId); + LLCommand* command = LLCommandManager::instance().getCommand(mId); - if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) - { - LLButton::onCommit(); - } + if (!mIsEnabledSignal || (*mIsEnabledSignal)(this, command->isEnabledParameters())) + { + LLButton::onCommit(); + } } void LLToolBarButton::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLButton::reshape(mWidthRange.clamp(width), height, called_from_parent); + LLButton::reshape(mWidthRange.clamp(width), height, called_from_parent); } void LLToolBarButton::setEnabled(BOOL enabled) { - if (enabled) - { - mImageSelected = mOriginalImageSelected; - mImageUnselected = mOriginalImageUnselected; - mImagePressed = mOriginalImagePressed; - mImagePressedSelected = mOriginalImagePressedSelected; - mUnselectedLabelColor = mOriginalLabelColor; - mSelectedLabelColor = mOriginalLabelColorSelected; - mImageOverlayColor = mOriginalImageOverlayColor; - mImageOverlaySelectedColor = mOriginalImageOverlaySelectedColor; - } - else - { - mImageSelected = mImageDisabledSelected; - mImageUnselected = mImageDisabled; - mImagePressed = mImageDisabled; - mImagePressedSelected = mImageDisabledSelected; - mUnselectedLabelColor = mDisabledLabelColor; - mSelectedLabelColor = mDisabledSelectedLabelColor; - mImageOverlayColor = mImageOverlayDisabledColor; - mImageOverlaySelectedColor = mImageOverlayDisabledColor; - } + if (enabled) + { + mImageSelected = mOriginalImageSelected; + mImageUnselected = mOriginalImageUnselected; + mImagePressed = mOriginalImagePressed; + mImagePressedSelected = mOriginalImagePressedSelected; + mUnselectedLabelColor = mOriginalLabelColor; + mSelectedLabelColor = mOriginalLabelColorSelected; + mImageOverlayColor = mOriginalImageOverlayColor; + mImageOverlaySelectedColor = mOriginalImageOverlaySelectedColor; + } + else + { + mImageSelected = mImageDisabledSelected; + mImageUnselected = mImageDisabled; + mImagePressed = mImageDisabled; + mImagePressedSelected = mImageDisabledSelected; + mUnselectedLabelColor = mDisabledLabelColor; + mSelectedLabelColor = mDisabledSelectedLabelColor; + mImageOverlayColor = mImageOverlayDisabledColor; + mImageOverlaySelectedColor = mImageOverlayDisabledColor; + } } -const std::string LLToolBarButton::getToolTip() const -{ - std::string tooltip; - - if (labelIsTruncated() || getCurrentLabel().empty()) - { - tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip(); - } - else - { - tooltip = LLView::getToolTip(); - } - - LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); - if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0) - { - tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")"; - } - - return tooltip; +const std::string LLToolBarButton::getToolTip() const +{ + std::string tooltip; + + if (labelIsTruncated() || getCurrentLabel().empty()) + { + tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip(); + } + else + { + tooltip = LLView::getToolTip(); + } + + LLToolBar* parent_toolbar = getParentByType<LLToolBar>(); + if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0) + { + tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")"; + } + + return tooltip; } void LLToolBar::LLCenterLayoutPanel::handleReshape(const LLRect& rect, bool by_user) { - LLLayoutPanel::handleReshape(rect, by_user); - - if (!mReshapeCallback.empty()) - { - LLRect r; - localRectToOtherView(mButtonPanel->getRect(), &r, gFloaterView); - r.stretch(FLOATER_MIN_VISIBLE_PIXELS); - mReshapeCallback(mLocationId, r); - } + LLLayoutPanel::handleReshape(rect, by_user); + + if (!mReshapeCallback.empty()) + { + LLRect r; + localRectToOtherView(mButtonPanel->getRect(), &r, gFloaterView); + r.stretch(FLOATER_MIN_VISIBLE_PIXELS); + mReshapeCallback(mLocationId, r); + } } diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h index 370941c787..1a9c1cdf9f 100644 --- a/indra/llui/lltoolbar.h +++ b/indra/llui/lltoolbar.h @@ -1,4 +1,4 @@ -/** +/** * @file lltoolbar.h * @author Richard Nelson * @brief User customizable toolbar class @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,286 +45,286 @@ typedef boost::function<BOOL (void* data, S32 x, S32 y, LLToolBar* toolbar)> too class LLToolBarButton : public LLButton { - friend class LLToolBar; + friend class LLToolBar; public: - struct Params : public LLInitParam::Block<Params, LLButton::Params> - { - Optional<LLUI::RangeS32::Params> button_width; - Optional<S32> desired_height; + struct Params : public LLInitParam::Block<Params, LLButton::Params> + { + Optional<LLUI::RangeS32::Params> button_width; + Optional<S32> desired_height; - Params() - : button_width("button_width"), - desired_height("desired_height", 20) - {} + Params() + : button_width("button_width"), + desired_height("desired_height", 20) + {} - }; + }; - LLToolBarButton(const Params& p); - ~LLToolBarButton(); + LLToolBarButton(const Params& p); + ~LLToolBarButton(); - BOOL handleMouseDown(S32 x, S32 y, MASK mask); - BOOL handleHover(S32 x, S32 y, MASK mask); + BOOL handleMouseDown(S32 x, S32 y, MASK mask); + BOOL handleHover(S32 x, S32 y, MASK mask); - void reshape(S32 width, S32 height, BOOL called_from_parent = true); - void setEnabled(BOOL enabled); - void setCommandId(const LLCommandId& id) { mId = id; } - LLCommandId getCommandId() { return mId; } + void reshape(S32 width, S32 height, BOOL called_from_parent = true); + void setEnabled(BOOL enabled); + void setCommandId(const LLCommandId& id) { mId = id; } + LLCommandId getCommandId() { return mId; } - void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } - void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } + void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } + void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } - void onMouseEnter(S32 x, S32 y, MASK mask); - void onMouseLeave(S32 x, S32 y, MASK mask); - void onMouseCaptureLost(); + void onMouseEnter(S32 x, S32 y, MASK mask); + void onMouseLeave(S32 x, S32 y, MASK mask); + void onMouseCaptureLost(); - void onCommit(); + void onCommit(); - virtual const std::string getToolTip() const; + virtual const std::string getToolTip() const; private: - void callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param ); - - LLCommandId mId; - S32 mMouseDownX; - S32 mMouseDownY; - LLUI::RangeS32 mWidthRange; - S32 mDesiredHeight; - bool mIsDragged; - tool_startdrag_callback_t mStartDragItemCallback; - tool_handledrag_callback_t mHandleDragItemCallback; - - enable_signal_t* mIsEnabledSignal; - enable_signal_t* mIsRunningSignal; - enable_signal_t* mIsStartingSignal; - LLPointer<LLUIImage> mOriginalImageSelected, - mOriginalImageUnselected, - mOriginalImagePressed, - mOriginalImagePressedSelected; - LLUIColor mOriginalLabelColor, - mOriginalLabelColorSelected, - mOriginalImageOverlayColor, - mOriginalImageOverlaySelectedColor; + void callIfEnabled(LLUICtrl::commit_callback_t commit, LLUICtrl* ctrl, const LLSD& param ); + + LLCommandId mId; + S32 mMouseDownX; + S32 mMouseDownY; + LLUI::RangeS32 mWidthRange; + S32 mDesiredHeight; + bool mIsDragged; + tool_startdrag_callback_t mStartDragItemCallback; + tool_handledrag_callback_t mHandleDragItemCallback; + + enable_signal_t* mIsEnabledSignal; + enable_signal_t* mIsRunningSignal; + enable_signal_t* mIsStartingSignal; + LLPointer<LLUIImage> mOriginalImageSelected, + mOriginalImageUnselected, + mOriginalImagePressed, + mOriginalImagePressedSelected; + LLUIColor mOriginalLabelColor, + mOriginalLabelColorSelected, + mOriginalImageOverlayColor, + mOriginalImageOverlaySelectedColor; }; namespace LLToolBarEnums { - enum ButtonType - { - BTNTYPE_ICONS_WITH_TEXT = 0, - BTNTYPE_ICONS_ONLY, - - BTNTYPE_COUNT - }; - - enum SideType - { - SIDE_BOTTOM, - SIDE_LEFT, - SIDE_RIGHT, - SIDE_TOP, - }; - - enum EToolBarLocation - { - TOOLBAR_NONE = 0, - TOOLBAR_LEFT, - TOOLBAR_RIGHT, - TOOLBAR_BOTTOM, - - TOOLBAR_COUNT, - - TOOLBAR_FIRST = TOOLBAR_LEFT, - TOOLBAR_LAST = TOOLBAR_BOTTOM, - }; - - LLView::EOrientation getOrientation(SideType sideType); + enum ButtonType + { + BTNTYPE_ICONS_WITH_TEXT = 0, + BTNTYPE_ICONS_ONLY, + + BTNTYPE_COUNT + }; + + enum SideType + { + SIDE_BOTTOM, + SIDE_LEFT, + SIDE_RIGHT, + SIDE_TOP, + }; + + enum EToolBarLocation + { + TOOLBAR_NONE = 0, + TOOLBAR_LEFT, + TOOLBAR_RIGHT, + TOOLBAR_BOTTOM, + + TOOLBAR_COUNT, + + TOOLBAR_FIRST = TOOLBAR_LEFT, + TOOLBAR_LAST = TOOLBAR_BOTTOM, + }; + + LLView::EOrientation getOrientation(SideType sideType); } // NOTE: This needs to occur before Param block declaration for proper compilation. namespace LLInitParam { - template<> - struct TypeValues<LLToolBarEnums::ButtonType> : public TypeValuesHelper<LLToolBarEnums::ButtonType> - { - static void declareValues(); - }; - - template<> - struct TypeValues<LLToolBarEnums::SideType> : public TypeValuesHelper<LLToolBarEnums::SideType> - { - static void declareValues(); - }; + template<> + struct TypeValues<LLToolBarEnums::ButtonType> : public TypeValuesHelper<LLToolBarEnums::ButtonType> + { + static void declareValues(); + }; + + template<> + struct TypeValues<LLToolBarEnums::SideType> : public TypeValuesHelper<LLToolBarEnums::SideType> + { + static void declareValues(); + }; } class LLToolBar -: public LLUICtrl +: public LLUICtrl { - friend class LLToolBarButton; + friend class LLToolBarButton; public: - class LLCenterLayoutPanel : public LLLayoutPanel - { - public: - typedef boost::function<void(LLToolBarEnums::EToolBarLocation tb, const LLRect& rect)> reshape_callback_t; - - virtual ~LLCenterLayoutPanel() {} - /*virtual*/ void handleReshape(const LLRect& rect, bool by_user); - - void setLocationId(LLToolBarEnums::EToolBarLocation id) { mLocationId = id; } - void setReshapeCallback(reshape_callback_t cb) { mReshapeCallback = cb; } - void setButtonPanel(LLPanel * panel) { mButtonPanel = panel; } - - protected: - friend class LLUICtrlFactory; - LLCenterLayoutPanel(const Params& params) : LLLayoutPanel(params), mButtonPanel(NULL) {} - - private: - reshape_callback_t mReshapeCallback; - LLToolBarEnums::EToolBarLocation mLocationId; - LLPanel * mButtonPanel; - }; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Mandatory<LLToolBarEnums::ButtonType> button_display_mode; - Mandatory<LLToolBarEnums::SideType> side; - - Optional<LLToolBarButton::Params> button_icon, - button_icon_and_text; - - Optional<bool> read_only, - wrap; - - Optional<S32> pad_left, - pad_top, - pad_right, - pad_bottom, - pad_between, - min_girth; - - // default command set - Multiple<LLCommandId::Params> commands; - - Optional<LLPanel::Params> button_panel; - - Params(); - }; - - // virtuals - void draw(); - void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - static const int RANK_NONE = -1; - bool addCommand(const LLCommandId& commandId, int rank = RANK_NONE); - int removeCommand(const LLCommandId& commandId); // Returns the rank the removed command was at, RANK_NONE if not found - bool hasCommand(const LLCommandId& commandId) const; // is this command bound to a button in this toolbar - bool enableCommand(const LLCommandId& commandId, bool enabled); // enable/disable button bound to the specified command, if it exists in this toolbar - bool stopCommandInProgress(const LLCommandId& commandId); // stop command if it is currently active - bool flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing = false); // flash button associated with given command, if in this toolbar - - void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } // connects drag and drop behavior to external logic - void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } - void setHandleDropCallback(tool_handledrop_callback_t cb) { mHandleDropCallback = cb; } - bool isReadOnly() const { return mReadOnly; } - LLCenterLayoutPanel * getCenterLayoutPanel() const { return mCenterPanel; } - - LLToolBarButton* createButton(const LLCommandId& id); - - typedef boost::signals2::signal<void (LLView* button)> button_signal_t; - boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb); - boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb); - boost::signals2::connection setButtonLeaveCallback(const button_signal_t::slot_type& cb); - boost::signals2::connection setButtonRemoveCallback(const button_signal_t::slot_type& cb); - - // append the specified string to end of tooltip - void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; } - - LLToolBarEnums::SideType getSideType() const { return mSideType; } - bool hasButtons() const { return !mButtons.empty(); } - bool isModified() const { return mModified; } - - int getRankFromPosition(S32 x, S32 y); - int getRankFromPosition(const LLCommandId& id); - - // Methods used in loading and saving toolbar settings - void setButtonType(LLToolBarEnums::ButtonType button_type); - LLToolBarEnums::ButtonType getButtonType() { return mButtonType; } - command_id_list_t& getCommandsList() { return mButtonCommands; } - void clearCommandsList(); + class LLCenterLayoutPanel : public LLLayoutPanel + { + public: + typedef boost::function<void(LLToolBarEnums::EToolBarLocation tb, const LLRect& rect)> reshape_callback_t; + + virtual ~LLCenterLayoutPanel() {} + /*virtual*/ void handleReshape(const LLRect& rect, bool by_user); + + void setLocationId(LLToolBarEnums::EToolBarLocation id) { mLocationId = id; } + void setReshapeCallback(reshape_callback_t cb) { mReshapeCallback = cb; } + void setButtonPanel(LLPanel * panel) { mButtonPanel = panel; } + + protected: + friend class LLUICtrlFactory; + LLCenterLayoutPanel(const Params& params) : LLLayoutPanel(params), mButtonPanel(NULL) {} + + private: + reshape_callback_t mReshapeCallback; + LLToolBarEnums::EToolBarLocation mLocationId; + LLPanel * mButtonPanel; + }; + + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Mandatory<LLToolBarEnums::ButtonType> button_display_mode; + Mandatory<LLToolBarEnums::SideType> side; + + Optional<LLToolBarButton::Params> button_icon, + button_icon_and_text; + + Optional<bool> read_only, + wrap; + + Optional<S32> pad_left, + pad_top, + pad_right, + pad_bottom, + pad_between, + min_girth; + + // default command set + Multiple<LLCommandId::Params> commands; + + Optional<LLPanel::Params> button_panel; + + Params(); + }; + + // virtuals + void draw(); + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + static const int RANK_NONE = -1; + bool addCommand(const LLCommandId& commandId, int rank = RANK_NONE); + int removeCommand(const LLCommandId& commandId); // Returns the rank the removed command was at, RANK_NONE if not found + bool hasCommand(const LLCommandId& commandId) const; // is this command bound to a button in this toolbar + bool enableCommand(const LLCommandId& commandId, bool enabled); // enable/disable button bound to the specified command, if it exists in this toolbar + bool stopCommandInProgress(const LLCommandId& commandId); // stop command if it is currently active + bool flashCommand(const LLCommandId& commandId, bool flash, bool force_flashing = false); // flash button associated with given command, if in this toolbar + + void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } // connects drag and drop behavior to external logic + void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } + void setHandleDropCallback(tool_handledrop_callback_t cb) { mHandleDropCallback = cb; } + bool isReadOnly() const { return mReadOnly; } + LLCenterLayoutPanel * getCenterLayoutPanel() const { return mCenterPanel; } + + LLToolBarButton* createButton(const LLCommandId& id); + + typedef boost::signals2::signal<void (LLView* button)> button_signal_t; + boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb); + boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb); + boost::signals2::connection setButtonLeaveCallback(const button_signal_t::slot_type& cb); + boost::signals2::connection setButtonRemoveCallback(const button_signal_t::slot_type& cb); + + // append the specified string to end of tooltip + void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; } + + LLToolBarEnums::SideType getSideType() const { return mSideType; } + bool hasButtons() const { return !mButtons.empty(); } + bool isModified() const { return mModified; } + + int getRankFromPosition(S32 x, S32 y); + int getRankFromPosition(const LLCommandId& id); + + // Methods used in loading and saving toolbar settings + void setButtonType(LLToolBarEnums::ButtonType button_type); + LLToolBarEnums::ButtonType getButtonType() { return mButtonType; } + command_id_list_t& getCommandsList() { return mButtonCommands; } + void clearCommandsList(); private: - friend class LLUICtrlFactory; - LLToolBar(const Params&); - ~LLToolBar(); - - void initFromParams(const Params&); - void createContextMenu(); - void updateLayoutAsNeeded(); - void createButtons(); - void resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth); - BOOL isSettingChecked(const LLSD& userdata); - void onSettingEnable(const LLSD& userdata); - void onRemoveSelectedCommand(); + friend class LLUICtrlFactory; + LLToolBar(const Params&); + ~LLToolBar(); + + void initFromParams(const Params&); + void createContextMenu(); + void updateLayoutAsNeeded(); + void createButtons(); + void resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth); + BOOL isSettingChecked(const LLSD& userdata); + void onSettingEnable(const LLSD& userdata); + void onRemoveSelectedCommand(); private: - // static layout state - const bool mReadOnly; - const LLToolBarEnums::SideType mSideType; - const bool mWrap; - const S32 mPadLeft, - mPadRight, - mPadTop, - mPadBottom, - mPadBetween, - mMinGirth; - - // drag and drop state - tool_startdrag_callback_t mStartDragItemCallback; - tool_handledrag_callback_t mHandleDragItemCallback; - tool_handledrop_callback_t mHandleDropCallback; - bool mDragAndDropTarget; - int mDragRank; - S32 mDragx, - mDragy, - mDragGirth; - - typedef std::list<LLToolBarButton*> toolbar_button_list; - typedef std::map<LLUUID, LLToolBarButton*> command_id_map; - toolbar_button_list mButtons; - command_id_list_t mButtonCommands; - command_id_map mButtonMap; - - LLToolBarEnums::ButtonType mButtonType; - LLToolBarButton::Params mButtonParams[LLToolBarEnums::BTNTYPE_COUNT]; - - // related widgets - LLLayoutStack* mCenteringStack; - LLCenterLayoutPanel* mCenterPanel; - LLPanel* mButtonPanel; - LLHandle<class LLContextMenu> mPopupMenuHandle; - LLHandle<class LLView> mRemoveButtonHandle; - - LLToolBarButton* mRightMouseTargetButton; - - bool mNeedsLayout; - bool mModified; - - button_signal_t* mButtonAddSignal; - button_signal_t* mButtonEnterSignal; - button_signal_t* mButtonLeaveSignal; - button_signal_t* mButtonRemoveSignal; - - std::string mButtonTooltipSuffix; - - LLIconCtrl* mCaretIcon; + // static layout state + const bool mReadOnly; + const LLToolBarEnums::SideType mSideType; + const bool mWrap; + const S32 mPadLeft, + mPadRight, + mPadTop, + mPadBottom, + mPadBetween, + mMinGirth; + + // drag and drop state + tool_startdrag_callback_t mStartDragItemCallback; + tool_handledrag_callback_t mHandleDragItemCallback; + tool_handledrop_callback_t mHandleDropCallback; + bool mDragAndDropTarget; + int mDragRank; + S32 mDragx, + mDragy, + mDragGirth; + + typedef std::list<LLToolBarButton*> toolbar_button_list; + typedef std::map<LLUUID, LLToolBarButton*> command_id_map; + toolbar_button_list mButtons; + command_id_list_t mButtonCommands; + command_id_map mButtonMap; + + LLToolBarEnums::ButtonType mButtonType; + LLToolBarButton::Params mButtonParams[LLToolBarEnums::BTNTYPE_COUNT]; + + // related widgets + LLLayoutStack* mCenteringStack; + LLCenterLayoutPanel* mCenterPanel; + LLPanel* mButtonPanel; + LLHandle<class LLContextMenu> mPopupMenuHandle; + LLHandle<class LLView> mRemoveButtonHandle; + + LLToolBarButton* mRightMouseTargetButton; + + bool mNeedsLayout; + bool mModified; + + button_signal_t* mButtonAddSignal; + button_signal_t* mButtonEnterSignal; + button_signal_t* mButtonLeaveSignal; + button_signal_t* mButtonRemoveSignal; + + std::string mButtonTooltipSuffix; + + LLIconCtrl* mCaretIcon; }; diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index bea46f4a6f..c10b8b4830 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltooltip.cpp * @brief LLToolTipMgr class implementation and related classes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ #include "lliconctrl.h" #include "llbutton.h" #include "llmenugl.h" // hideMenus() -#include "llui.h" // positionViewNearMouse() +#include "llui.h" // positionViewNearMouse() #include "llwindow.h" #include "lltrans.h" // @@ -55,77 +55,77 @@ static LLDefaultChildRegistry::Register<LLToolTipView> register_tooltip_view("to LLToolTipView::Params::Params() { - changeDefault(mouse_opaque, false); + changeDefault(mouse_opaque, false); } LLToolTipView::LLToolTipView(const LLToolTipView::Params& p) -: LLView(p) +: LLView(p) { } void LLToolTipView::draw() { - LLToolTipMgr::instance().updateToolTipVisibility(); + LLToolTipMgr::instance().updateToolTipVisibility(); - // do the usual thing - LLView::draw(); + // do the usual thing + LLView::draw(); } BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask) { - static S32 last_x = x; - static S32 last_y = y; + static S32 last_x = x; + static S32 last_y = y; - LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance(); + LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance(); - if (x != last_x && y != last_y && !tooltip_mgr.getMouseNearRect().pointInRect(x, y)) - { - // allow new tooltips because mouse moved outside of mouse near rect - tooltip_mgr.unblockToolTips(); - } + if (x != last_x && y != last_y && !tooltip_mgr.getMouseNearRect().pointInRect(x, y)) + { + // allow new tooltips because mouse moved outside of mouse near rect + tooltip_mgr.unblockToolTips(); + } - last_x = x; - last_y = y; - return LLView::handleHover(x, y, mask); + last_x = x; + last_y = y; + return LLView::handleHover(x, y, mask); } BOOL LLToolTipView::handleMouseDown(S32 x, S32 y, MASK mask) { - LLToolTipMgr::instance().blockToolTips(); + LLToolTipMgr::instance().blockToolTips(); - if (LLView::handleMouseDown(x, y, mask)) - { - // If we are handling the mouse event menu holder - // won't get a chance to close menus so do this here - LLMenuGL::sMenuContainer->hideMenus(); - return TRUE; - } + if (LLView::handleMouseDown(x, y, mask)) + { + // If we are handling the mouse event menu holder + // won't get a chance to close menus so do this here + LLMenuGL::sMenuContainer->hideMenus(); + return TRUE; + } - return FALSE; + return FALSE; } BOOL LLToolTipView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - LLToolTipMgr::instance().blockToolTips(); - return LLView::handleMiddleMouseDown(x, y, mask); + LLToolTipMgr::instance().blockToolTips(); + return LLView::handleMiddleMouseDown(x, y, mask); } BOOL LLToolTipView::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLToolTipMgr::instance().blockToolTips(); - return LLView::handleRightMouseDown(x, y, mask); + LLToolTipMgr::instance().blockToolTips(); + return LLView::handleRightMouseDown(x, y, mask); } BOOL LLToolTipView::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - LLToolTipMgr::instance().blockToolTips(); - return FALSE; + LLToolTipMgr::instance().blockToolTips(); + return FALSE; } void LLToolTipView::drawStickyRect() { - gl_rect_2d(LLToolTipMgr::instance().getMouseNearRect(), LLColor4::white, false); + gl_rect_2d(LLToolTipMgr::instance().getMouseNearRect(), LLColor4::white, false); } // defaults for floater param block pulled from widgets/floater.xml @@ -140,277 +140,277 @@ static LLDefaultChildRegistry::Register<LLToolTip> register_tooltip("tool_tip"); LLToolTip::Params::Params() -: max_width("max_width", 200), - padding("padding", 4), - wrap("wrap", true), - pos("pos"), - message("message"), - delay_time("delay_time", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" )), - visible_time_over("visible_time_over", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )), - visible_time_near("visible_time_near", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )), - visible_time_far("visible_time_far", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )), - sticky_rect("sticky_rect"), - image("image"), - text_color("text_color"), - time_based_media("time_based_media", false), - web_based_media("web_based_media", false), - media_playing("media_playing", false), +: max_width("max_width", 200), + padding("padding", 4), + wrap("wrap", true), + pos("pos"), + message("message"), + delay_time("delay_time", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" )), + visible_time_over("visible_time_over", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )), + visible_time_near("visible_time_near", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )), + visible_time_far("visible_time_far", LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )), + sticky_rect("sticky_rect"), + image("image"), + text_color("text_color"), + time_based_media("time_based_media", false), + web_based_media("web_based_media", false), + media_playing("media_playing", false), allow_paste_tooltip("allow_paste_tooltip", false) { - changeDefault(chrome, true); + changeDefault(chrome, true); } LLToolTip::LLToolTip(const LLToolTip::Params& p) -: LLPanel(p), - mHasClickCallback(p.click_callback.isProvided()), - mPadding(p.padding), - mMaxWidth(p.max_width), - mTextBox(NULL), - mInfoButton(NULL), - mPlayMediaButton(NULL), - mHomePageButton(NULL), +: LLPanel(p), + mHasClickCallback(p.click_callback.isProvided()), + mPadding(p.padding), + mMaxWidth(p.max_width), + mTextBox(NULL), + mInfoButton(NULL), + mPlayMediaButton(NULL), + mHomePageButton(NULL), mIsTooltipPastable(p.allow_paste_tooltip) { - LLTextBox::Params params; - params.name = params.initial_value().asString(); - // bake textbox padding into initial rect - params.rect = LLRect (mPadding, mPadding + 1, mPadding + 1, mPadding); - params.h_pad = 0; - params.v_pad = 0; - params.mouse_opaque = false; - params.text_color = p.text_color; - params.bg_visible = false; - params.font = p.font; - params.use_ellipses = true; - params.wrap = p.wrap; - params.font_valign = LLFontGL::VCENTER; - params.parse_urls = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips - mTextBox = LLUICtrlFactory::create<LLTextBox> (params); - addChild(mTextBox); - - S32 TOOLTIP_ICON_SIZE = 0; - S32 TOOLTIP_PLAYBUTTON_SIZE = 0; - if (p.image.isProvided()) - { - LLButton::Params icon_params; - icon_params.name = "tooltip_info"; - LLRect icon_rect; - LLUIImage* imagep = p.image; - TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16); - icon_rect.setOriginAndSize(mPadding, mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); - icon_params.rect = icon_rect; - icon_params.image_unselected(imagep); - icon_params.image_selected(imagep); - - icon_params.scale_image(true); - icon_params.flash_color.control = "ButtonUnselectedFgColor"; - mInfoButton = LLUICtrlFactory::create<LLButton>(icon_params); - if (p.click_callback.isProvided()) - { - mInfoButton->setCommitCallback(boost::bind(p.click_callback())); - } - addChild(mInfoButton); - - // move text over to fit image in - mTextBox->translate(TOOLTIP_ICON_SIZE + mPadding, 0); - } - - if (p.time_based_media) - { - LLButton::Params p_button; - p_button.name(std::string("play_media")); - p_button.label(""); // provide label but set to empty so name does not overwrite it -angela - TOOLTIP_PLAYBUTTON_SIZE = 16; - LLRect button_rect; - button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); - p_button.rect = button_rect; - p_button.image_selected.name("button_anim_pause.tga"); - p_button.image_unselected.name("button_anim_play.tga"); - p_button.scale_image(true); - - mPlayMediaButton = LLUICtrlFactory::create<LLButton>(p_button); - if(p.click_playmedia_callback.isProvided()) - { - mPlayMediaButton->setCommitCallback(boost::bind(p.click_playmedia_callback())); - } - mPlayMediaButton->setToggleState(p.media_playing); - addChild(mPlayMediaButton); - - // move text over to fit image in - mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0); - } - - if (p.web_based_media) - { - LLButton::Params p_w_button; - p_w_button.name(std::string("home_page")); - p_w_button.label(""); // provid label but set to empty so name does not overwrite it -angela - TOOLTIP_PLAYBUTTON_SIZE = 16; - LLRect button_rect; - button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); - p_w_button.rect = button_rect; - p_w_button.image_unselected.name("map_home.tga"); - p_w_button.scale_image(true); - - mHomePageButton = LLUICtrlFactory::create<LLButton>(p_w_button); - if(p.click_homepage_callback.isProvided()) - { - mHomePageButton->setCommitCallback(boost::bind(p.click_homepage_callback())); - } - addChild(mHomePageButton); - - // move text over to fit image in - mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0); - } - - if (p.click_callback.isProvided()) - { - setMouseUpCallback(boost::bind(p.click_callback())); - } + LLTextBox::Params params; + params.name = params.initial_value().asString(); + // bake textbox padding into initial rect + params.rect = LLRect (mPadding, mPadding + 1, mPadding + 1, mPadding); + params.h_pad = 0; + params.v_pad = 0; + params.mouse_opaque = false; + params.text_color = p.text_color; + params.bg_visible = false; + params.font = p.font; + params.use_ellipses = true; + params.wrap = p.wrap; + params.font_valign = LLFontGL::VCENTER; + params.parse_urls = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips + mTextBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mTextBox); + + S32 TOOLTIP_ICON_SIZE = 0; + S32 TOOLTIP_PLAYBUTTON_SIZE = 0; + if (p.image.isProvided()) + { + LLButton::Params icon_params; + icon_params.name = "tooltip_info"; + LLRect icon_rect; + LLUIImage* imagep = p.image; + TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16); + icon_rect.setOriginAndSize(mPadding, mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); + icon_params.rect = icon_rect; + icon_params.image_unselected(imagep); + icon_params.image_selected(imagep); + + icon_params.scale_image(true); + icon_params.flash_color.control = "ButtonUnselectedFgColor"; + mInfoButton = LLUICtrlFactory::create<LLButton>(icon_params); + if (p.click_callback.isProvided()) + { + mInfoButton->setCommitCallback(boost::bind(p.click_callback())); + } + addChild(mInfoButton); + + // move text over to fit image in + mTextBox->translate(TOOLTIP_ICON_SIZE + mPadding, 0); + } + + if (p.time_based_media) + { + LLButton::Params p_button; + p_button.name(std::string("play_media")); + p_button.label(""); // provide label but set to empty so name does not overwrite it -angela + TOOLTIP_PLAYBUTTON_SIZE = 16; + LLRect button_rect; + button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); + p_button.rect = button_rect; + p_button.image_selected.name("button_anim_pause.tga"); + p_button.image_unselected.name("button_anim_play.tga"); + p_button.scale_image(true); + + mPlayMediaButton = LLUICtrlFactory::create<LLButton>(p_button); + if(p.click_playmedia_callback.isProvided()) + { + mPlayMediaButton->setCommitCallback(boost::bind(p.click_playmedia_callback())); + } + mPlayMediaButton->setToggleState(p.media_playing); + addChild(mPlayMediaButton); + + // move text over to fit image in + mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0); + } + + if (p.web_based_media) + { + LLButton::Params p_w_button; + p_w_button.name(std::string("home_page")); + p_w_button.label(""); // provid label but set to empty so name does not overwrite it -angela + TOOLTIP_PLAYBUTTON_SIZE = 16; + LLRect button_rect; + button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); + p_w_button.rect = button_rect; + p_w_button.image_unselected.name("map_home.tga"); + p_w_button.scale_image(true); + + mHomePageButton = LLUICtrlFactory::create<LLButton>(p_w_button); + if(p.click_homepage_callback.isProvided()) + { + mHomePageButton->setCommitCallback(boost::bind(p.click_homepage_callback())); + } + addChild(mHomePageButton); + + // move text over to fit image in + mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0); + } + + if (p.click_callback.isProvided()) + { + setMouseUpCallback(boost::bind(p.click_callback())); + } } void LLToolTip::initFromParams(const LLToolTip::Params& p) { - LLPanel::initFromParams(p); + LLPanel::initFromParams(p); - // do this *after* we've had our size set in LLPanel::initFromParams(); - const S32 REALLY_LARGE_HEIGHT = 10000; - mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT); + // do this *after* we've had our size set in LLPanel::initFromParams(); + const S32 REALLY_LARGE_HEIGHT = 10000; + mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT); - if (p.styled_message.isProvided()) - { - for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message.begin(); - text_it != p.styled_message.end(); - ++text_it) - { - mTextBox->appendText(text_it->text(), false, text_it->style); - } - } - else - { - mTextBox->setText(p.message()); - } + if (p.styled_message.isProvided()) + { + for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message.begin(); + text_it != p.styled_message.end(); + ++text_it) + { + mTextBox->appendText(text_it->text(), false, text_it->style); + } + } + else + { + mTextBox->setText(p.message()); + } - mIsTooltipPastable = p.allow_paste_tooltip; + mIsTooltipPastable = p.allow_paste_tooltip; - updateTextBox(); - snapToChildren(); + updateTextBox(); + snapToChildren(); } void LLToolTip::updateTextBox() { - S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1); - S32 text_height = mTextBox->getTextPixelHeight(); - mTextBox->reshape(text_width, text_height); + S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1); + S32 text_height = mTextBox->getTextPixelHeight(); + mTextBox->reshape(text_width, text_height); } - + void LLToolTip::snapToChildren() { - // reshape tooltip panel to fit text box - LLRect tooltip_rect = calcBoundingRect(); - tooltip_rect.mTop += mPadding; - tooltip_rect.mRight += mPadding; - tooltip_rect.mBottom = 0; - tooltip_rect.mLeft = 0; - - if (mInfoButton) - { - mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); + // reshape tooltip panel to fit text box + LLRect tooltip_rect = calcBoundingRect(); + tooltip_rect.mTop += mPadding; + tooltip_rect.mRight += mPadding; + tooltip_rect.mBottom = 0; + tooltip_rect.mLeft = 0; + + if (mInfoButton) + { + mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); - LLRect text_rect = mTextBox->getRect(); - LLRect icon_rect = mInfoButton->getRect(); - mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY()); - } + LLRect text_rect = mTextBox->getRect(); + LLRect icon_rect = mInfoButton->getRect(); + mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY()); + } - setShape(tooltip_rect); + setShape(tooltip_rect); } void LLToolTip::setVisible(BOOL visible) { - // fade out tooltip over time - if (visible) - { - mVisibleTimer.start(); - mFadeTimer.stop(); - LLPanel::setVisible(TRUE); - } - else - { - mVisibleTimer.stop(); - // don't actually change mVisible state, start fade out transition instead - if (!mFadeTimer.getStarted()) - { - mFadeTimer.start(); - } - } + // fade out tooltip over time + if (visible) + { + mVisibleTimer.start(); + mFadeTimer.stop(); + LLPanel::setVisible(TRUE); + } + else + { + mVisibleTimer.stop(); + // don't actually change mVisible state, start fade out transition instead + if (!mFadeTimer.getStarted()) + { + mFadeTimer.start(); + } + } } BOOL LLToolTip::handleHover(S32 x, S32 y, MASK mask) { - //mInfoButton->setFlashing(true); - if(mInfoButton) - mInfoButton->setHighlight(true); - - LLPanel::handleHover(x, y, mask); - if (mHasClickCallback) - { - getWindow()->setCursor(UI_CURSOR_HAND); - } - return TRUE; + //mInfoButton->setFlashing(true); + if(mInfoButton) + mInfoButton->setHighlight(true); + + LLPanel::handleHover(x, y, mask); + if (mHasClickCallback) + { + getWindow()->setCursor(UI_CURSOR_HAND); + } + return TRUE; } void LLToolTip::onMouseLeave(S32 x, S32 y, MASK mask) { - //mInfoButton->setFlashing(true); - if(mInfoButton) - mInfoButton->setHighlight(false); - LLUICtrl::onMouseLeave(x, y, mask); + //mInfoButton->setFlashing(true); + if(mInfoButton) + mInfoButton->setHighlight(false); + LLUICtrl::onMouseLeave(x, y, mask); } void LLToolTip::draw() { - F32 alpha = 1.f; + F32 alpha = 1.f; - if (mFadeTimer.getStarted()) - { - static LLCachedControl<F32> tool_tip_fade_time(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFadeTime", 0.2f); - alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time(), 1.f, 0.f); - if (alpha == 0.f) - { - // finished fading out, so hide ourselves - mFadeTimer.stop(); - LLPanel::setVisible(false); - } - } + if (mFadeTimer.getStarted()) + { + static LLCachedControl<F32> tool_tip_fade_time(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFadeTime", 0.2f); + alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time(), 1.f, 0.f); + if (alpha == 0.f) + { + // finished fading out, so hide ourselves + mFadeTimer.stop(); + LLPanel::setVisible(false); + } + } - // draw tooltip contents with appropriate alpha - { - LLViewDrawContext context(alpha); - LLPanel::draw(); - } + // draw tooltip contents with appropriate alpha + { + LLViewDrawContext context(alpha); + LLPanel::draw(); + } } -bool LLToolTip::isFading() -{ - return mFadeTimer.getStarted(); +bool LLToolTip::isFading() +{ + return mFadeTimer.getStarted(); } -F32 LLToolTip::getVisibleTime() -{ - return mVisibleTimer.getStarted() ? mVisibleTimer.getElapsedTimeF32() : 0.f; +F32 LLToolTip::getVisibleTime() +{ + return mVisibleTimer.getStarted() ? mVisibleTimer.getElapsedTimeF32() : 0.f; } -bool LLToolTip::hasClickCallback() +bool LLToolTip::hasClickCallback() { - return mHasClickCallback; + return mHasClickCallback; } void LLToolTip::getToolTipMessage(std::string & message) { - if (mTextBox) - { - message = mTextBox->getText(); - } + if (mTextBox) + { + message = mTextBox->getText(); + } } @@ -421,75 +421,75 @@ void LLToolTip::getToolTipMessage(std::string & message) LLToolTipMgr::LLToolTipMgr() : mToolTipsBlocked(false), - mToolTip(NULL), - mNeedsToolTip(false) + mToolTip(NULL), + mNeedsToolTip(false) {} void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) { - // block all other tooltips until tooltips re-enabled (e.g. mouse moved) - blockToolTips(); + // block all other tooltips until tooltips re-enabled (e.g. mouse moved) + blockToolTips(); - delete mToolTip; + delete mToolTip; - LLToolTip::Params tooltip_params(params); - // block mouse events if there is a click handler registered (specifically, hover) - if (params.click_callback.isProvided() && !params.mouse_opaque.isProvided()) - { - // set mouse_opaque to true if it wasn't already set to something else - // this prevents mouse down from going "through" the tooltip and ultimately - // causing the tooltip to disappear - tooltip_params.mouse_opaque = true; - } - tooltip_params.rect = LLRect (0, 1, 1, 0); + LLToolTip::Params tooltip_params(params); + // block mouse events if there is a click handler registered (specifically, hover) + if (params.click_callback.isProvided() && !params.mouse_opaque.isProvided()) + { + // set mouse_opaque to true if it wasn't already set to something else + // this prevents mouse down from going "through" the tooltip and ultimately + // causing the tooltip to disappear + tooltip_params.mouse_opaque = true; + } + tooltip_params.rect = LLRect (0, 1, 1, 0); - if (tooltip_params.create_callback.isProvided()) + if (tooltip_params.create_callback.isProvided()) { mToolTip = tooltip_params.create_callback()(tooltip_params); - if (mToolTip == NULL) + if (mToolTip == NULL) { return; } } - else - mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params); - - gToolTipView->addChild(mToolTip); - - if (params.pos.isProvided()) - { - LLCoordGL pos = params.pos; - // try to spawn at requested position - LLUI::getInstance()->positionViewNearMouse(mToolTip, pos.mX, pos.mY); - } - else - { - // just spawn at mouse location - LLUI::getInstance()->positionViewNearMouse(mToolTip); - } - - //...update "sticky" rect and tooltip position - if (params.sticky_rect.isProvided()) - { - mMouseNearRect = params.sticky_rect; - } - else - { - S32 mouse_x; - S32 mouse_y; - LLUI::getInstance()->getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y); - - // allow mouse a little bit of slop before changing tooltips - mMouseNearRect.setCenterAndSize(mouse_x, mouse_y, 3, 3); - } - - // allow mouse to move all the way to the tooltip without changing tooltips - // (tooltip can still time out) - if (mToolTip->hasClickCallback()) - { - // keep tooltip up when we mouse over it - mMouseNearRect.unionWith(mToolTip->getRect()); - } + else + mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params); + + gToolTipView->addChild(mToolTip); + + if (params.pos.isProvided()) + { + LLCoordGL pos = params.pos; + // try to spawn at requested position + LLUI::getInstance()->positionViewNearMouse(mToolTip, pos.mX, pos.mY); + } + else + { + // just spawn at mouse location + LLUI::getInstance()->positionViewNearMouse(mToolTip); + } + + //...update "sticky" rect and tooltip position + if (params.sticky_rect.isProvided()) + { + mMouseNearRect = params.sticky_rect; + } + else + { + S32 mouse_x; + S32 mouse_y; + LLUI::getInstance()->getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y); + + // allow mouse a little bit of slop before changing tooltips + mMouseNearRect.setCenterAndSize(mouse_x, mouse_y, 3, 3); + } + + // allow mouse to move all the way to the tooltip without changing tooltips + // (tooltip can still time out) + if (mToolTip->hasClickCallback()) + { + // keep tooltip up when we mouse over it + mMouseNearRect.unionWith(mToolTip->getRect()); + } } @@ -500,140 +500,140 @@ void LLToolTipMgr::show(const std::string& msg, bool allow_paste_tooltip) void LLToolTipMgr::show(const LLToolTip::Params& params) { - if (!params.styled_message.isProvided() - && (!params.message.isProvided() || params.message().empty()) - && !params.image.isProvided() && !params.create_callback.isProvided()) return; - - // fill in default tooltip params from tool_tip.xml - LLToolTip::Params params_with_defaults(params); - params_with_defaults.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLToolTip>()); - if (!params_with_defaults.validateBlock()) - { - LL_WARNS() << "Could not display tooltip!" << LL_ENDL; - return; - } - - // are we ready to show the tooltip? - if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc. - && LLUI::getInstance()->getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough - { - bool tooltip_changed = mLastToolTipParams.message() != params_with_defaults.message() - || mLastToolTipParams.pos() != params_with_defaults.pos() - || mLastToolTipParams.time_based_media() != params_with_defaults.time_based_media() - || mLastToolTipParams.web_based_media() != params_with_defaults.web_based_media(); - - bool tooltip_shown = mToolTip - && mToolTip->getVisible() - && !mToolTip->isFading(); - - mNeedsToolTip = tooltip_changed || !tooltip_shown; - // store description of tooltip for later creation - mNextToolTipParams = params_with_defaults; - } + if (!params.styled_message.isProvided() + && (!params.message.isProvided() || params.message().empty()) + && !params.image.isProvided() && !params.create_callback.isProvided()) return; + + // fill in default tooltip params from tool_tip.xml + LLToolTip::Params params_with_defaults(params); + params_with_defaults.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLToolTip>()); + if (!params_with_defaults.validateBlock()) + { + LL_WARNS() << "Could not display tooltip!" << LL_ENDL; + return; + } + + // are we ready to show the tooltip? + if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc. + && LLUI::getInstance()->getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough + { + bool tooltip_changed = mLastToolTipParams.message() != params_with_defaults.message() + || mLastToolTipParams.pos() != params_with_defaults.pos() + || mLastToolTipParams.time_based_media() != params_with_defaults.time_based_media() + || mLastToolTipParams.web_based_media() != params_with_defaults.web_based_media(); + + bool tooltip_shown = mToolTip + && mToolTip->getVisible() + && !mToolTip->isFading(); + + mNeedsToolTip = tooltip_changed || !tooltip_shown; + // store description of tooltip for later creation + mNextToolTipParams = params_with_defaults; + } } // allow new tooltips to be created, e.g. after mouse has moved void LLToolTipMgr::unblockToolTips() { - mToolTipsBlocked = false; + mToolTipsBlocked = false; } // disallow new tooltips until unblockTooltips called void LLToolTipMgr::blockToolTips() { - hideToolTips(); - mToolTipsBlocked = true; + hideToolTips(); + mToolTipsBlocked = true; } -void LLToolTipMgr::hideToolTips() -{ - if (mToolTip) - { - mToolTip->setVisible(FALSE); - } +void LLToolTipMgr::hideToolTips() +{ + if (mToolTip) + { + mToolTip->setVisible(FALSE); + } } bool LLToolTipMgr::toolTipVisible() { - return mToolTip ? mToolTip->isInVisibleChain() : false; + return mToolTip ? mToolTip->isInVisibleChain() : false; } LLRect LLToolTipMgr::getToolTipRect() { - if (mToolTip && mToolTip->getVisible()) - { - return mToolTip->getRect(); - } - return LLRect(); + if (mToolTip && mToolTip->getVisible()) + { + return mToolTip->getRect(); + } + return LLRect(); } -LLRect LLToolTipMgr::getMouseNearRect() -{ - return toolTipVisible() ? mMouseNearRect : LLRect(); +LLRect LLToolTipMgr::getMouseNearRect() +{ + return toolTipVisible() ? mMouseNearRect : LLRect(); } // every frame, determine if current tooltip should be hidden void LLToolTipMgr::updateToolTipVisibility() { - // create new tooltip if we have one ready to go - if (mNeedsToolTip) - { - mNeedsToolTip = false; - createToolTip(mNextToolTipParams); - mLastToolTipParams = mNextToolTipParams; - - return; - } - - // hide tooltips when mouse cursor is hidden - if (LLUI::getInstance()->getWindow()->isCursorHidden()) - { - blockToolTips(); - return; - } - - // hide existing tooltips if they have timed out - F32 tooltip_timeout = 0.f; - if (toolTipVisible()) - { - S32 mouse_x, mouse_y; - LLUI::getInstance()->getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y); - - // mouse far away from tooltip - tooltip_timeout = mLastToolTipParams.visible_time_far; - // mouse near rect will only include the tooltip if the - // tooltip is clickable - if (mMouseNearRect.pointInRect(mouse_x, mouse_y)) - { - // mouse "close" to tooltip - tooltip_timeout = mLastToolTipParams.visible_time_near; - - // if tooltip is clickable (has large mMouseNearRect) - // than having cursor over tooltip keeps it up indefinitely - if (mToolTip->parentPointInView(mouse_x, mouse_y)) - { - // mouse over tooltip itself, don't time out - tooltip_timeout = mLastToolTipParams.visible_time_over; - } - } - - if (mToolTip->getVisibleTime() > tooltip_timeout) - { - hideToolTips(); - unblockToolTips(); - } - } + // create new tooltip if we have one ready to go + if (mNeedsToolTip) + { + mNeedsToolTip = false; + createToolTip(mNextToolTipParams); + mLastToolTipParams = mNextToolTipParams; + + return; + } + + // hide tooltips when mouse cursor is hidden + if (LLUI::getInstance()->getWindow()->isCursorHidden()) + { + blockToolTips(); + return; + } + + // hide existing tooltips if they have timed out + F32 tooltip_timeout = 0.f; + if (toolTipVisible()) + { + S32 mouse_x, mouse_y; + LLUI::getInstance()->getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y); + + // mouse far away from tooltip + tooltip_timeout = mLastToolTipParams.visible_time_far; + // mouse near rect will only include the tooltip if the + // tooltip is clickable + if (mMouseNearRect.pointInRect(mouse_x, mouse_y)) + { + // mouse "close" to tooltip + tooltip_timeout = mLastToolTipParams.visible_time_near; + + // if tooltip is clickable (has large mMouseNearRect) + // than having cursor over tooltip keeps it up indefinitely + if (mToolTip->parentPointInView(mouse_x, mouse_y)) + { + // mouse over tooltip itself, don't time out + tooltip_timeout = mLastToolTipParams.visible_time_over; + } + } + + if (mToolTip->getVisibleTime() > tooltip_timeout) + { + hideToolTips(); + unblockToolTips(); + } + } } // Return the current tooltip text void LLToolTipMgr::getToolTipMessage(std::string & message) { - if (toolTipVisible()) - { - mToolTip->getToolTipMessage(message); - } + if (toolTipVisible()) + { + mToolTip->getToolTipMessage(message); + } } bool LLToolTipMgr::isTooltipPastable() diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index fef5e7c75f..9ae537e0c1 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -1,25 +1,25 @@ -/** +/** * @file lltooltip.h * @brief LLToolTipMgr class definition and related classes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,95 +39,95 @@ class LLToolTipView : public LLView { public: - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Params(); - }; - LLToolTipView(const LLToolTipView::Params&); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(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 handleScrollWheel( S32 x, S32 y, S32 clicks ); - - void drawStickyRect(); - - /*virtual*/ void draw(); + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Params(); + }; + LLToolTipView(const LLToolTipView::Params&); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(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 handleScrollWheel( S32 x, S32 y, S32 clicks ); + + void drawStickyRect(); + + /*virtual*/ void draw(); }; class LLToolTip : public LLPanel { public: - struct StyledText : public LLInitParam::Block<StyledText> - { - Mandatory<std::string> text; - Optional<LLStyle::Params> style; - }; - - struct Params : public LLInitParam::Block<Params, LLPanel::Params> - { - typedef boost::function<void(void)> click_callback_t; - typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t; - - Optional<std::string> message; - Multiple<StyledText> styled_message; - - Optional<LLCoordGL> pos; - Optional<F32> delay_time, - visible_time_over, // time for which tooltip is visible while mouse on it - visible_time_near, // time for which tooltip is visible while mouse near it - visible_time_far; // time for which tooltip is visible while mouse moved away - Optional<LLRect> sticky_rect; - Optional<const LLFontGL*> font; - Optional<LLUIImage*> image; - Optional<LLUIColor> text_color; - Optional<bool> time_based_media, - web_based_media, - media_playing; - Optional<create_callback_t> create_callback; - Optional<LLSD> create_params; - Optional<click_callback_t> click_callback, - click_playmedia_callback, - click_homepage_callback; - Optional<S32> max_width, - padding; - Optional<bool> wrap; + struct StyledText : public LLInitParam::Block<StyledText> + { + Mandatory<std::string> text; + Optional<LLStyle::Params> style; + }; + + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + { + typedef boost::function<void(void)> click_callback_t; + typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t; + + Optional<std::string> message; + Multiple<StyledText> styled_message; + + Optional<LLCoordGL> pos; + Optional<F32> delay_time, + visible_time_over, // time for which tooltip is visible while mouse on it + visible_time_near, // time for which tooltip is visible while mouse near it + visible_time_far; // time for which tooltip is visible while mouse moved away + Optional<LLRect> sticky_rect; + Optional<const LLFontGL*> font; + Optional<LLUIImage*> image; + Optional<LLUIColor> text_color; + Optional<bool> time_based_media, + web_based_media, + media_playing; + Optional<create_callback_t> create_callback; + Optional<LLSD> create_params; + Optional<click_callback_t> click_callback, + click_playmedia_callback, + click_homepage_callback; + Optional<S32> max_width, + padding; + Optional<bool> wrap; Optional<bool> allow_paste_tooltip; - Params(); - }; - /*virtual*/ void draw(); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ void setVisible(BOOL visible); + Params(); + }; + /*virtual*/ void draw(); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); + /*virtual*/ void setVisible(BOOL visible); - bool isFading(); - F32 getVisibleTime(); - bool hasClickCallback(); + bool isFading(); + F32 getVisibleTime(); + bool hasClickCallback(); - LLToolTip(const Params& p); - virtual void initFromParams(const LLToolTip::Params& params); + LLToolTip(const Params& p); + virtual void initFromParams(const LLToolTip::Params& params); - void getToolTipMessage(std::string & message); + void getToolTipMessage(std::string & message); bool isTooltipPastable() { return mIsTooltipPastable; } protected: - void updateTextBox(); - void snapToChildren(); + void updateTextBox(); + void snapToChildren(); protected: - class LLTextBox* mTextBox; - class LLButton* mInfoButton; - class LLButton* mPlayMediaButton; - class LLButton* mHomePageButton; + class LLTextBox* mTextBox; + class LLButton* mInfoButton; + class LLButton* mPlayMediaButton; + class LLButton* mHomePageButton; - LLFrameTimer mFadeTimer; - LLFrameTimer mVisibleTimer; - bool mHasClickCallback; - S32 mPadding; // pixels - S32 mMaxWidth; + LLFrameTimer mFadeTimer; + LLFrameTimer mVisibleTimer; + bool mHasClickCallback; + S32 mPadding; // pixels + S32 mMaxWidth; bool mIsTooltipPastable; }; @@ -136,44 +136,44 @@ protected: 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> { - LLSINGLETON(LLToolTipMgr); - LOG_CLASS(LLToolTipMgr); + LLSINGLETON(LLToolTipMgr); + LOG_CLASS(LLToolTipMgr); public: - void show(const LLToolTip::Params& params); - void show(const std::string& message, bool allow_paste_tooltip = false); + void show(const LLToolTip::Params& params); + void show(const std::string& message, bool allow_paste_tooltip = false); - void unblockToolTips(); - void blockToolTips(); + void unblockToolTips(); + void blockToolTips(); - void hideToolTips(); - bool toolTipVisible(); - LLRect getToolTipRect(); - LLRect getMouseNearRect(); - void updateToolTipVisibility(); + void hideToolTips(); + bool toolTipVisible(); + LLRect getToolTipRect(); + LLRect getMouseNearRect(); + void updateToolTipVisibility(); - void getToolTipMessage(std::string & message); + void getToolTipMessage(std::string & message); bool isTooltipPastable(); private: - void createToolTip(const LLToolTip::Params& params); + void createToolTip(const LLToolTip::Params& params); - bool mToolTipsBlocked; - class LLToolTip* mToolTip; + bool mToolTipsBlocked; + class LLToolTip* mToolTip; - // tooltip creation is deferred until the UI is drawn every frame - // so the last tooltip to be created in a given frame will win - LLToolTip::Params mLastToolTipParams; // description of last tooltip we showed - LLToolTip::Params mNextToolTipParams; // description of next tooltip we want to show - bool mNeedsToolTip; // do we want to show a tooltip + // tooltip creation is deferred until the UI is drawn every frame + // so the last tooltip to be created in a given frame will win + LLToolTip::Params mLastToolTipParams; // description of last tooltip we showed + LLToolTip::Params mNextToolTipParams; // description of next tooltip we want to show + bool mNeedsToolTip; // do we want to show a tooltip - LLRect mMouseNearRect; + LLRect mMouseNearRect; }; // diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index a1ef34159d..6c7e472a87 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,7 +28,7 @@ #include "lltrans.h" -#include "llfasttimer.h" // for call count statistics +#include "llfasttimer.h" // for call count statistics #include "llxuiparser.h" #include "llsd.h" #include "llxmlnode.h" @@ -41,307 +41,307 @@ LLStringUtil::format_map_t LLTrans::sDefaultArgs; struct StringDef : public LLInitParam::Block<StringDef> { - Mandatory<std::string> name; - Mandatory<std::string> value; + Mandatory<std::string> name; + Mandatory<std::string> value; - StringDef() - : name("name"), - value("value") - {} + StringDef() + : name("name"), + value("value") + {} }; struct StringTable : public LLInitParam::Block<StringTable> { - Multiple<StringDef> strings; - StringTable() - : strings("string") - {} + Multiple<StringDef> strings; + StringTable() + : strings("string") + {} }; -//static +//static bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args) { - std::string xml_filename = "(strings file)"; - if (!root->hasName("strings")) - { - LL_ERRS() << "Invalid root node name in " << xml_filename - << ": was " << root->getName() << ", expected \"strings\"" << LL_ENDL; - } - - StringTable string_table; - LLXUIParser parser; - parser.readXUI(root, string_table, xml_filename); - - if (!string_table.validateBlock()) - { - LL_ERRS() << "Problem reading strings: " << xml_filename << LL_ENDL; - return false; - } - static bool default_strings_init = false; - sStringTemplates.clear(); - sDefaultArgs.clear(); - - for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); - it != string_table.strings.end(); - ++it) - { - LLTransTemplate xml_template(it->name, it->value); - sStringTemplates[xml_template.mName] = xml_template; - if (!default_strings_init) - { - sDefaultStringTemplates[xml_template.mName] = xml_template; - } - std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName); - if (iter != default_args.end()) - { - std::string name = *iter; - if (name[0] != '[') - name = llformat("[%s]",name.c_str()); - sDefaultArgs[name] = xml_template.mText; - } - } - default_strings_init = true; - - return true; + std::string xml_filename = "(strings file)"; + if (!root->hasName("strings")) + { + LL_ERRS() << "Invalid root node name in " << xml_filename + << ": was " << root->getName() << ", expected \"strings\"" << LL_ENDL; + } + + StringTable string_table; + LLXUIParser parser; + parser.readXUI(root, string_table, xml_filename); + + if (!string_table.validateBlock()) + { + LL_ERRS() << "Problem reading strings: " << xml_filename << LL_ENDL; + return false; + } + static bool default_strings_init = false; + sStringTemplates.clear(); + sDefaultArgs.clear(); + + for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); + it != string_table.strings.end(); + ++it) + { + LLTransTemplate xml_template(it->name, it->value); + sStringTemplates[xml_template.mName] = xml_template; + if (!default_strings_init) + { + sDefaultStringTemplates[xml_template.mName] = xml_template; + } + std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName); + if (iter != default_args.end()) + { + std::string name = *iter; + if (name[0] != '[') + name = llformat("[%s]",name.c_str()); + sDefaultArgs[name] = xml_template.mText; + } + } + default_strings_init = true; + + return true; } //static bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) { - std::string xml_filename = "(language strings file)"; - if (!root->hasName("strings")) - { - LL_ERRS() << "Invalid root node name in " << xml_filename - << ": was " << root->getName() << ", expected \"strings\"" << LL_ENDL; - } - - StringTable string_table; - LLXUIParser parser; - parser.readXUI(root, string_table, xml_filename); - - if (!string_table.validateBlock()) - { - LL_ERRS() << "Problem reading strings: " << xml_filename << LL_ENDL; - return false; - } - - for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); - it != string_table.strings.end(); - ++it) - { - // share the same map with parseStrings() so we can search the strings using the same getString() function.- angela - LLTransTemplate xml_template(it->name, it->value); - sStringTemplates[xml_template.mName] = xml_template; - } - - return true; + std::string xml_filename = "(language strings file)"; + if (!root->hasName("strings")) + { + LL_ERRS() << "Invalid root node name in " << xml_filename + << ": was " << root->getName() << ", expected \"strings\"" << LL_ENDL; + } + + StringTable string_table; + LLXUIParser parser; + parser.readXUI(root, string_table, xml_filename); + + if (!string_table.validateBlock()) + { + LL_ERRS() << "Problem reading strings: " << xml_filename << LL_ENDL; + return false; + } + + for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); + it != string_table.strings.end(); + ++it) + { + // share the same map with parseStrings() so we can search the strings using the same getString() function.- angela + LLTransTemplate xml_template(it->name, it->value); + sStringTemplates[xml_template.mName] = xml_template; + } + + return true; } static LLTrace::BlockTimerStatHandle FTM_GET_TRANS("Translate string"); -//static +//static std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args, bool def_string) { - // Don't care about time as much as call count. Make sure we're not - // calling LLTrans::getString() in an inner loop. JC - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - - if (def_string) - { - return getDefString(xml_desc, msg_args); - } - - template_map_t::iterator iter = sStringTemplates.find(xml_desc); - if (iter != sStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format_map_t args = sDefaultArgs; - args.insert(msg_args.begin(), msg_args.end()); - LLStringUtil::format(text, args); - - return text; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return "MissingString("+xml_desc+")"; - } + // Don't care about time as much as call count. Make sure we're not + // calling LLTrans::getString() in an inner loop. JC + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (def_string) + { + return getDefString(xml_desc, msg_args); + } + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format_map_t args = sDefaultArgs; + args.insert(msg_args.begin(), msg_args.end()); + LLStringUtil::format(text, args); + + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString("+xml_desc+")"; + } } -//static +//static std::string LLTrans::getDefString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) { - template_map_t::iterator iter = sDefaultStringTemplates.find(xml_desc); - if (iter != sDefaultStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format_map_t args = sDefaultArgs; - args.insert(msg_args.begin(), msg_args.end()); - LLStringUtil::format(text, args); - - return text; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return "MissingString(" + xml_desc + ")"; - } + template_map_t::iterator iter = sDefaultStringTemplates.find(xml_desc); + if (iter != sDefaultStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format_map_t args = sDefaultArgs; + args.insert(msg_args.begin(), msg_args.end()); + LLStringUtil::format(text, args); + + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString(" + xml_desc + ")"; + } } //static std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args, bool def_string) { - // Don't care about time as much as call count. Make sure we're not - // calling LLTrans::getString() in an inner loop. JC - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - - if (def_string) - { - return getDefString(xml_desc, msg_args); - } - - template_map_t::iterator iter = sStringTemplates.find(xml_desc); - if (iter != sStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format(text, msg_args); - return text; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return "MissingString("+xml_desc+")"; - } + // Don't care about time as much as call count. Make sure we're not + // calling LLTrans::getString() in an inner loop. JC + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (def_string) + { + return getDefString(xml_desc, msg_args); + } + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format(text, msg_args); + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString("+xml_desc+")"; + } } //static std::string LLTrans::getDefString(const std::string &xml_desc, const LLSD& msg_args) { - template_map_t::iterator iter = sDefaultStringTemplates.find(xml_desc); - if (iter != sDefaultStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format(text, msg_args); - return text; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return "MissingString(" + xml_desc + ")"; - } + template_map_t::iterator iter = sDefaultStringTemplates.find(xml_desc); + if (iter != sDefaultStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format(text, msg_args); + return text; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return "MissingString(" + xml_desc + ")"; + } } -//static +//static bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - - template_map_t::iterator iter = sStringTemplates.find(xml_desc); - if (iter != sStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format_map_t args = sDefaultArgs; - args.insert(msg_args.begin(), msg_args.end()); - LLStringUtil::format(text, args); - result = text; - return true; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return false; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format_map_t args = sDefaultArgs; + args.insert(msg_args.begin(), msg_args.end()); + LLStringUtil::format(text, args); + result = text; + return true; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return false; + } } //static bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - - template_map_t::iterator iter = sStringTemplates.find(xml_desc); - if (iter != sStringTemplates.end()) - { - std::string text = iter->second.mText; - LLStringUtil::format(text, msg_args); - result = text; - return true; - } - else - { - LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; - return false; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + template_map_t::iterator iter = sStringTemplates.find(xml_desc); + if (iter != sStringTemplates.end()) + { + std::string text = iter->second.mText; + LLStringUtil::format(text, msg_args); + result = text; + return true; + } + else + { + LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; + return false; + } } //static std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count) { - // Compute which string identifier to use - const char* form = ""; - if (language == "ru") // Russian - { - // From GNU ngettext() - // Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; - if (count % 10 == 1 - && count % 100 != 11) - { - // singular, "1 item" - form = "A"; - } - else if (count % 10 >= 2 - && count % 10 <= 4 - && (count % 100 < 10 || count % 100 >= 20) ) - { - // special case "2 items", "23 items", but not "13 items" - form = "B"; - } - else - { - // English-style plural, "5 items" - form = "C"; - } - } - else if (language == "fr" || language == "pt") // French, Brazilian Portuguese - { - // French and Portuguese treat zero as a singular "0 item" not "0 items" - if (count == 0 || count == 1) - { - form = "A"; - } - else - { - // English-style plural - form = "B"; - } - } - else // default - { - // languages like English with 2 forms, singular and plural - if (count == 1) - { - // "1 item" - form = "A"; - } - else - { - // "2 items", also use plural for "0 items" - form = "B"; - } - } - - // Translate that string - LLStringUtil::format_map_t args; - args["[COUNT]"] = llformat("%d", count); - - // Look up "AgeYearsB" or "AgeWeeksC" including the "form" - std::string key = llformat("%s%s", xml_desc.c_str(), form); - return getString(key, args); + // Compute which string identifier to use + const char* form = ""; + if (language == "ru") // Russian + { + // From GNU ngettext() + // Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + if (count % 10 == 1 + && count % 100 != 11) + { + // singular, "1 item" + form = "A"; + } + else if (count % 10 >= 2 + && count % 10 <= 4 + && (count % 100 < 10 || count % 100 >= 20) ) + { + // special case "2 items", "23 items", but not "13 items" + form = "B"; + } + else + { + // English-style plural, "5 items" + form = "C"; + } + } + else if (language == "fr" || language == "pt") // French, Brazilian Portuguese + { + // French and Portuguese treat zero as a singular "0 item" not "0 items" + if (count == 0 || count == 1) + { + form = "A"; + } + else + { + // English-style plural + form = "B"; + } + } + else // default + { + // languages like English with 2 forms, singular and plural + if (count == 1) + { + // "1 item" + form = "A"; + } + else + { + // "2 items", also use plural for "0 items" + form = "B"; + } + } + + // Translate that string + LLStringUtil::format_map_t args; + args["[COUNT]"] = llformat("%d", count); + + // Look up "AgeYearsB" or "AgeWeeksC" including the "form" + std::string key = llformat("%s%s", xml_desc.c_str(), form); + return getString(key, args); } void LLTrans::setDefaultArg(const std::string& name, const std::string& value) { - sDefaultArgs[name] = value; + sDefaultArgs[name] = value; } diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h index 9bd751fc78..4f38ef9067 100644 --- a/indra/llui/lltrans.h +++ b/indra/llui/lltrans.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,10 +43,10 @@ class LLSD; class LLTransTemplate { public: - LLTransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {} + LLTransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {} - std::string mName; - std::string mText; + std::string mName; + std::string mText; }; /** @@ -58,80 +58,80 @@ public: class LLTrans { public: - LLTrans(); - - /** - * @brief Parses the xml root that holds the strings. Used once on startup -// *FIXME * @param xml_filename Filename to parse - * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" - * @returns true if the file was parsed successfully, true if something went wrong - */ - static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); - - static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); - - /** - * @brief Returns a translated string - * @param xml_desc String's description - * @param args A list of substrings to replace in the string - * @returns Translated string - */ - static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args, bool def_string = false); - static std::string getDefString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); - static std::string getString(const std::string &xml_desc, const LLSD& args, bool def_string = false); - static std::string getDefString(const std::string &xml_desc, const LLSD& args); - static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args); - static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args); - - // Returns translated string with [COUNT] replaced with a number, following - // special per-language logic for plural nouns. For example, some languages - // may have different plurals for 0, 1, 2 and > 2. - // See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. - static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); - - /** - * @brief Returns a translated string - * @param xml_desc String's description - * @returns Translated string - */ - static std::string getString(const std::string &xml_desc, bool def_string = false) - { - LLStringUtil::format_map_t empty; - return getString(xml_desc, empty); - } - - static bool findString(std::string &result, const std::string &xml_desc) - { - LLStringUtil::format_map_t empty; - return findString(result, xml_desc, empty); - } - - static std::string getKeyboardString(const char* keystring) - { - std::string key_str(keystring); - std::string trans_str; - return findString(trans_str, key_str) ? trans_str : key_str; - } - - // get the default args - static const LLStringUtil::format_map_t& getDefaultArgs() - { - return sDefaultArgs; - } - - static void setDefaultArg(const std::string& name, const std::string& value); - - // insert default args into an arg list - static void getArgs(LLStringUtil::format_map_t& args) - { - args.insert(sDefaultArgs.begin(), sDefaultArgs.end()); - } - + LLTrans(); + + /** + * @brief Parses the xml root that holds the strings. Used once on startup +// *FIXME * @param xml_filename Filename to parse + * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" + * @returns true if the file was parsed successfully, true if something went wrong + */ + static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); + + static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); + + /** + * @brief Returns a translated string + * @param xml_desc String's description + * @param args A list of substrings to replace in the string + * @returns Translated string + */ + static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args, bool def_string = false); + static std::string getDefString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); + static std::string getString(const std::string &xml_desc, const LLSD& args, bool def_string = false); + static std::string getDefString(const std::string &xml_desc, const LLSD& args); + static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args); + static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args); + + // Returns translated string with [COUNT] replaced with a number, following + // special per-language logic for plural nouns. For example, some languages + // may have different plurals for 0, 1, 2 and > 2. + // See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. + static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); + + /** + * @brief Returns a translated string + * @param xml_desc String's description + * @returns Translated string + */ + static std::string getString(const std::string &xml_desc, bool def_string = false) + { + LLStringUtil::format_map_t empty; + return getString(xml_desc, empty); + } + + static bool findString(std::string &result, const std::string &xml_desc) + { + LLStringUtil::format_map_t empty; + return findString(result, xml_desc, empty); + } + + static std::string getKeyboardString(const char* keystring) + { + std::string key_str(keystring); + std::string trans_str; + return findString(trans_str, key_str) ? trans_str : key_str; + } + + // get the default args + static const LLStringUtil::format_map_t& getDefaultArgs() + { + return sDefaultArgs; + } + + static void setDefaultArg(const std::string& name, const std::string& value); + + // insert default args into an arg list + static void getArgs(LLStringUtil::format_map_t& args) + { + args.insert(sDefaultArgs.begin(), sDefaultArgs.end()); + } + private: - typedef std::map<std::string, LLTransTemplate > template_map_t; - static template_map_t sStringTemplates; - static template_map_t sDefaultStringTemplates; - static LLStringUtil::format_map_t sDefaultArgs; + typedef std::map<std::string, LLTransTemplate > template_map_t; + static template_map_t sStringTemplates; + static template_map_t sDefaultStringTemplates; + static LLStringUtil::format_map_t sDefaultArgs; }; #endif diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index 6c486f29ba..3d3a7ddf4e 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,40 +35,40 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args) { - LLXMLNodePtr root; - // Pass LLDir::ALL_SKINS to load a composite of all the individual string - // definitions in the default skin and the current skin. This means an - // individual skin can provide an xml_filename that overrides only a - // subset of the available string definitions; any string definition not - // overridden by that skin will be sought in the default skin. - bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS); - if (!success) - { + LLXMLNodePtr root; + // Pass LLDir::ALL_SKINS to load a composite of all the individual string + // definitions in the default skin and the current skin. This means an + // individual skin can provide an xml_filename that overrides only a + // subset of the available string definitions; any string definition not + // overridden by that skin will be sought in the default skin. + bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS); + if (!success) + { const std::string error_string = "Second Life viewer couldn't access some of the files it needs and will be closed." "\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and " "contact https://support.secondlife.com if issue persists after reinstall."; LLError::LLUserWarningMsg::show(error_string); - gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); - LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL; - return false; - } + gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); + LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL; + return false; + } - return LLTrans::parseStrings(root, default_args); + return LLTrans::parseStrings(root, default_args); } bool LLTransUtil::parseLanguageStrings(const std::string& xml_filename) { - LLXMLNodePtr root; - BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); - - if (!success) - { + LLXMLNodePtr root; + BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); + + if (!success) + { LLError::LLUserWarningMsg::showMissingFiles(); - LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL; - return false; - } - - return LLTrans::parseLanguageStrings(root); + LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL; + return false; + } + + return LLTrans::parseLanguageStrings(root); } diff --git a/indra/llui/lltransutil.h b/indra/llui/lltransutil.h index 9c7cee3f6f..96ef14ce1d 100644 --- a/indra/llui/lltransutil.h +++ b/indra/llui/lltransutil.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,15 +31,15 @@ namespace LLTransUtil { - /** - * @brief Parses the xml file that holds the strings. Used once on startup - * @param xml_filename Filename to parse - * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" - * @returns true if the file was parsed successfully, true if something went wrong - */ - bool parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args); + /** + * @brief Parses the xml file that holds the strings. Used once on startup + * @param xml_filename Filename to parse + * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" + * @returns true if the file was parsed successfully, true if something went wrong + */ + bool parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args); - bool parseLanguageStrings(const std::string& xml_filename); + bool parseLanguageStrings(const std::string& xml_filename); }; #endif diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 3f3ec7ee8b..c7539fcec7 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llui.cpp * @brief UI implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -91,64 +91,64 @@ static LLDefaultChildRegistry::Register<LLToolBar> register_toolbar("toolbar"); LLUUID find_ui_sound(const char * namep) { - std::string name = ll_safe_string(namep); - LLUUID uuid = LLUUID(NULL); - LLUI *ui_inst = LLUI::getInstance(); - if (!ui_inst->mSettingGroups["config"]->controlExists(name)) - { - LL_WARNS() << "tried to make UI sound for unknown sound name: " << name << LL_ENDL; - } - else - { - uuid = LLUUID(ui_inst->mSettingGroups["config"]->getString(name)); - if (uuid.isNull()) - { - if (ui_inst->mSettingGroups["config"]->getString(name) == LLUUID::null.asString()) - { - if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) - { - LL_INFOS() << "UI sound name: " << name << " triggered but silent (null uuid)" << LL_ENDL; - } - } - else - { - LL_WARNS() << "UI sound named: " << name << " does not translate to a valid uuid" << LL_ENDL; - } - } - else if (ui_inst->mAudioCallback != NULL) - { - if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) - { - LL_INFOS() << "UI sound name: " << name << LL_ENDL; - } - } - } - - return uuid; + std::string name = ll_safe_string(namep); + LLUUID uuid = LLUUID(NULL); + LLUI *ui_inst = LLUI::getInstance(); + if (!ui_inst->mSettingGroups["config"]->controlExists(name)) + { + LL_WARNS() << "tried to make UI sound for unknown sound name: " << name << LL_ENDL; + } + else + { + uuid = LLUUID(ui_inst->mSettingGroups["config"]->getString(name)); + if (uuid.isNull()) + { + if (ui_inst->mSettingGroups["config"]->getString(name) == LLUUID::null.asString()) + { + if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) + { + LL_INFOS() << "UI sound name: " << name << " triggered but silent (null uuid)" << LL_ENDL; + } + } + else + { + LL_WARNS() << "UI sound named: " << name << " does not translate to a valid uuid" << LL_ENDL; + } + } + else if (ui_inst->mAudioCallback != NULL) + { + if (ui_inst->mSettingGroups["config"]->getBOOL("UISndDebugSpamToggle")) + { + LL_INFOS() << "UI sound name: " << name << LL_ENDL; + } + } + } + + return uuid; } void make_ui_sound(const char* namep) { - LLUUID soundUUID = find_ui_sound(namep); - if(soundUUID.notNull()) - { - LLUI::getInstance()->mAudioCallback(soundUUID); - } + LLUUID soundUUID = find_ui_sound(namep); + if(soundUUID.notNull()) + { + LLUI::getInstance()->mAudioCallback(soundUUID); + } } void make_ui_sound_deferred(const char* namep) { - LLUUID soundUUID = find_ui_sound(namep); - if(soundUUID.notNull()) - { - LLUI::getInstance()->mDeferredAudioCallback(soundUUID); - } + LLUUID soundUUID = find_ui_sound(namep); + if(soundUUID.notNull()) + { + LLUI::getInstance()->mDeferredAudioCallback(soundUUID); + } } LLUI::LLUI(const settings_map_t& settings, - LLImageProviderInterface* image_provider, - LLUIAudioCallback audio_callback, - LLUIAudioCallback deferred_audio_callback) + LLImageProviderInterface* image_provider, + LLUIAudioCallback audio_callback, + LLUIAudioCallback deferred_audio_callback) : mSettingGroups(settings), mAudioCallback(audio_callback), mDeferredAudioCallback(deferred_audio_callback), @@ -156,51 +156,51 @@ mWindow(NULL), // set later in startup mRootView(NULL), mHelpImpl(NULL) { - LLRender2D::initParamSingleton(image_provider); - - if ((get_ptr_in_map(mSettingGroups, std::string("config")) == NULL) || - (get_ptr_in_map(mSettingGroups, std::string("floater")) == NULL) || - (get_ptr_in_map(mSettingGroups, std::string("ignores")) == NULL)) - { - LL_ERRS() << "Failure to initialize configuration groups" << LL_ENDL; - } - - LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow"); - - LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); - - // Callbacks for associating controls with floater visibility: - reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD())); - reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD())); - reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE)); - reg.add("Floater.ShowOrBringToFront", boost::bind(&LLFloaterReg::showInstanceOrBringToFront, _2, LLSD())); - reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD())); - - // Button initialization callback for toggle buttons - reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); - - // Button initialization callback for toggle buttons on dockable floaters - reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2)); - - // Display the help topic for the current context - reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2)); - - // Currently unused, but kept for reference: - reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); - - // Used by menus along with Floater.Toggle to display visibility as a check-mark - LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); - LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); - - // Parse the master list of commands - LLCommandManager::load(); + LLRender2D::initParamSingleton(image_provider); + + if ((get_ptr_in_map(mSettingGroups, std::string("config")) == NULL) || + (get_ptr_in_map(mSettingGroups, std::string("floater")) == NULL) || + (get_ptr_in_map(mSettingGroups, std::string("ignores")) == NULL)) + { + LL_ERRS() << "Failure to initialize configuration groups" << LL_ENDL; + } + + LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow"); + + LLUICtrl::CommitCallbackRegistry::Registrar& reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar(); + + // Callbacks for associating controls with floater visibility: + reg.add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleInstance, _2, LLSD())); + reg.add("Floater.ToggleOrBringToFront", boost::bind(&LLFloaterReg::toggleInstanceOrBringToFront, _2, LLSD())); + reg.add("Floater.Show", boost::bind(&LLFloaterReg::showInstance, _2, LLSD(), FALSE)); + reg.add("Floater.ShowOrBringToFront", boost::bind(&LLFloaterReg::showInstanceOrBringToFront, _2, LLSD())); + reg.add("Floater.Hide", boost::bind(&LLFloaterReg::hideInstance, _2, LLSD())); + + // Button initialization callback for toggle buttons + reg.add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2)); + + // Button initialization callback for toggle buttons on dockable floaters + reg.add("Button.SetDockableFloaterToggle", boost::bind(&LLButton::setDockableFloaterToggle, _1, _2)); + + // Display the help topic for the current context + reg.add("Button.ShowHelp", boost::bind(&LLButton::showHelp, _1, _2)); + + // Currently unused, but kept for reference: + reg.add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2)); + + // Used by menus along with Floater.Toggle to display visibility as a check-mark + LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); + LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); + + // Parse the master list of commands + LLCommandManager::load(); } void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups) { - mAddPopupFunc = add_popup; - mRemovePopupFunc = remove_popup; - mClearPopupsFunc = clear_popups; + mAddPopupFunc = add_popup; + mRemovePopupFunc = remove_popup; + mClearPopupsFunc = clear_popups; } void LLUI::setMousePositionScreen(S32 x, S32 y) @@ -212,60 +212,60 @@ void LLUI::setMousePositionScreen(S32 x, S32 y) S32 screen_x = ll_round((F32)x * getScaleFactor().mV[VX]); S32 screen_y = ll_round((F32)y * getScaleFactor().mV[VY]); #endif - - LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); + + LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); } void LLUI::getMousePositionScreen(S32 *x, S32 *y) { - LLCoordWindow cursor_pos_window; - getWindow()->getCursorPosition(&cursor_pos_window); - LLCoordGL cursor_pos_gl(cursor_pos_window.convert()); - *x = ll_round((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]); - *y = ll_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VY]); + LLCoordWindow cursor_pos_window; + getWindow()->getCursorPosition(&cursor_pos_window); + LLCoordGL cursor_pos_gl(cursor_pos_window.convert()); + *x = ll_round((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]); + *y = ll_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VY]); } void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y) { - S32 screen_x, screen_y; - viewp->localPointToScreen(x, y, &screen_x, &screen_y); + S32 screen_x, screen_y; + viewp->localPointToScreen(x, y, &screen_x, &screen_y); - setMousePositionScreen(screen_x, screen_y); + setMousePositionScreen(screen_x, screen_y); } void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y) { - S32 screen_x, screen_y; - getMousePositionScreen(&screen_x, &screen_y); - viewp->screenPointToLocal(screen_x, screen_y, x, y); + S32 screen_x, screen_y; + getMousePositionScreen(&screen_x, &screen_y); + viewp->screenPointToLocal(screen_x, screen_y, x, y); } // On Windows, the user typically sets the language when they install the // app (by running it with a shortcut that sets InstallLanguage). On Mac, -// or on Windows if the SecondLife.exe executable is run directly, the +// or on Windows if the SecondLife.exe executable is run directly, the // language follows the OS language. In all cases the user can override // the language manually in preferences. JC std::string LLUI::getUILanguage() { - std::string language = "en"; - if (mSettingGroups["config"]) - { - language = mSettingGroups["config"]->getString("Language"); - if (language.empty() || language == "default") - { - language = mSettingGroups["config"]->getString("InstallLanguage"); - } - if (language.empty() || language == "default") - { - language = mSettingGroups["config"]->getString("SystemLanguage"); - } - if (language.empty() || language == "default") - { - language = "en"; - } - } - return language; + std::string language = "en"; + if (mSettingGroups["config"]) + { + language = mSettingGroups["config"]->getString("Language"); + if (language.empty() || language == "default") + { + language = mSettingGroups["config"]->getString("InstallLanguage"); + } + if (language.empty() || language == "default") + { + language = mSettingGroups["config"]->getString("SystemLanguage"); + } + if (language.empty() || language == "default") + { + language = "en"; + } + } + return language; } // static @@ -277,224 +277,224 @@ std::string LLUI::getLanguage() struct SubDir : public LLInitParam::Block<SubDir> { - Mandatory<std::string> value; + Mandatory<std::string> value; - SubDir() - : value("value") - {} + SubDir() + : value("value") + {} }; struct Directory : public LLInitParam::Block<Directory> { - Multiple<SubDir, AtLeast<1> > subdirs; + Multiple<SubDir, AtLeast<1> > subdirs; - Directory() - : subdirs("subdir") - {} + Directory() + : subdirs("subdir") + {} }; struct Paths : public LLInitParam::Block<Paths> { - Multiple<Directory, AtLeast<1> > directories; + Multiple<Directory, AtLeast<1> > directories; - Paths() - : directories("directory") - {} + Paths() + : directories("directory") + {} }; //static std::string LLUI::locateSkin(const std::string& filename) { - std::string found_file = filename; - if (gDirUtilp->fileExists(found_file)) - { - return found_file; - } - - found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS? - if (gDirUtilp->fileExists(found_file)) - { - return found_file; - } - - found_file = gDirUtilp->findSkinnedFilename(LLDir::XUI, filename); - if (! found_file.empty()) - { - return found_file; - } - - found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename); - if (gDirUtilp->fileExists(found_file)) - { - return found_file; - } - LL_WARNS("LLUI") << "Can't find '" << filename - << "' in user settings, any skin directory or app_settings" << LL_ENDL; - return ""; + std::string found_file = filename; + if (gDirUtilp->fileExists(found_file)) + { + return found_file; + } + + found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS? + if (gDirUtilp->fileExists(found_file)) + { + return found_file; + } + + found_file = gDirUtilp->findSkinnedFilename(LLDir::XUI, filename); + if (! found_file.empty()) + { + return found_file; + } + + found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename); + if (gDirUtilp->fileExists(found_file)) + { + return found_file; + } + LL_WARNS("LLUI") << "Can't find '" << filename + << "' in user settings, any skin directory or app_settings" << LL_ENDL; + return ""; } LLVector2 LLUI::getWindowSize() { - LLCoordWindow window_rect; - mWindow->getSize(&window_rect); + LLCoordWindow window_rect; + mWindow->getSize(&window_rect); - return LLVector2(window_rect.mX / getScaleFactor().mV[VX], window_rect.mY / getScaleFactor().mV[VY]); + return LLVector2(window_rect.mX / getScaleFactor().mV[VX], window_rect.mY / getScaleFactor().mV[VY]); } void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y) { - *gl_x = ll_round((F32)screen_x * getScaleFactor().mV[VX]); - *gl_y = ll_round((F32)screen_y * getScaleFactor().mV[VY]); + *gl_x = ll_round((F32)screen_x * getScaleFactor().mV[VX]); + *gl_y = ll_round((F32)screen_y * getScaleFactor().mV[VY]); } void LLUI::glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y) { - *screen_x = ll_round((F32)gl_x / getScaleFactor().mV[VX]); - *screen_y = ll_round((F32)gl_y / getScaleFactor().mV[VY]); + *screen_x = ll_round((F32)gl_x / getScaleFactor().mV[VX]); + *screen_y = ll_round((F32)gl_y / getScaleFactor().mV[VY]); } void LLUI::screenRectToGL(const LLRect& screen, LLRect *gl) { - screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop); - screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom); + screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop); + screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom); } void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen) { - glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop); - glPointToScreen(gl.mRight, gl.mBottom, &screen->mRight, &screen->mBottom); + glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop); + glPointToScreen(gl.mRight, gl.mBottom, &screen->mRight, &screen->mBottom); } LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) { - for (settings_map_t::iterator itor = mSettingGroups.begin(); - itor != mSettingGroups.end(); ++itor) - { - LLControlGroup* control_group = itor->second; - if(control_group != NULL) - { - if (control_group->controlExists(controlname)) - return *control_group; - } - } - - return *mSettingGroups["config"]; // default group + for (settings_map_t::iterator itor = mSettingGroups.begin(); + itor != mSettingGroups.end(); ++itor) + { + LLControlGroup* control_group = itor->second; + if(control_group != NULL) + { + if (control_group->controlExists(controlname)) + return *control_group; + } + } + + return *mSettingGroups["config"]; // default group } void LLUI::addPopup(LLView* viewp) { - if (mAddPopupFunc) - { - mAddPopupFunc(viewp); - } + if (mAddPopupFunc) + { + mAddPopupFunc(viewp); + } } void LLUI::removePopup(LLView* viewp) { - if (mRemovePopupFunc) - { - mRemovePopupFunc(viewp); - } + if (mRemovePopupFunc) + { + mRemovePopupFunc(viewp); + } } void LLUI::clearPopups() { - if (mClearPopupsFunc) - { - mClearPopupsFunc(); - } + if (mClearPopupsFunc) + { + mClearPopupsFunc(); + } } void LLUI::reportBadKeystroke() { - make_ui_sound("UISndBadKeystroke"); + make_ui_sound("UISndBadKeystroke"); } // spawn_x and spawn_y are top left corner of view in screen GL coordinates void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) { - const S32 CURSOR_HEIGHT = 16; // Approximate "normal" cursor size - const S32 CURSOR_WIDTH = 8; - - LLView* parent = view->getParent(); - - S32 mouse_x; - S32 mouse_y; - getMousePositionScreen(&mouse_x, &mouse_y); - - // If no spawn location provided, use mouse position - if (spawn_x == S32_MAX || spawn_y == S32_MAX) - { - spawn_x = mouse_x + CURSOR_WIDTH; - spawn_y = mouse_y - CURSOR_HEIGHT; - } - - LLRect virtual_window_rect = parent->getLocalRect(); - - LLRect mouse_rect; - const S32 MOUSE_CURSOR_PADDING = 1; - mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, - mouse_y + MOUSE_CURSOR_PADDING, - CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, - CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); - - S32 local_x, local_y; - // convert screen coordinates to tooltip view-local coordinates - parent->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y); - - // Start at spawn position (using left/top) - view->setOrigin( local_x, local_y - view->getRect().getHeight()); - // Make sure we're on-screen and not overlapping the mouse - view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect ); + const S32 CURSOR_HEIGHT = 16; // Approximate "normal" cursor size + const S32 CURSOR_WIDTH = 8; + + LLView* parent = view->getParent(); + + S32 mouse_x; + S32 mouse_y; + getMousePositionScreen(&mouse_x, &mouse_y); + + // If no spawn location provided, use mouse position + if (spawn_x == S32_MAX || spawn_y == S32_MAX) + { + spawn_x = mouse_x + CURSOR_WIDTH; + spawn_y = mouse_y - CURSOR_HEIGHT; + } + + LLRect virtual_window_rect = parent->getLocalRect(); + + LLRect mouse_rect; + const S32 MOUSE_CURSOR_PADDING = 1; + mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, + mouse_y + MOUSE_CURSOR_PADDING, + CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, + CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2); + + S32 local_x, local_y; + // convert screen coordinates to tooltip view-local coordinates + parent->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y); + + // Start at spawn position (using left/top) + view->setOrigin( local_x, local_y - view->getRect().getHeight()); + // Make sure we're on-screen and not overlapping the mouse + view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect ); } LLView* LLUI::resolvePath(LLView* context, const std::string& path) { - // Nothing about resolvePath() should require non-const LLView*. If caller - // wants non-const, call the const flavor and then cast away const-ness. - return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path)); + // Nothing about resolvePath() should require non-const LLView*. If caller + // wants non-const, call the const flavor and then cast away const-ness. + return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path)); } const LLView* LLUI::resolvePath(const LLView* context, const std::string& path) { - // Create an iterator over slash-separated parts of 'path'. Dereferencing - // this iterator returns an iterator_range over the substring. Unlike - // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent - // delimiters: leading/trailing slash produces an empty substring, double - // slash produces an empty substring. That's what we need. - boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend; - - if (ti == tend) - { - // 'path' is completely empty, no navigation - return context; - } - - // leading / means "start at root" - if (ti->empty()) - { - context = getRootView(); - ++ti; - } - - bool recurse = false; - for (; ti != tend && context; ++ti) - { - if (ti->empty()) - { - recurse = true; - } - else - { - std::string part(ti->begin(), ti->end()); - context = context->findChildView(LLURI::unescape(part), recurse); - recurse = false; - } - } - - return context; + // Create an iterator over slash-separated parts of 'path'. Dereferencing + // this iterator returns an iterator_range over the substring. Unlike + // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent + // delimiters: leading/trailing slash produces an empty substring, double + // slash produces an empty substring. That's what we need. + boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend; + + if (ti == tend) + { + // 'path' is completely empty, no navigation + return context; + } + + // leading / means "start at root" + if (ti->empty()) + { + context = getRootView(); + ++ti; + } + + bool recurse = false; + for (; ti != tend && context; ++ti) + { + if (ti->empty()) + { + recurse = true; + } + else + { + std::string part(ti->begin(), ti->end()); + context = context->findChildView(LLURI::unescape(part), recurse); + recurse = false; + } + } + + return context; } //static @@ -514,225 +514,225 @@ void LLUI::setScaleFactor(const LLVector2& scale_factor) namespace LLInitParam { - ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) - : super_t(color), - red("red"), - green("green"), - blue("blue"), - alpha("alpha"), - control("") - { - updateBlockFromValue(false); - } - - void ParamValue<LLUIColor>::updateValueFromBlock() - { - if (control.isProvided() && !control().empty()) - { - updateValue(LLUIColorTable::instance().getColor(control)); - } - else - { - updateValue(LLColor4(red, green, blue, alpha)); - } - } - - void ParamValue<LLUIColor>::updateBlockFromValue(bool make_block_authoritative) - { - LLColor4 color = getValue(); - red.set(color.mV[VRED], make_block_authoritative); - green.set(color.mV[VGREEN], make_block_authoritative); - blue.set(color.mV[VBLUE], make_block_authoritative); - alpha.set(color.mV[VALPHA], make_block_authoritative); - control.set("", make_block_authoritative); - } - - bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) - { - return !(a->getFontDesc() < b->getFontDesc()) - && !(b->getFontDesc() < a->getFontDesc()); - } - - ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) - : super_t(fontp), - name("name"), - size("size"), - style("style") - { - if (!fontp) - { - updateValue(LLFontGL::getFontDefault()); - } - addSynonym(name, ""); - updateBlockFromValue(false); - } - - void ParamValue<const LLFontGL*>::updateValueFromBlock() - { - const LLFontGL* res_fontp = LLFontGL::getFontByName(name); - if (res_fontp) - { - updateValue(res_fontp); - return; - } - - U8 fontstyle = 0; - fontstyle = LLFontGL::getStyleFromString(style()); - LLFontDescriptor desc(name(), size(), fontstyle); - const LLFontGL* fontp = LLFontGL::getFont(desc); - if (fontp) - { - updateValue(fontp); - } - else - { - updateValue(LLFontGL::getFontDefault()); - } - } - - void ParamValue<const LLFontGL*>::updateBlockFromValue(bool make_block_authoritative) - { - if (getValue()) - { - name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative); - size.set(LLFontGL::sizeFromFont(getValue()), make_block_authoritative); - style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), make_block_authoritative); - } - } - - ParamValue<LLRect>::ParamValue(const LLRect& rect) - : super_t(rect), - left("left"), - top("top"), - right("right"), - bottom("bottom"), - width("width"), - height("height") - { - updateBlockFromValue(false); - } - - void ParamValue<LLRect>::updateValueFromBlock() - { - LLRect rect; - - //calculate from params - // prefer explicit left and right - if (left.isProvided() && right.isProvided()) - { - rect.mLeft = left; - rect.mRight = right; - } - // otherwise use width along with specified side, if any - else if (width.isProvided()) - { - // only right + width provided - if (right.isProvided()) - { - rect.mRight = right; - rect.mLeft = right - width; - } - else // left + width, or just width - { - rect.mLeft = left; - rect.mRight = left + width; - } - } - // just left, just right, or none - else - { - rect.mLeft = left; - rect.mRight = right; - } - - // prefer explicit bottom and top - if (bottom.isProvided() && top.isProvided()) - { - rect.mBottom = bottom; - rect.mTop = top; - } - // otherwise height along with specified side, if any - else if (height.isProvided()) - { - // top + height provided - if (top.isProvided()) - { - rect.mTop = top; - rect.mBottom = top - height; - } - // bottom + height or just height - else - { - rect.mBottom = bottom; - rect.mTop = bottom + height; - } - } - // just bottom, just top, or none - else - { - rect.mBottom = bottom; - rect.mTop = top; - } - updateValue(rect); - } - - void ParamValue<LLRect>::updateBlockFromValue(bool make_block_authoritative) - { - // because of the ambiguity in specifying a rect by position and/or dimensions - // we use the lowest priority pairing so that any valid pairing in xui - // will override those calculated from the rect object - // in this case, that is left+width and bottom+height - LLRect& value = getValue(); - - right.set(value.mRight, false); - left.set(value.mLeft, make_block_authoritative); - width.set(value.getWidth(), make_block_authoritative); - - top.set(value.mTop, false); - bottom.set(value.mBottom, make_block_authoritative); - height.set(value.getHeight(), make_block_authoritative); - } - - ParamValue<LLCoordGL>::ParamValue(const LLCoordGL& coord) - : super_t(coord), - x("x"), - y("y") - { - updateBlockFromValue(false); - } - - void ParamValue<LLCoordGL>::updateValueFromBlock() - { - updateValue(LLCoordGL(x, y)); - } - - void ParamValue<LLCoordGL>::updateBlockFromValue(bool make_block_authoritative) - { - x.set(getValue().mX, make_block_authoritative); - y.set(getValue().mY, make_block_authoritative); - } - - - void TypeValues<LLFontGL::HAlign>::declareValues() - { - declare("left", LLFontGL::LEFT); - declare("right", LLFontGL::RIGHT); - declare("center", LLFontGL::HCENTER); - } - - void TypeValues<LLFontGL::VAlign>::declareValues() - { - declare("top", LLFontGL::TOP); - declare("center", LLFontGL::VCENTER); - declare("baseline", LLFontGL::BASELINE); - declare("bottom", LLFontGL::BOTTOM); - } - - void TypeValues<LLFontGL::ShadowType>::declareValues() - { - declare("none", LLFontGL::NO_SHADOW); - declare("hard", LLFontGL::DROP_SHADOW); - declare("soft", LLFontGL::DROP_SHADOW_SOFT); - } + ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) + : super_t(color), + red("red"), + green("green"), + blue("blue"), + alpha("alpha"), + control("") + { + updateBlockFromValue(false); + } + + void ParamValue<LLUIColor>::updateValueFromBlock() + { + if (control.isProvided() && !control().empty()) + { + updateValue(LLUIColorTable::instance().getColor(control)); + } + else + { + updateValue(LLColor4(red, green, blue, alpha)); + } + } + + void ParamValue<LLUIColor>::updateBlockFromValue(bool make_block_authoritative) + { + LLColor4 color = getValue(); + red.set(color.mV[VRED], make_block_authoritative); + green.set(color.mV[VGREEN], make_block_authoritative); + blue.set(color.mV[VBLUE], make_block_authoritative); + alpha.set(color.mV[VALPHA], make_block_authoritative); + control.set("", make_block_authoritative); + } + + bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) + { + return !(a->getFontDesc() < b->getFontDesc()) + && !(b->getFontDesc() < a->getFontDesc()); + } + + ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) + : super_t(fontp), + name("name"), + size("size"), + style("style") + { + if (!fontp) + { + updateValue(LLFontGL::getFontDefault()); + } + addSynonym(name, ""); + updateBlockFromValue(false); + } + + void ParamValue<const LLFontGL*>::updateValueFromBlock() + { + const LLFontGL* res_fontp = LLFontGL::getFontByName(name); + if (res_fontp) + { + updateValue(res_fontp); + return; + } + + U8 fontstyle = 0; + fontstyle = LLFontGL::getStyleFromString(style()); + LLFontDescriptor desc(name(), size(), fontstyle); + const LLFontGL* fontp = LLFontGL::getFont(desc); + if (fontp) + { + updateValue(fontp); + } + else + { + updateValue(LLFontGL::getFontDefault()); + } + } + + void ParamValue<const LLFontGL*>::updateBlockFromValue(bool make_block_authoritative) + { + if (getValue()) + { + name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative); + size.set(LLFontGL::sizeFromFont(getValue()), make_block_authoritative); + style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), make_block_authoritative); + } + } + + ParamValue<LLRect>::ParamValue(const LLRect& rect) + : super_t(rect), + left("left"), + top("top"), + right("right"), + bottom("bottom"), + width("width"), + height("height") + { + updateBlockFromValue(false); + } + + void ParamValue<LLRect>::updateValueFromBlock() + { + LLRect rect; + + //calculate from params + // prefer explicit left and right + if (left.isProvided() && right.isProvided()) + { + rect.mLeft = left; + rect.mRight = right; + } + // otherwise use width along with specified side, if any + else if (width.isProvided()) + { + // only right + width provided + if (right.isProvided()) + { + rect.mRight = right; + rect.mLeft = right - width; + } + else // left + width, or just width + { + rect.mLeft = left; + rect.mRight = left + width; + } + } + // just left, just right, or none + else + { + rect.mLeft = left; + rect.mRight = right; + } + + // prefer explicit bottom and top + if (bottom.isProvided() && top.isProvided()) + { + rect.mBottom = bottom; + rect.mTop = top; + } + // otherwise height along with specified side, if any + else if (height.isProvided()) + { + // top + height provided + if (top.isProvided()) + { + rect.mTop = top; + rect.mBottom = top - height; + } + // bottom + height or just height + else + { + rect.mBottom = bottom; + rect.mTop = bottom + height; + } + } + // just bottom, just top, or none + else + { + rect.mBottom = bottom; + rect.mTop = top; + } + updateValue(rect); + } + + void ParamValue<LLRect>::updateBlockFromValue(bool make_block_authoritative) + { + // because of the ambiguity in specifying a rect by position and/or dimensions + // we use the lowest priority pairing so that any valid pairing in xui + // will override those calculated from the rect object + // in this case, that is left+width and bottom+height + LLRect& value = getValue(); + + right.set(value.mRight, false); + left.set(value.mLeft, make_block_authoritative); + width.set(value.getWidth(), make_block_authoritative); + + top.set(value.mTop, false); + bottom.set(value.mBottom, make_block_authoritative); + height.set(value.getHeight(), make_block_authoritative); + } + + ParamValue<LLCoordGL>::ParamValue(const LLCoordGL& coord) + : super_t(coord), + x("x"), + y("y") + { + updateBlockFromValue(false); + } + + void ParamValue<LLCoordGL>::updateValueFromBlock() + { + updateValue(LLCoordGL(x, y)); + } + + void ParamValue<LLCoordGL>::updateBlockFromValue(bool make_block_authoritative) + { + x.set(getValue().mX, make_block_authoritative); + y.set(getValue().mY, make_block_authoritative); + } + + + void TypeValues<LLFontGL::HAlign>::declareValues() + { + declare("left", LLFontGL::LEFT); + declare("right", LLFontGL::RIGHT); + declare("center", LLFontGL::HCENTER); + } + + void TypeValues<LLFontGL::VAlign>::declareValues() + { + declare("top", LLFontGL::TOP); + declare("center", LLFontGL::VCENTER); + declare("baseline", LLFontGL::BASELINE); + declare("bottom", LLFontGL::BOTTOM); + } + + void TypeValues<LLFontGL::ShadowType>::declareValues() + { + declare("none", LLFontGL::NO_SHADOW); + declare("hard", LLFontGL::DROP_SHADOW); + declare("soft", LLFontGL::DROP_SHADOW_SOFT); + } } diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 86b23c8c93..471602515d 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -1,25 +1,25 @@ -/** +/** * @file llui.h * @brief General static UI services. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,28 +53,28 @@ class LLWindow; class LLView; class LLHelp; - -// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim) +const S32 DRAG_N_DROP_DISTANCE_THRESHOLD = 3; +// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim) enum EDragAndDropType { - DAD_NONE = 0, - DAD_TEXTURE = 1, - DAD_SOUND = 2, - DAD_CALLINGCARD = 3, - DAD_LANDMARK = 4, - DAD_SCRIPT = 5, - DAD_CLOTHING = 6, - DAD_OBJECT = 7, - DAD_NOTECARD = 8, - DAD_CATEGORY = 9, - DAD_ROOT_CATEGORY = 10, - DAD_BODYPART = 11, - DAD_ANIMATION = 12, - DAD_GESTURE = 13, - DAD_LINK = 14, - DAD_MESH = 15, - DAD_WIDGET = 16, - DAD_PERSON = 17, + DAD_NONE = 0, + DAD_TEXTURE = 1, + DAD_SOUND = 2, + DAD_CALLINGCARD = 3, + DAD_LANDMARK = 4, + DAD_SCRIPT = 5, + DAD_CLOTHING = 6, + DAD_OBJECT = 7, + DAD_NOTECARD = 8, + DAD_CATEGORY = 9, + DAD_ROOT_CATEGORY = 10, + DAD_BODYPART = 11, + DAD_ANIMATION = 12, + DAD_GESTURE = 13, + DAD_LINK = 14, + DAD_MESH = 15, + DAD_WIDGET = 16, + DAD_PERSON = 17, DAD_SETTINGS = 18, DAD_MATERIAL = 19, DAD_COUNT = 20, // number of types in this enum @@ -84,21 +84,21 @@ enum EDragAndDropType // ordered by priority for multi-drag enum EAcceptance { - ACCEPT_POSTPONED, // we are asynchronously determining acceptance - ACCEPT_NO, // Uninformative, general purpose denial. - ACCEPT_NO_CUSTOM, // Denial with custom message. - ACCEPT_NO_LOCKED, // Operation would be valid, but permissions are set to disallow it. - ACCEPT_YES_COPY_SINGLE, // We'll take a copy of a single item - ACCEPT_YES_SINGLE, // Accepted. OK to drag and drop single item here. - ACCEPT_YES_COPY_MULTI, // We'll take a copy of multiple items - ACCEPT_YES_MULTI // Accepted. OK to drag and drop multiple items here. + ACCEPT_POSTPONED, // we are asynchronously determining acceptance + ACCEPT_NO, // Uninformative, general purpose denial. + ACCEPT_NO_CUSTOM, // Denial with custom message. + ACCEPT_NO_LOCKED, // Operation would be valid, but permissions are set to disallow it. + ACCEPT_YES_COPY_SINGLE, // We'll take a copy of a single item + ACCEPT_YES_SINGLE, // Accepted. OK to drag and drop single item here. + ACCEPT_YES_COPY_MULTI, // We'll take a copy of multiple items + ACCEPT_YES_MULTI // Accepted. OK to drag and drop multiple items here. }; enum EAddPosition { - ADD_TOP, - ADD_BOTTOM, - ADD_DEFAULT + ADD_TOP, + ADD_BOTTOM, + ADD_DEFAULT }; @@ -107,237 +107,237 @@ void make_ui_sound_deferred(const char * name); class LLImageProviderInterface; -typedef void (*LLUIAudioCallback)(const LLUUID& uuid); +typedef void (*LLUIAudioCallback)(const LLUUID& uuid); class LLUI : public LLParamSingleton<LLUI> { public: - typedef std::map<std::string, LLControlGroup*> settings_map_t; + typedef std::map<std::string, LLControlGroup*> settings_map_t; private: - LLSINGLETON(LLUI , const settings_map_t &settings, - LLImageProviderInterface* image_provider, - LLUIAudioCallback audio_callback, - LLUIAudioCallback deferred_audio_callback); - LOG_CLASS(LLUI); + LLSINGLETON(LLUI , const settings_map_t &settings, + LLImageProviderInterface* image_provider, + LLUIAudioCallback audio_callback, + LLUIAudioCallback deferred_audio_callback); + LOG_CLASS(LLUI); public: - // - // Classes - // - - struct RangeS32 - { - struct Params : public LLInitParam::Block<Params> - { - Optional<S32> minimum, - maximum; - - Params() - : minimum("min", 0), - maximum("max", S32_MAX) - {} - }; - - // correct for inverted params - RangeS32(const Params& p = Params()) - : mMin(p.minimum), - mMax(p.maximum) - { - sanitizeRange(); - } - - RangeS32(S32 minimum, S32 maximum) - : mMin(minimum), - mMax(maximum) - { - sanitizeRange(); - } - - S32 clamp(S32 input) - { - if (input < mMin) return mMin; - if (input > mMax) return mMax; - return input; - } - - void setRange(S32 minimum, S32 maximum) - { - mMin = minimum; - mMax = maximum; - sanitizeRange(); - } - - S32 getMin() { return mMin; } - S32 getMax() { return mMax; } - - bool operator==(const RangeS32& other) const - { - return mMin == other.mMin - && mMax == other.mMax; - } - private: - void sanitizeRange() - { - if (mMin > mMax) - { - LL_WARNS() << "Bad interval range (" << mMin << ", " << mMax << ")" << LL_ENDL; - // since max is usually the most dangerous one to ignore (buffer overflow, etc), prefer it - // in the case of a malformed range - mMin = mMax; - } - } - - - S32 mMin, - mMax; - }; - - struct ClampedS32 : public RangeS32 - { - struct Params : public LLInitParam::Block<Params, RangeS32::Params> - { - Mandatory<S32> value; - - Params() - : value("", 0) - { - addSynonym(value, "value"); - } - }; - - ClampedS32(const Params& p) - : RangeS32(p) - {} - - ClampedS32(const RangeS32& range) - : RangeS32(range) - { - // set value here, after range has been sanitized - mValue = clamp(0); - } - - ClampedS32(S32 value, const RangeS32& range = RangeS32()) - : RangeS32(range) - { - mValue = clamp(value); - } - - S32 get() - { - return mValue; - } - - void set(S32 value) - { - mValue = clamp(value); - } - - - private: - S32 mValue; - }; - - // - // Methods - // - typedef boost::function<void(LLView*)> add_popup_t; - typedef boost::function<void(LLView*)> remove_popup_t; - typedef boost::function<void(void)> clear_popups_t; - - void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); - - // Return the ISO639 language name ("en", "ko", etc.) for the viewer UI. - // http://www.loc.gov/standards/iso639-2/php/code_list.php - std::string getUILanguage(); - static std::string getLanguage(); // static for lldateutil_test compatibility - - //helper functions (should probably move free standing rendering helper functions here) - LLView* getRootView() { return mRootView; } - void setRootView(LLView* view) { mRootView = view; } - /** - * Walk the LLView tree to resolve a path - * Paths can be discovered using Develop > XUI > Show XUI Paths - * - * A leading "/" indicates the root of the tree is the starting - * position of the search, (otherwise the context node is used) - * - * Adjacent "//" mean that the next level of the search is done - * recursively ("descendant" rather than "child"). - * - * Return values: If no match is found, NULL is returned, - * otherwise the matching LLView* is returned. - * - * Examples: - * - * "/" -> return the root view - * "/foo" -> find "foo" as a direct child of the root - * "foo" -> find "foo" as a direct child of the context node - * "//foo" -> find the first "foo" child anywhere in the tree - * "/foo/bar" -> find "foo" as direct child of the root, and - * "bar" as a direct child of "foo" - * "//foo//bar/baz" -> find the first "foo" anywhere in the - * tree, the first "bar" anywhere under it, and "baz" - * as a direct child of that - */ - const LLView* resolvePath(const LLView* context, const std::string& path); - LLView* resolvePath(LLView* context, const std::string& path); - static std::string locateSkin(const std::string& filename); - void setMousePositionScreen(S32 x, S32 y); - void getMousePositionScreen(S32 *x, S32 *y); - void setMousePositionLocal(const LLView* viewp, S32 x, S32 y); - void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y); - LLVector2 getWindowSize(); - void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y); - void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); - void screenRectToGL(const LLRect& screen, LLRect *gl); - void glRectToScreen(const LLRect& gl, LLRect *screen); - // Returns the control group containing the control name, or the default group - LLControlGroup& getControlControlGroup (const std::string& controlname); - F32 getMouseIdleTime() { return mMouseIdleTimer.getElapsedTimeF32(); } - void resetMouseIdleTimer() { mMouseIdleTimer.reset(); } - LLWindow* getWindow() { return mWindow; } - - void addPopup(LLView*); - void removePopup(LLView*); - void clearPopups(); - - void reportBadKeystroke(); - - // Ensures view does not overlap mouse cursor, but is inside - // the view's parent rectangle. Used for tooltips, inspectors. - // Optionally override the view's default X/Y, which are relative to the - // view's parent. - void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX); - - // LLRender2D wrappers - static void pushMatrix() { LLRender2D::pushMatrix(); } - static void popMatrix() { LLRender2D::popMatrix(); } - static void loadIdentity() { LLRender2D::loadIdentity(); } - static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); } + // + // Classes + // + + struct RangeS32 + { + struct Params : public LLInitParam::Block<Params> + { + Optional<S32> minimum, + maximum; + + Params() + : minimum("min", 0), + maximum("max", S32_MAX) + {} + }; + + // correct for inverted params + RangeS32(const Params& p = Params()) + : mMin(p.minimum), + mMax(p.maximum) + { + sanitizeRange(); + } + + RangeS32(S32 minimum, S32 maximum) + : mMin(minimum), + mMax(maximum) + { + sanitizeRange(); + } + + S32 clamp(S32 input) + { + if (input < mMin) return mMin; + if (input > mMax) return mMax; + return input; + } + + void setRange(S32 minimum, S32 maximum) + { + mMin = minimum; + mMax = maximum; + sanitizeRange(); + } + + S32 getMin() { return mMin; } + S32 getMax() { return mMax; } + + bool operator==(const RangeS32& other) const + { + return mMin == other.mMin + && mMax == other.mMax; + } + private: + void sanitizeRange() + { + if (mMin > mMax) + { + LL_WARNS() << "Bad interval range (" << mMin << ", " << mMax << ")" << LL_ENDL; + // since max is usually the most dangerous one to ignore (buffer overflow, etc), prefer it + // in the case of a malformed range + mMin = mMax; + } + } + + + S32 mMin, + mMax; + }; + + struct ClampedS32 : public RangeS32 + { + struct Params : public LLInitParam::Block<Params, RangeS32::Params> + { + Mandatory<S32> value; + + Params() + : value("", 0) + { + addSynonym(value, "value"); + } + }; + + ClampedS32(const Params& p) + : RangeS32(p) + {} + + ClampedS32(const RangeS32& range) + : RangeS32(range) + { + // set value here, after range has been sanitized + mValue = clamp(0); + } + + ClampedS32(S32 value, const RangeS32& range = RangeS32()) + : RangeS32(range) + { + mValue = clamp(value); + } + + S32 get() + { + return mValue; + } + + void set(S32 value) + { + mValue = clamp(value); + } + + + private: + S32 mValue; + }; + + // + // Methods + // + typedef boost::function<void(LLView*)> add_popup_t; + typedef boost::function<void(LLView*)> remove_popup_t; + typedef boost::function<void(void)> clear_popups_t; + + void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); + + // Return the ISO639 language name ("en", "ko", etc.) for the viewer UI. + // http://www.loc.gov/standards/iso639-2/php/code_list.php + std::string getUILanguage(); + static std::string getLanguage(); // static for lldateutil_test compatibility + + //helper functions (should probably move free standing rendering helper functions here) + LLView* getRootView() { return mRootView; } + void setRootView(LLView* view) { mRootView = view; } + /** + * Walk the LLView tree to resolve a path + * Paths can be discovered using Develop > XUI > Show XUI Paths + * + * A leading "/" indicates the root of the tree is the starting + * position of the search, (otherwise the context node is used) + * + * Adjacent "//" mean that the next level of the search is done + * recursively ("descendant" rather than "child"). + * + * Return values: If no match is found, NULL is returned, + * otherwise the matching LLView* is returned. + * + * Examples: + * + * "/" -> return the root view + * "/foo" -> find "foo" as a direct child of the root + * "foo" -> find "foo" as a direct child of the context node + * "//foo" -> find the first "foo" child anywhere in the tree + * "/foo/bar" -> find "foo" as direct child of the root, and + * "bar" as a direct child of "foo" + * "//foo//bar/baz" -> find the first "foo" anywhere in the + * tree, the first "bar" anywhere under it, and "baz" + * as a direct child of that + */ + const LLView* resolvePath(const LLView* context, const std::string& path); + LLView* resolvePath(LLView* context, const std::string& path); + static std::string locateSkin(const std::string& filename); + void setMousePositionScreen(S32 x, S32 y); + void getMousePositionScreen(S32 *x, S32 *y); + void setMousePositionLocal(const LLView* viewp, S32 x, S32 y); + void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y); + LLVector2 getWindowSize(); + void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y); + void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y); + void screenRectToGL(const LLRect& screen, LLRect *gl); + void glRectToScreen(const LLRect& gl, LLRect *screen); + // Returns the control group containing the control name, or the default group + LLControlGroup& getControlControlGroup (const std::string& controlname); + F32 getMouseIdleTime() { return mMouseIdleTimer.getElapsedTimeF32(); } + void resetMouseIdleTimer() { mMouseIdleTimer.reset(); } + LLWindow* getWindow() { return mWindow; } + + void addPopup(LLView*); + void removePopup(LLView*); + void clearPopups(); + + void reportBadKeystroke(); + + // Ensures view does not overlap mouse cursor, but is inside + // the view's parent rectangle. Used for tooltips, inspectors. + // Optionally override the view's default X/Y, which are relative to the + // view's parent. + void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX); + + // LLRender2D wrappers + static void pushMatrix() { LLRender2D::pushMatrix(); } + static void popMatrix() { LLRender2D::popMatrix(); } + static void loadIdentity() { LLRender2D::loadIdentity(); } + static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); } static LLVector2& getScaleFactor(); static void setScaleFactor(const LLVector2& scale_factor); - static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); } - static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0) - { return LLRender2D::getInstance()->getUIImageByID(image_id, priority); } - static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0) - { return LLRender2D::getInstance()->getUIImage(name, priority); } - - // - // Data - // - settings_map_t mSettingGroups; - LLUIAudioCallback mAudioCallback; - LLUIAudioCallback mDeferredAudioCallback; - LLWindow* mWindow; - LLView* mRootView; - LLHelp* mHelpImpl; + static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); } + static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0) + { return LLRender2D::getInstance()->getUIImageByID(image_id, priority); } + static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0) + { return LLRender2D::getInstance()->getUIImage(name, priority); } + + // + // Data + // + settings_map_t mSettingGroups; + LLUIAudioCallback mAudioCallback; + LLUIAudioCallback mDeferredAudioCallback; + LLWindow* mWindow; + LLView* mRootView; + LLHelp* mHelpImpl; private: - std::vector<std::string> mXUIPaths; - LLFrameTimer mMouseIdleTimer; - add_popup_t mAddPopupFunc; - remove_popup_t mRemovePopupFunc; - clear_popups_t mClearPopupsFunc; + std::vector<std::string> mXUIPaths; + LLFrameTimer mMouseIdleTimer; + add_popup_t mAddPopupFunc; + remove_popup_t mRemovePopupFunc; + clear_popups_t mClearPopupsFunc; }; @@ -346,118 +346,118 @@ private: // useful parameter blocks struct TimeIntervalParam : public LLInitParam::ChoiceBlock<TimeIntervalParam> { - Alternative<F32> seconds; - Alternative<S32> frames; - TimeIntervalParam() - : seconds("seconds"), - frames("frames") - {} + Alternative<F32> seconds; + Alternative<S32> frames; + TimeIntervalParam() + : seconds("seconds"), + frames("frames") + {} }; template <class T> class LLUICachedControl : public LLCachedControl<T> { public: - // This constructor will declare a control if it doesn't exist in the contol group - LLUICachedControl(const std::string& name, - const T& default_value, - const std::string& comment = "Declared In Code") - : LLCachedControl<T>(LLUI::getInstance()->getControlControlGroup(name), name, default_value, comment) - {} + // This constructor will declare a control if it doesn't exist in the contol group + LLUICachedControl(const std::string& name, + const T& default_value, + const std::string& comment = "Declared In Code") + : LLCachedControl<T>(LLUI::getInstance()->getControlControlGroup(name), name, default_value, comment) + {} }; namespace LLInitParam { - template<> - class ParamValue<LLRect> - : public CustomParamValue<LLRect> - { + template<> + class ParamValue<LLRect> + : public CustomParamValue<LLRect> + { typedef CustomParamValue<LLRect> super_t; - public: - Optional<S32> left, - top, - right, - bottom, - width, - height; - - ParamValue(const LLRect& value); - - void updateValueFromBlock(); - void updateBlockFromValue(bool make_block_authoritative); - }; - - template<> - class ParamValue<LLUIColor> - : public CustomParamValue<LLUIColor> - { + public: + Optional<S32> left, + top, + right, + bottom, + width, + height; + + ParamValue(const LLRect& value); + + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue<LLUIColor> + : public CustomParamValue<LLUIColor> + { typedef CustomParamValue<LLUIColor> super_t; - public: - Optional<F32> red, - green, - blue, - alpha; - Optional<std::string> control; - - ParamValue(const LLUIColor& color); - void updateValueFromBlock(); - void updateBlockFromValue(bool make_block_authoritative); - }; - - template<> - class ParamValue<const LLFontGL*> - : public CustomParamValue<const LLFontGL* > - { + public: + Optional<F32> red, + green, + blue, + alpha; + Optional<std::string> control; + + ParamValue(const LLUIColor& color); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue<const LLFontGL*> + : public CustomParamValue<const LLFontGL* > + { typedef CustomParamValue<const LLFontGL*> super_t; - public: - Optional<std::string> name, - size, - style; - - ParamValue(const LLFontGL* value); - void updateValueFromBlock(); - void updateBlockFromValue(bool make_block_authoritative); - }; - - template<> - struct TypeValues<LLFontGL::HAlign> : public TypeValuesHelper<LLFontGL::HAlign> - { - static void declareValues(); - }; - - template<> - struct TypeValues<LLFontGL::VAlign> : public TypeValuesHelper<LLFontGL::VAlign> - { - static void declareValues(); - }; - - template<> - struct TypeValues<LLFontGL::ShadowType> : public TypeValuesHelper<LLFontGL::ShadowType> - { - static void declareValues(); - }; - - template<> - struct ParamCompare<const LLFontGL*, false> - { - static bool equals(const LLFontGL* a, const LLFontGL* b); - }; - - - template<> - class ParamValue<LLCoordGL> - : public CustomParamValue<LLCoordGL> - { - typedef CustomParamValue<LLCoordGL> super_t; - public: - Optional<S32> x, - y; - - ParamValue(const LLCoordGL& val); - void updateValueFromBlock(); - void updateBlockFromValue(bool make_block_authoritative); - }; + public: + Optional<std::string> name, + size, + style; + + ParamValue(const LLFontGL* value); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + struct TypeValues<LLFontGL::HAlign> : public TypeValuesHelper<LLFontGL::HAlign> + { + static void declareValues(); + }; + + template<> + struct TypeValues<LLFontGL::VAlign> : public TypeValuesHelper<LLFontGL::VAlign> + { + static void declareValues(); + }; + + template<> + struct TypeValues<LLFontGL::ShadowType> : public TypeValuesHelper<LLFontGL::ShadowType> + { + static void declareValues(); + }; + + template<> + struct ParamCompare<const LLFontGL*, false> + { + static bool equals(const LLFontGL* a, const LLFontGL* b); + }; + + + template<> + class ParamValue<LLCoordGL> + : public CustomParamValue<LLCoordGL> + { + typedef CustomParamValue<LLCoordGL> super_t; + public: + Optional<S32> x, + y; + + ParamValue(const LLCoordGL& val); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; } #endif diff --git a/indra/llui/lluicolor.cpp b/indra/llui/lluicolor.cpp index f9bb80f8c5..71db556fad 100644 --- a/indra/llui/lluicolor.cpp +++ b/indra/llui/lluicolor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lluicolor.cpp * @brief brief LLUIColor class implementation file * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,59 +29,59 @@ #include "lluicolor.h" LLUIColor::LLUIColor() - :mColorPtr(NULL) + :mColorPtr(NULL) { } LLUIColor::LLUIColor(const LLColor4& color) -: mColor(color), - mColorPtr(NULL) +: mColor(color), + mColorPtr(NULL) { } LLUIColor::LLUIColor(const LLUIColor* color) -: mColorPtr(color) +: mColorPtr(color) { } void LLUIColor::set(const LLColor4& color) { - mColor = color; - mColorPtr = NULL; + mColor = color; + mColorPtr = NULL; } void LLUIColor::set(const LLUIColor* color) { - mColorPtr = color; + mColorPtr = color; } const LLColor4& LLUIColor::get() const { - return (mColorPtr == NULL ? mColor : mColorPtr->get()); + return (mColorPtr == NULL ? mColor : mColorPtr->get()); } LLUIColor::operator const LLColor4& () const { - return get(); + return get(); } const LLColor4& LLUIColor::operator()() const { - return get(); + return get(); } bool LLUIColor::isReference() const { - return mColorPtr != NULL; + return mColorPtr != NULL; } namespace LLInitParam { - // used to detect equivalence with default values on export - bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) - { - // do not detect value equivalence, treat pointers to colors as distinct from color values - return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); - } + // used to detect equivalence with default values on export + bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) + { + // do not detect value equivalence, treat pointers to colors as distinct from color values + return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); + } } diff --git a/indra/llui/lluicolor.h b/indra/llui/lluicolor.h index 97ebea854a..f688cc95af 100644 --- a/indra/llui/lluicolor.h +++ b/indra/llui/lluicolor.h @@ -1,25 +1,25 @@ -/** +/** * @file lluicolor.h * @brief brief LLUIColor class header file * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,41 +31,41 @@ namespace LLInitParam { - template<typename T, bool> - struct ParamCompare; + template<typename T, bool> + struct ParamCompare; } class LLUIColor { public: - LLUIColor(); - LLUIColor(const LLColor4& color); - LLUIColor(const LLUIColor* color); + LLUIColor(); + LLUIColor(const LLColor4& color); + LLUIColor(const LLUIColor* color); - void set(const LLColor4& color); - void set(const LLUIColor* color); + void set(const LLColor4& color); + void set(const LLUIColor* color); - const LLColor4& get() const; + const LLColor4& get() const; - operator const LLColor4& () const; - const LLColor4& operator()() const; + operator const LLColor4& () const; + const LLColor4& operator()() const; - bool isReference() const; + bool isReference() const; private: - friend struct LLInitParam::ParamCompare<LLUIColor, false>; + friend struct LLInitParam::ParamCompare<LLUIColor, false>; - const LLUIColor* mColorPtr; - LLColor4 mColor; + const LLUIColor* mColorPtr; + LLColor4 mColor; }; namespace LLInitParam { - template<> - struct ParamCompare<LLUIColor, false> - { - static bool equals(const LLUIColor& a, const LLUIColor& b); - }; + template<> + struct ParamCompare<LLUIColor, false> + { + static bool equals(const LLUIColor& a, const LLUIColor& b); + }; } #endif diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index f43bdf1fdc..54f8727fa5 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lluicolortable.cpp * @brief brief LLUIColorTable class implementation file * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,298 +34,298 @@ #include "lluictrlfactory.h" LLUIColorTable::ColorParams::ColorParams() -: value("value"), - reference("reference") +: value("value"), + reference("reference") { } LLUIColorTable::ColorEntryParams::ColorEntryParams() -: name("name"), - color("") +: name("name"), + color("") { } LLUIColorTable::Params::Params() -: color_entries("color") +: color_entries("color") { } 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; - string_string_map_t unresolved_refs; - - for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin(); - it != p.color_entries.end(); - ++it) - { - ColorEntryParams color_entry = *it; - if(color_entry.color.value.isChosen()) - { - setColor(color_entry.name, color_entry.color.value, table); - } - else - { - unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference)); - } - } - - // maintain an in order queue of visited references for better debugging of cycles - typedef std::queue<std::string> string_queue_t; - string_queue_t ref_chain; - - // maintain a map of the previously visited references in the reference chain for detecting cycles - typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t; - string_color_ref_iter_map_t visited_refs; - - // loop through the unresolved color references until there are none left - while(!unresolved_refs.empty()) - { - // we haven't visited any references yet - visited_refs.clear(); - - string_string_map_t::iterator current = unresolved_refs.begin(); - string_string_map_t::iterator previous; - - while(true) - { - if(current != unresolved_refs.end()) - { - // locate the current reference in the previously visited references... - string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(current->first); - if(visited != visited_refs.end() - && !(visited_refs.key_comp()(current->first, visited->first))) - { - // ...if we find the current reference in the previously visited references - // we know that there is a cycle - std::string ending_ref = current->first; - std::string warning("The following colors form a cycle: "); - - // warn about the references in the chain and remove them from - // the unresolved references map because they cannot be resolved - for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); - iter != visited_refs.end(); - ++iter) - { - if(!ref_chain.empty()) - { - warning += ref_chain.front() + "->"; - ref_chain.pop(); - } - unresolved_refs.erase(iter->second); - } - - LL_WARNS() << warning + ending_ref << LL_ENDL; - - break; - } - else - { - // ...continue along the reference chain - ref_chain.push(current->first); - visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(current->first, current)); - } - } - else - { - // since this reference does not refer to another reference it must refer to an - // actual color, lets find it... - string_color_map_t::iterator color_value = mLoadedColors.find(previous->second); - - if(color_value != mLoadedColors.end()) - { - // ...we found the color, and we now add every reference in the reference chain - // to the color map - for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); - iter != visited_refs.end(); - ++iter) - { - setColor(iter->first, color_value->second, mLoadedColors); - unresolved_refs.erase(iter->second); - } - - break; - } - else - { - // ... we did not find the color which imples that the current reference - // references a non-existant color - for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); - iter != visited_refs.end(); - ++iter) - { - LL_WARNS() << iter->first << " references a non-existent color" << LL_ENDL; - unresolved_refs.erase(iter->second); - } - - break; - } - } - - // find the next color reference in the reference chain - previous = current; - current = unresolved_refs.find(current->second); - } - } + // this map will contain all color references after the following loop + typedef std::map<std::string, std::string> string_string_map_t; + string_string_map_t unresolved_refs; + + for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin(); + it != p.color_entries.end(); + ++it) + { + ColorEntryParams color_entry = *it; + if(color_entry.color.value.isChosen()) + { + setColor(color_entry.name, color_entry.color.value, table); + } + else + { + unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference)); + } + } + + // maintain an in order queue of visited references for better debugging of cycles + typedef std::queue<std::string> string_queue_t; + string_queue_t ref_chain; + + // maintain a map of the previously visited references in the reference chain for detecting cycles + typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t; + string_color_ref_iter_map_t visited_refs; + + // loop through the unresolved color references until there are none left + while(!unresolved_refs.empty()) + { + // we haven't visited any references yet + visited_refs.clear(); + + string_string_map_t::iterator current = unresolved_refs.begin(); + string_string_map_t::iterator previous; + + while(true) + { + if(current != unresolved_refs.end()) + { + // locate the current reference in the previously visited references... + string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(current->first); + if(visited != visited_refs.end() + && !(visited_refs.key_comp()(current->first, visited->first))) + { + // ...if we find the current reference in the previously visited references + // we know that there is a cycle + std::string ending_ref = current->first; + std::string warning("The following colors form a cycle: "); + + // warn about the references in the chain and remove them from + // the unresolved references map because they cannot be resolved + for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); + iter != visited_refs.end(); + ++iter) + { + if(!ref_chain.empty()) + { + warning += ref_chain.front() + "->"; + ref_chain.pop(); + } + unresolved_refs.erase(iter->second); + } + + LL_WARNS() << warning + ending_ref << LL_ENDL; + + break; + } + else + { + // ...continue along the reference chain + ref_chain.push(current->first); + visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(current->first, current)); + } + } + else + { + // since this reference does not refer to another reference it must refer to an + // actual color, lets find it... + string_color_map_t::iterator color_value = mLoadedColors.find(previous->second); + + if(color_value != mLoadedColors.end()) + { + // ...we found the color, and we now add every reference in the reference chain + // to the color map + for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); + iter != visited_refs.end(); + ++iter) + { + setColor(iter->first, color_value->second, mLoadedColors); + unresolved_refs.erase(iter->second); + } + + break; + } + else + { + // ... we did not find the color which imples that the current reference + // references a non-existant color + for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin(); + iter != visited_refs.end(); + ++iter) + { + LL_WARNS() << iter->first << " references a non-existent color" << LL_ENDL; + unresolved_refs.erase(iter->second); + } + + break; + } + } + + // find the next color reference in the reference chain + previous = current; + current = unresolved_refs.find(current->second); + } + } } void LLUIColorTable::clear() { - clearTable(mLoadedColors); - clearTable(mUserSetColors); + clearTable(mLoadedColors); + clearTable(mUserSetColors); } LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const { - string_color_map_t::const_iterator iter = mUserSetColors.find(name); - - if(iter != mUserSetColors.end()) - { - return LLUIColor(&iter->second); - } - - iter = mLoadedColors.find(name); - - if(iter != mLoadedColors.end()) - { - return LLUIColor(&iter->second); - } - - return LLUIColor(default_color); + string_color_map_t::const_iterator iter = mUserSetColors.find(name); + + if(iter != mUserSetColors.end()) + { + return LLUIColor(&iter->second); + } + + iter = mLoadedColors.find(name); + + if(iter != mLoadedColors.end()) + { + return LLUIColor(&iter->second); + } + + return LLUIColor(default_color); } // update user color, loaded colors are parsed on initialization void LLUIColorTable::setColor(const std::string& name, const LLColor4& color) { - setColor(name, color, mUserSetColors); + setColor(name, color, mUserSetColors); } bool LLUIColorTable::loadFromSettings() { - bool result = false; + bool result = false; - // pass constraint=LLDir::ALL_SKINS because we want colors.xml from every - // skin dir - for (const std::string& colors_path : - gDirUtilp->findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS)) - { - result |= loadFromFilename(colors_path, mLoadedColors); - } + // pass constraint=LLDir::ALL_SKINS because we want colors.xml from every + // skin dir + for (const std::string& colors_path : + gDirUtilp->findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS)) + { + result |= loadFromFilename(colors_path, mLoadedColors); + } - std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - loadFromFilename(user_filename, mUserSetColors); + std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); + loadFromFilename(user_filename, mUserSetColors); - return result; + return result; } void LLUIColorTable::saveUserSettings() const { - Params params; - - for(string_color_map_t::const_iterator it = mUserSetColors.begin(); - it != mUserSetColors.end(); - ++it) - { - // Compare user color value with the default value, skip if equal - string_color_map_t::const_iterator itd = mLoadedColors.find(it->first); - if(itd != mLoadedColors.end() && itd->second == it->second) - continue; - - ColorEntryParams color_entry; - color_entry.name = it->first; - color_entry.color.value = it->second; - - params.color_entries.add(color_entry); - } - - LLXMLNodePtr output_node = new LLXMLNode("colors", false); - LLXUIParser parser; - parser.writeXUI(output_node, params); - - if(!output_node->isNull()) - { - const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - LLFILE *fp = LLFile::fopen(filename, "w"); - - if(fp != NULL) - { - LLXMLNode::writeHeaderToFile(fp); - output_node->writeToFile(fp); - - fclose(fp); - } - } + Params params; + + for(string_color_map_t::const_iterator it = mUserSetColors.begin(); + it != mUserSetColors.end(); + ++it) + { + // Compare user color value with the default value, skip if equal + string_color_map_t::const_iterator itd = mLoadedColors.find(it->first); + if(itd != mLoadedColors.end() && itd->second == it->second) + continue; + + ColorEntryParams color_entry; + color_entry.name = it->first; + color_entry.color.value = it->second; + + params.color_entries.add(color_entry); + } + + LLXMLNodePtr output_node = new LLXMLNode("colors", false); + LLXUIParser parser; + parser.writeXUI(output_node, params); + + if(!output_node->isNull()) + { + const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); + LLFILE *fp = LLFile::fopen(filename, "w"); + + if(fp != NULL) + { + LLXMLNode::writeHeaderToFile(fp); + output_node->writeToFile(fp); + + fclose(fp); + } + } } bool LLUIColorTable::colorExists(const std::string& color_name) const { - return ((mLoadedColors.find(color_name) != mLoadedColors.end()) - || (mUserSetColors.find(color_name) != mUserSetColors.end())); + return ((mLoadedColors.find(color_name) != mLoadedColors.end()) + || (mUserSetColors.find(color_name) != mUserSetColors.end())); } void LLUIColorTable::clearTable(string_color_map_t& table) { - for(string_color_map_t::iterator it = table.begin(); - it != table.end(); - ++it) - { - it->second = LLColor4::magenta; - } + for(string_color_map_t::iterator it = table.begin(); + it != table.end(); + ++it) + { + it->second = LLColor4::magenta; + } } // this method inserts a color into the table if it does not exist // if the color already exists it changes the color void LLUIColorTable::setColor(const std::string& name, const LLColor4& color, string_color_map_t& table) { - string_color_map_t::iterator it = table.lower_bound(name); - if(it != table.end() - && !(table.key_comp()(name, it->first))) - { - it->second = color; - } - else - { - table.insert(it, string_color_map_t::value_type(name, color)); - } + string_color_map_t::iterator it = table.lower_bound(name); + if(it != table.end() + && !(table.key_comp()(name, it->first))) + { + it->second = color; + } + else + { + table.insert(it, string_color_map_t::value_type(name, color)); + } } bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_map_t& table) { - LLXMLNodePtr root; - - if(!LLXMLNode::parseFile(filename, root, NULL)) - { - LL_WARNS() << "Unable to parse color file " << filename << LL_ENDL; - return false; - } - - if(!root->hasName("colors")) - { - LL_WARNS() << filename << " is not a valid color definition file" << LL_ENDL; - return false; - } - - Params params; - LLXUIParser parser; - parser.readXUI(root, params, filename); - - if(params.validateBlock()) - { - insertFromParams(params, table); - } - else - { - LL_WARNS() << filename << " failed to load" << LL_ENDL; - return false; - } - - return true; + LLXMLNodePtr root; + + if(!LLXMLNode::parseFile(filename, root, NULL)) + { + LL_WARNS() << "Unable to parse color file " << filename << LL_ENDL; + return false; + } + + if(!root->hasName("colors")) + { + LL_WARNS() << filename << " is not a valid color definition file" << LL_ENDL; + return false; + } + + Params params; + LLXUIParser parser; + parser.readXUI(root, params, filename); + + if(params.validateBlock()) + { + insertFromParams(params, table); + } + else + { + LL_WARNS() << filename << " failed to load" << LL_ENDL; + return false; + } + + return true; } void LLUIColorTable::insertFromParams(const Params& p) { - insertFromParams(p, mUserSetColors); + insertFromParams(p, mUserSetColors); } // EOF diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index 44472070cc..7232077cab 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -1,25 +1,25 @@ -/** +/** * @file lluicolortable.h * @brief brief LLUIColorTable class header file * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,67 +38,67 @@ class LLUIColor; class LLUIColorTable : public LLSingleton<LLUIColorTable> { - LLSINGLETON_EMPTY_CTOR(LLUIColorTable); - LOG_CLASS(LLUIColorTable); + LLSINGLETON_EMPTY_CTOR(LLUIColorTable); + LOG_CLASS(LLUIColorTable); - // consider using sorted vector, can be much faster - typedef std::map<std::string, LLUIColor> string_color_map_t; + // consider using sorted vector, can be much faster + typedef std::map<std::string, LLUIColor> string_color_map_t; public: - struct ColorParams : LLInitParam::ChoiceBlock<ColorParams> - { - Alternative<LLColor4> value; - Alternative<std::string> reference; + struct ColorParams : LLInitParam::ChoiceBlock<ColorParams> + { + Alternative<LLColor4> value; + Alternative<std::string> reference; - ColorParams(); - }; + ColorParams(); + }; - struct ColorEntryParams : LLInitParam::Block<ColorEntryParams> - { - Mandatory<std::string> name; - Mandatory<ColorParams> color; + struct ColorEntryParams : LLInitParam::Block<ColorEntryParams> + { + Mandatory<std::string> name; + Mandatory<ColorParams> color; - ColorEntryParams(); - }; + ColorEntryParams(); + }; - struct Params : LLInitParam::Block<Params> - { - Multiple<ColorEntryParams> color_entries; + struct Params : LLInitParam::Block<Params> + { + Multiple<ColorEntryParams> color_entries; - Params(); - }; + Params(); + }; - // define colors by passing in a param block that can be generated via XUI file or manually - void insertFromParams(const Params& p); + // define colors by passing in a param block that can be generated via XUI file or manually + void insertFromParams(const Params& p); - // reset all colors to default magenta color - void clear(); + // reset all colors to default magenta color + void clear(); - // color lookup - LLUIColor getColor(const std::string& name, const LLColor4& default_color = LLColor4::magenta) const; + // color lookup + LLUIColor getColor(const std::string& name, const LLColor4& default_color = LLColor4::magenta) const; - // if the color is in the table, it's value is changed, otherwise it is added - void setColor(const std::string& name, const LLColor4& color); + // if the color is in the table, it's value is changed, otherwise it is added + void setColor(const std::string& name, const LLColor4& color); - // returns true if color_name exists in the table - bool colorExists(const std::string& color_name) const; + // returns true if color_name exists in the table + bool colorExists(const std::string& color_name) const; - // loads colors from settings files - bool loadFromSettings(); + // loads colors from settings files + bool loadFromSettings(); - // saves colors specified by the user to the users skin directory - void saveUserSettings() const; + // saves colors specified by the user to the users skin directory + void saveUserSettings() const; private: - bool loadFromFilename(const std::string& filename, string_color_map_t& table); + bool loadFromFilename(const std::string& filename, string_color_map_t& table); + + void insertFromParams(const Params& p, string_color_map_t& table); - 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); + void clearTable(string_color_map_t& table); + void setColor(const std::string& name, const LLColor4& color, string_color_map_t& table); - string_color_map_t mLoadedColors; - string_color_map_t mUserSetColors; + string_color_map_t mLoadedColors; + string_color_map_t mUserSetColors; }; #endif // LL_LLUICOLORTABLE_H diff --git a/indra/llui/lluiconstants.h b/indra/llui/lluiconstants.h index 1479e58c43..5fdfd37c6e 100644 --- a/indra/llui/lluiconstants.h +++ b/indra/llui/lluiconstants.h @@ -1,25 +1,25 @@ -/** +/** * @file lluiconstants.h * @brief Compile-time configuration for UI * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,11 +40,11 @@ const S32 VPAD = 4; const S32 HPAD = 4; // Account History, how far to look into past -const S32 SUMMARY_INTERVAL = 7; // one week -const S32 SUMMARY_MAX = 8; // -const S32 DETAILS_INTERVAL = 1; // one day -const S32 DETAILS_MAX = 30; // one month +const S32 SUMMARY_INTERVAL = 7; // one week +const S32 SUMMARY_MAX = 8; // +const S32 DETAILS_INTERVAL = 1; // one day +const S32 DETAILS_MAX = 30; // one month const S32 TRANSACTIONS_INTERVAL = 1;// one day -const S32 TRANSACTIONS_MAX = 30; // one month +const S32 TRANSACTIONS_MAX = 30; // one month #endif diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 7eb9ae69fb..69093393d9 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lluictrl.cpp * @author James Cook, Richard Nelson, Tom Yedwab * @brief Abstract base class for UI controls @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,221 +44,221 @@ F32 LLUICtrl::sInactiveControlTransparency = 1.0f; // Compiler optimization, generate extern template template class LLUICtrl* LLView::getChild<class LLUICtrl>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; LLUICtrl::CallbackParam::CallbackParam() -: name("name"), - function_name("function"), - parameter("parameter"), - control_name("control") // Shortcut to control -> "control_name" for backwards compatability +: name("name"), + function_name("function"), + parameter("parameter"), + control_name("control") // Shortcut to control -> "control_name" for backwards compatability { - addSynonym(parameter, "userdata"); + addSynonym(parameter, "userdata"); } LLUICtrl::EnableControls::EnableControls() -: enabled("enabled_control"), - disabled("disabled_control") +: enabled("enabled_control"), + disabled("disabled_control") {} LLUICtrl::ControlVisibility::ControlVisibility() -: visible("visibility_control"), - invisible("invisibility_control") +: visible("visibility_control"), + invisible("invisibility_control") { - addSynonym(visible, "visiblity_control"); - addSynonym(invisible, "invisiblity_control"); + addSynonym(visible, "visiblity_control"); + addSynonym(invisible, "invisiblity_control"); } LLUICtrl::Params::Params() -: tab_stop("tab_stop", true), - chrome("chrome", false), - requests_front("requests_front", false), - label("label"), - initial_value("value"), - init_callback("init_callback"), - commit_callback("commit_callback"), - validate_callback("validate_callback"), - mouseenter_callback("mouseenter_callback"), - mouseleave_callback("mouseleave_callback"), - control_name("control_name"), - font("font", LLFontGL::getFontSansSerif()), - font_halign("halign"), - font_valign("valign"), - length("length"), // ignore LLXMLNode cruft - type("type") // ignore LLXMLNode cruft -{ - addSynonym(initial_value, "initial_value"); +: tab_stop("tab_stop", true), + chrome("chrome", false), + requests_front("requests_front", false), + label("label"), + initial_value("value"), + init_callback("init_callback"), + commit_callback("commit_callback"), + validate_callback("validate_callback"), + mouseenter_callback("mouseenter_callback"), + mouseleave_callback("mouseleave_callback"), + control_name("control_name"), + font("font", LLFontGL::getFontEmojiMedium()), + font_halign("halign"), + font_valign("valign"), + length("length"), // ignore LLXMLNode cruft + type("type") // ignore LLXMLNode cruft +{ + addSynonym(initial_value, "initial_value"); } // NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp. -//static +//static const LLUICtrl::Params& LLUICtrl::getDefaultParams() { - return LLUICtrlFactory::getDefaultParams<LLUICtrl>(); + return LLUICtrlFactory::getDefaultParams<LLUICtrl>(); } -LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) -: LLView(p), - mIsChrome(FALSE), - mRequestsFront(p.requests_front), - mTabStop(FALSE), - mTentative(FALSE), +LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) +: LLView(p), + mIsChrome(FALSE), + mRequestsFront(p.requests_front), + mTabStop(FALSE), + mTentative(FALSE), mViewModel(viewmodel), - mControlVariable(NULL), - mEnabledControlVariable(NULL), - mDisabledControlVariable(NULL), - mMakeVisibleControlVariable(NULL), - mMakeInvisibleControlVariable(NULL), - mCommitSignal(NULL), - mValidateSignal(NULL), - mMouseEnterSignal(NULL), - mMouseLeaveSignal(NULL), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mRightMouseDownSignal(NULL), - mRightMouseUpSignal(NULL), - mDoubleClickSignal(NULL), - mTransparencyType(TT_DEFAULT) + mControlVariable(NULL), + mEnabledControlVariable(NULL), + mDisabledControlVariable(NULL), + mMakeVisibleControlVariable(NULL), + mMakeInvisibleControlVariable(NULL), + mCommitSignal(NULL), + mValidateSignal(NULL), + mMouseEnterSignal(NULL), + mMouseLeaveSignal(NULL), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mRightMouseDownSignal(NULL), + mRightMouseUpSignal(NULL), + mDoubleClickSignal(NULL), + mTransparencyType(TT_DEFAULT) { } void LLUICtrl::initFromParams(const Params& p) { - LLView::initFromParams(p); - - mRequestsFront = p.requests_front; - - setIsChrome(p.chrome); - setControlName(p.control_name); - if(p.enabled_controls.isProvided()) - { - if (p.enabled_controls.enabled.isChosen()) - { - LLControlVariable* control = findControl(p.enabled_controls.enabled); - if (control) - { - setEnabledControlVariable(control); - } - else - { - LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName() - << ": control " << p.enabled_controls.enabled() - << " does not exist." << LL_ENDL; - } - } - else if(p.enabled_controls.disabled.isChosen()) - { - LLControlVariable* control = findControl(p.enabled_controls.disabled); - if (control) - { - setDisabledControlVariable(control); - } - else - { - LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName() - << ": control " << p.enabled_controls.disabled() - << " does not exist." << LL_ENDL; - } - } - } - if(p.controls_visibility.isProvided()) - { - if (p.controls_visibility.visible.isChosen()) - { - LLControlVariable* control = findControl(p.controls_visibility.visible); - if (control) - { - setMakeVisibleControlVariable(control); - } - else - { - LL_WARNS() << "Failed to assign visibility control variable to " << getName() - << ": control " << p.controls_visibility.visible() - << " does not exist." << LL_ENDL; - } - } - else if (p.controls_visibility.invisible.isChosen()) - { - LLControlVariable* control = findControl(p.controls_visibility.invisible); - if (control) - { - setMakeInvisibleControlVariable(control); - } - else - { - LL_WARNS() << "Failed to assign invisibility control variable to " << getName() - << ": control " << p.controls_visibility.invisible() - << " does not exist." << LL_ENDL; - } - } - } - - setTabStop(p.tab_stop); - - if (p.initial_value.isProvided() - && !p.control_name.isProvided()) - { + LLView::initFromParams(p); + + mRequestsFront = p.requests_front; + + setIsChrome(p.chrome); + setControlName(p.control_name); + if(p.enabled_controls.isProvided()) + { + if (p.enabled_controls.enabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.enabled); + if (control) + { + setEnabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'enabled' control variable to " << getName() + << ": control " << p.enabled_controls.enabled() + << " does not exist." << LL_ENDL; + } + } + else if(p.enabled_controls.disabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.disabled); + if (control) + { + setDisabledControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign 'disabled' control variable to " << getName() + << ": control " << p.enabled_controls.disabled() + << " does not exist." << LL_ENDL; + } + } + } + if(p.controls_visibility.isProvided()) + { + if (p.controls_visibility.visible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.visible); + if (control) + { + setMakeVisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign visibility control variable to " << getName() + << ": control " << p.controls_visibility.visible() + << " does not exist." << LL_ENDL; + } + } + else if (p.controls_visibility.invisible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.invisible); + if (control) + { + setMakeInvisibleControlVariable(control); + } + else + { + LL_WARNS() << "Failed to assign invisibility control variable to " << getName() + << ": control " << p.controls_visibility.invisible() + << " does not exist." << LL_ENDL; + } + } + } + + setTabStop(p.tab_stop); + + if (p.initial_value.isProvided() + && !p.control_name.isProvided()) + { setValue(p.initial_value); - } - - if (p.commit_callback.isProvided()) - { - setCommitCallback(initCommitCallback(p.commit_callback)); - } - - if (p.validate_callback.isProvided()) - { - setValidateCallback(initEnableCallback(p.validate_callback)); - } - - if (p.init_callback.isProvided()) - { - if (p.init_callback.function.isProvided()) - { - p.init_callback.function()(this, p.init_callback.parameter); - } - else - { - commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); - if (initfunc) - { - (*initfunc)(this, p.init_callback.parameter); - } - } - } - - if(p.mouseenter_callback.isProvided()) - { - setMouseEnterCallback(initCommitCallback(p.mouseenter_callback)); - } - - if(p.mouseleave_callback.isProvided()) - { - setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback)); - } + } + + if (p.commit_callback.isProvided()) + { + setCommitCallback(initCommitCallback(p.commit_callback)); + } + + if (p.validate_callback.isProvided()) + { + setValidateCallback(initEnableCallback(p.validate_callback)); + } + + if (p.init_callback.isProvided()) + { + if (p.init_callback.function.isProvided()) + { + p.init_callback.function()(this, p.init_callback.parameter); + } + else + { + commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); + if (initfunc) + { + (*initfunc)(this, p.init_callback.parameter); + } + } + } + + if(p.mouseenter_callback.isProvided()) + { + setMouseEnterCallback(initCommitCallback(p.mouseenter_callback)); + } + + if(p.mouseleave_callback.isProvided()) + { + setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback)); + } } LLUICtrl::~LLUICtrl() { - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() - if( gFocusMgr.getTopCtrl() == this ) - { - LL_WARNS() << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << LL_ENDL; - gFocusMgr.removeTopCtrlWithoutCallback( this ); - } + if( gFocusMgr.getTopCtrl() == this ) + { + LL_WARNS() << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << LL_ENDL; + gFocusMgr.removeTopCtrlWithoutCallback( this ); + } - delete mCommitSignal; - delete mValidateSignal; - delete mMouseEnterSignal; - delete mMouseLeaveSignal; - delete mMouseDownSignal; - delete mMouseUpSignal; - delete mRightMouseDownSignal; - delete mRightMouseUpSignal; - delete mDoubleClickSignal; + delete mCommitSignal; + delete mValidateSignal; + delete mMouseEnterSignal; + delete mMouseLeaveSignal; + delete mMouseDownSignal; + delete mMouseUpSignal; + delete mRightMouseDownSignal; + delete mRightMouseUpSignal; + delete mDoubleClickSignal; } void default_commit_handler(LLUICtrl* ctrl, const LLSD& param) @@ -266,185 +266,185 @@ void default_commit_handler(LLUICtrl* ctrl, const LLSD& param) bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param) { - return true; + return true; } LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb) { - if (cb.function.isProvided()) - { - if (cb.parameter.isProvided()) - return boost::bind(cb.function(), _1, cb.parameter); - else - return cb.function(); - } - else - { - std::string function_name = cb.function_name; - setFunctionName(function_name); - commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); - if (func) - { - if (cb.parameter.isProvided()) - return boost::bind((*func), _1, cb.parameter); - else - return commit_signal_t::slot_type(*func); - } - else if (!function_name.empty()) - { - LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL; - } - } - return default_commit_handler; + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), _1, cb.parameter); + else + return cb.function(); + } + else + { + std::string function_name = cb.function_name; + setFunctionName(function_name); + commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), _1, cb.parameter); + else + return commit_signal_t::slot_type(*func); + } + else if (!function_name.empty()) + { + LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL; + } + } + return default_commit_handler; } LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb) { - // Set the callback function - if (cb.function.isProvided()) - { - if (cb.parameter.isProvided()) - return boost::bind(cb.function(), this, cb.parameter); - else - return cb.function(); - } - else - { - enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name)); - if (func) - { - if (cb.parameter.isProvided()) - return boost::bind((*func), this, cb.parameter); - else - return enable_signal_t::slot_type(*func); - } - } - return default_enable_handler; + // Set the callback function + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), this, cb.parameter); + else + return cb.function(); + } + else + { + enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), this, cb.parameter); + else + return enable_signal_t::slot_type(*func); + } + } + return default_enable_handler; } // virtual void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask) { - if (mMouseEnterSignal) - { - (*mMouseEnterSignal)(this, getValue()); - } + if (mMouseEnterSignal) + { + (*mMouseEnterSignal)(this, getValue()); + } } // virtual void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask) { - if(mMouseLeaveSignal) - { - (*mMouseLeaveSignal)(this, getValue()); - } + if(mMouseLeaveSignal) + { + (*mMouseLeaveSignal)(this, getValue()); + } } -//virtual +//virtual BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask) { - LL_DEBUGS() << "LLUICtrl::handleMouseDown calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; - - BOOL handled = LLView::handleMouseDown(x,y,mask); - - if (mMouseDownSignal) - { - (*mMouseDownSignal)(this,x,y,mask); - } - LL_DEBUGS() << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << LL_ENDL; - - if (handled) { - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname()); - } - return handled; + LL_DEBUGS() << "LLUICtrl::handleMouseDown calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; + + BOOL handled = LLView::handleMouseDown(x,y,mask); + + if (mMouseDownSignal) + { + (*mMouseDownSignal)(this,x,y,mask); + } + LL_DEBUGS() << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << LL_ENDL; + + if (handled) { + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname()); + } + return handled; } //virtual BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask) { - LL_DEBUGS() << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; + LL_DEBUGS() << "LLUICtrl::handleMouseUp calling LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL; - BOOL handled = LLView::handleMouseUp(x,y,mask); - if (handled) { - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname()); - } - if (mMouseUpSignal) - { - (*mMouseUpSignal)(this,x,y,mask); - } + BOOL handled = LLView::handleMouseUp(x,y,mask); + if (handled) { + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-56,-56,getPathname()); + } + if (mMouseUpSignal) + { + (*mMouseUpSignal)(this,x,y,mask); + } - LL_DEBUGS() << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << LL_ENDL; + LL_DEBUGS() << "LLUICtrl::handleMouseUp - handled for xui " << getPathname() << " - is returning as: " << handled << " " << LL_ENDL; - return handled; + return handled; } //virtual BOOL LLUICtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleRightMouseDown(x,y,mask); - if (mRightMouseDownSignal) - { - (*mRightMouseDownSignal)(this,x,y,mask); - } - return handled; + BOOL handled = LLView::handleRightMouseDown(x,y,mask); + if (mRightMouseDownSignal) + { + (*mRightMouseDownSignal)(this,x,y,mask); + } + return handled; } //virtual BOOL LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleRightMouseUp(x,y,mask); - if(mRightMouseUpSignal) - { - (*mRightMouseUpSignal)(this,x,y,mask); - } - return handled; + BOOL handled = LLView::handleRightMouseUp(x,y,mask); + if(mRightMouseUpSignal) + { + (*mRightMouseUpSignal)(this,x,y,mask); + } + return handled; } BOOL LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleDoubleClick(x, y, mask); - if (mDoubleClickSignal) - { - (*mDoubleClickSignal)(this, x, y, mask); - } - return handled; + BOOL handled = LLView::handleDoubleClick(x, y, mask); + if (mDoubleClickSignal) + { + (*mDoubleClickSignal)(this, x, y, mask); + } + return handled; } // can't tab to children of a non-tab-stop widget BOOL LLUICtrl::canFocusChildren() const { - return hasTabStop(); + return hasTabStop(); } void LLUICtrl::onCommit() { - if (mCommitSignal) - { - if (!mFunctionName.empty()) - { - LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL; - LLUIUsage::instance().logCommand(mFunctionName); - LLUIUsage::instance().logControl(getPathname()); - } - else - { - //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL; - } - (*mCommitSignal)(this, getValue()); - } + if (mCommitSignal) + { + if (!mFunctionName.empty()) + { + LL_DEBUGS("UIUsage") << "calling commit function " << mFunctionName << LL_ENDL; + LLUIUsage::instance().logCommand(mFunctionName); + LLUIUsage::instance().logControl(getPathname()); + } + else + { + //LL_DEBUGS("UIUsage") << "calling commit function " << "UNKNOWN" << LL_ENDL; + } + (*mCommitSignal)(this, getValue()); + } } //virtual BOOL LLUICtrl::isCtrl() const { - return TRUE; + return TRUE; } -//virtual +//virtual void LLUICtrl::setValue(const LLSD& value) { mViewModel->setValue(value); @@ -453,7 +453,7 @@ void LLUICtrl::setValue(const LLSD& value) //virtual LLSD LLUICtrl::getValue() const { - return mViewModel->getValue(); + return mViewModel->getValue(); } /// When two widgets are displaying the same data (e.g. during a skin @@ -469,66 +469,66 @@ void LLUICtrl::shareViewModelFrom(const LLUICtrl& other) //virtual LLViewModel* LLUICtrl::getViewModel() const { - return mViewModel; + return mViewModel; } //virtual BOOL LLUICtrl::postBuild() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - // - // Find all of the children that want to be in front and move them to the front - // - - if (getChildCount() > 0) - { - std::vector<LLUICtrl*> childrenToMoveToFront; - - for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) - { - LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(*child_it); + // + // Find all of the children that want to be in front and move them to the front + // - if (uictrl && uictrl->mRequestsFront) - { - childrenToMoveToFront.push_back(uictrl); - } - } - - for (std::vector<LLUICtrl*>::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it) - { - sendChildToFront(*it); - } - } + if (getChildCount() > 0) + { + std::vector<LLUICtrl*> childrenToMoveToFront; + + for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) + { + LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(*child_it); + + if (uictrl && uictrl->mRequestsFront) + { + childrenToMoveToFront.push_back(uictrl); + } + } + + for (std::vector<LLUICtrl*>::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it) + { + sendChildToFront(*it); + } + } - return LLView::postBuild(); + return LLView::postBuild(); } bool LLUICtrl::setControlValue(const LLSD& value) { - if (mControlVariable) - { - mControlVariable->set(value); - return true; - } - return false; + if (mControlVariable) + { + mControlVariable->set(value); + return true; + } + return false; } void LLUICtrl::setControlVariable(LLControlVariable* control) { - if (mControlVariable) - { - //RN: this will happen in practice, should we try to avoid it? - //LL_WARNS() << "setControlName called twice on same control!" << LL_ENDL; - mControlConnection.disconnect(); // disconnect current signal - mControlVariable = NULL; - } - - if (control) - { - mControlVariable = control; - mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value"))); - setValue(mControlVariable->getValue()); - } + if (mControlVariable) + { + //RN: this will happen in practice, should we try to avoid it? + //LL_WARNS() << "setControlName called twice on same control!" << LL_ENDL; + mControlConnection.disconnect(); // disconnect current signal + mControlVariable = NULL; + } + + if (control) + { + mControlVariable = control; + mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value"))); + setValue(mControlVariable->getValue()); + } } void LLUICtrl::removeControlVariable() @@ -543,204 +543,204 @@ void LLUICtrl::removeControlVariable() //virtual void LLUICtrl::setControlName(const std::string& control_name, LLView *context) { - if (context == NULL) - { - context = this; - } + if (context == NULL) + { + context = this; + } - // Register new listener - if (!control_name.empty()) - { - LLControlVariable* control = context->findControl(control_name); - if (!control) - { - LL_WARNS() << "Failed to assign control variable to " << getName() - << ": control "<< control_name << " does not exist." << LL_ENDL; - } - setControlVariable(control); - } + // Register new listener + if (!control_name.empty()) + { + LLControlVariable* control = context->findControl(control_name); + if (!control) + { + LL_WARNS() << "Failed to assign control variable to " << getName() + << ": control "<< control_name << " does not exist." << LL_ENDL; + } + setControlVariable(control); + } } void LLUICtrl::setEnabledControlVariable(LLControlVariable* control) { - if (mEnabledControlVariable) - { - mEnabledControlConnection.disconnect(); // disconnect current signal - mEnabledControlVariable = NULL; - } - if (control) - { - mEnabledControlVariable = control; - mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled"))); - setEnabled(mEnabledControlVariable->getValue().asBoolean()); - } + if (mEnabledControlVariable) + { + mEnabledControlConnection.disconnect(); // disconnect current signal + mEnabledControlVariable = NULL; + } + if (control) + { + mEnabledControlVariable = control; + mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled"))); + setEnabled(mEnabledControlVariable->getValue().asBoolean()); + } } void LLUICtrl::setDisabledControlVariable(LLControlVariable* control) { - if (mDisabledControlVariable) - { - mDisabledControlConnection.disconnect(); // disconnect current signal - mDisabledControlVariable = NULL; - } - if (control) - { - mDisabledControlVariable = control; - mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled"))); - setEnabled(!(mDisabledControlVariable->getValue().asBoolean())); - } + if (mDisabledControlVariable) + { + mDisabledControlConnection.disconnect(); // disconnect current signal + mDisabledControlVariable = NULL; + } + if (control) + { + mDisabledControlVariable = control; + mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled"))); + setEnabled(!(mDisabledControlVariable->getValue().asBoolean())); + } } void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control) { - if (mMakeVisibleControlVariable) - { - mMakeVisibleControlConnection.disconnect(); // disconnect current signal - mMakeVisibleControlVariable = NULL; - } - if (control) - { - mMakeVisibleControlVariable = control; - mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible"))); - setVisible(mMakeVisibleControlVariable->getValue().asBoolean()); - } + if (mMakeVisibleControlVariable) + { + mMakeVisibleControlConnection.disconnect(); // disconnect current signal + mMakeVisibleControlVariable = NULL; + } + if (control) + { + mMakeVisibleControlVariable = control; + mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("visible"))); + setVisible(mMakeVisibleControlVariable->getValue().asBoolean()); + } } void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control) { - if (mMakeInvisibleControlVariable) - { - mMakeInvisibleControlConnection.disconnect(); // disconnect current signal - mMakeInvisibleControlVariable = NULL; - } - if (control) - { - mMakeInvisibleControlVariable = control; - mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible"))); - setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean())); - } + if (mMakeInvisibleControlVariable) + { + mMakeInvisibleControlConnection.disconnect(); // disconnect current signal + mMakeInvisibleControlVariable = NULL; + } + if (control) + { + mMakeInvisibleControlVariable = control; + mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("invisible"))); + setVisible(!(mMakeInvisibleControlVariable->getValue().asBoolean())); + } } void LLUICtrl::setFunctionName(const std::string& function_name) { - mFunctionName = function_name; + mFunctionName = function_name; } // static bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type) { - LLUICtrl* ctrl = handle.get(); - if (ctrl) - { - if (type == "value") - { - ctrl->setValue(newvalue); - return true; - } - else if (type == "enabled") - { - ctrl->setEnabled(newvalue.asBoolean()); - return true; - } - else if(type =="disabled") - { - ctrl->setEnabled(!newvalue.asBoolean()); - return true; - } - else if (type == "visible") - { - ctrl->setVisible(newvalue.asBoolean()); - return true; - } - else if (type == "invisible") - { - ctrl->setVisible(!newvalue.asBoolean()); - return true; - } - } - return false; + LLUICtrl* ctrl = handle.get(); + if (ctrl) + { + if (type == "value") + { + ctrl->setValue(newvalue); + return true; + } + else if (type == "enabled") + { + ctrl->setEnabled(newvalue.asBoolean()); + return true; + } + else if(type =="disabled") + { + ctrl->setEnabled(!newvalue.asBoolean()); + return true; + } + else if (type == "visible") + { + ctrl->setVisible(newvalue.asBoolean()); + return true; + } + else if (type == "invisible") + { + ctrl->setVisible(!newvalue.asBoolean()); + return true; + } + } + return false; } // virtual -BOOL LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text ) -{ - return FALSE; +BOOL LLUICtrl::setTextArg( const std::string& key, const LLStringExplicit& text ) +{ + return FALSE; } // virtual -BOOL LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) -{ - return FALSE; +BOOL LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text ) +{ + return FALSE; } // virtual -LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface() -{ - return NULL; +LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface() +{ + return NULL; } // virtual -LLCtrlListInterface* LLUICtrl::getListInterface() -{ - return NULL; +LLCtrlListInterface* LLUICtrl::getListInterface() +{ + return NULL; } // virtual -LLCtrlScrollInterface* LLUICtrl::getScrollInterface() -{ - return NULL; +LLCtrlScrollInterface* LLUICtrl::getScrollInterface() +{ + return NULL; } BOOL LLUICtrl::hasFocus() const { - return (gFocusMgr.childHasKeyboardFocus(this)); + return (gFocusMgr.childHasKeyboardFocus(this)); } void LLUICtrl::setFocus(BOOL b) { - // focus NEVER goes to ui ctrls that are disabled! - if (!getEnabled()) - { - return; - } - if( b ) - { - if (!hasFocus()) - { - gFocusMgr.setKeyboardFocus( this ); - } - } - else - { - if( gFocusMgr.childHasKeyboardFocus(this)) - { - gFocusMgr.setKeyboardFocus( NULL ); - } - } + // focus NEVER goes to ui ctrls that are disabled! + if (!getEnabled()) + { + return; + } + if( b ) + { + if (!hasFocus()) + { + gFocusMgr.setKeyboardFocus( this ); + } + } + else + { + if( gFocusMgr.childHasKeyboardFocus(this)) + { + gFocusMgr.setKeyboardFocus( NULL ); + } + } } // virtual -void LLUICtrl::setTabStop( BOOL b ) -{ - mTabStop = b; +void LLUICtrl::setTabStop( BOOL b ) +{ + mTabStop = b; } // virtual -BOOL LLUICtrl::hasTabStop() const -{ - return mTabStop; +BOOL LLUICtrl::hasTabStop() const +{ + return mTabStop; } // virtual BOOL LLUICtrl::acceptsTextInput() const -{ - return FALSE; +{ + return FALSE; } //virtual BOOL LLUICtrl::isDirty() const { - return mViewModel->isDirty(); + return mViewModel->isDirty(); }; //virtual @@ -756,382 +756,382 @@ void LLUICtrl::onTabInto() } // virtual -void LLUICtrl::clear() +void LLUICtrl::clear() { } // virtual void LLUICtrl::setIsChrome(BOOL is_chrome) { - mIsChrome = is_chrome; + mIsChrome = is_chrome; } // virtual BOOL LLUICtrl::getIsChrome() const { - if (mIsChrome) - return TRUE; + if (mIsChrome) + return TRUE; - LLView* parent_ctrl = getParent(); - while (parent_ctrl) - { - if (parent_ctrl->isCtrl()) - return ((LLUICtrl*)parent_ctrl)->getIsChrome(); + LLView* parent_ctrl = getParent(); + while (parent_ctrl) + { + if (parent_ctrl->isCtrl()) + return ((LLUICtrl*)parent_ctrl)->getIsChrome(); - parent_ctrl = parent_ctrl->getParent(); - } + parent_ctrl = parent_ctrl->getParent(); + } - return FALSE; + return FALSE; } BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - // try to select default tab group child - LLViewQuery query = getTabOrderQuery(); - child_list_t result = query(this); - if(result.size() > 0) - { - LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); - if(!ctrl->hasFocus()) - { - ctrl->setFocus(TRUE); - ctrl->onTabInto(); - if(focus_flash) - { - gFocusMgr.triggerFocusFlash(); - } - } - return TRUE; - } - // search for text field first - if(prefer_text_fields) - { - LLViewQuery query = getTabOrderQuery(); - query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); - child_list_t result = query(this); - if(result.size() > 0) - { - LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); - if(!ctrl->hasFocus()) - { - ctrl->setFocus(TRUE); - ctrl->onTabInto(); - if(focus_flash) - { - gFocusMgr.triggerFocusFlash(); - } - } - return TRUE; - } - } - // no text field found, or we don't care about text fields - result = getTabOrderQuery().run(this); - if(result.size() > 0) - { - LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); - if(!ctrl->hasFocus()) - { - ctrl->setFocus(TRUE); - ctrl->onTabInto(); - if(focus_flash) - { - gFocusMgr.triggerFocusFlash(); - } - } - return TRUE; - } - return FALSE; + // try to select default tab group child + LLViewQuery query = getTabOrderQuery(); + child_list_t result = query(this); + if(result.size() > 0) + { + LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); + if(!ctrl->hasFocus()) + { + ctrl->setFocus(TRUE); + ctrl->onTabInto(); + if(focus_flash) + { + gFocusMgr.triggerFocusFlash(); + } + } + return TRUE; + } + // search for text field first + if(prefer_text_fields) + { + LLViewQuery query = getTabOrderQuery(); + query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); + child_list_t result = query(this); + if(result.size() > 0) + { + LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); + if(!ctrl->hasFocus()) + { + ctrl->setFocus(TRUE); + ctrl->onTabInto(); + if(focus_flash) + { + gFocusMgr.triggerFocusFlash(); + } + } + return TRUE; + } + } + // no text field found, or we don't care about text fields + result = getTabOrderQuery().run(this); + if(result.size() > 0) + { + LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back()); + if(!ctrl->hasFocus()) + { + ctrl->setFocus(TRUE); + ctrl->onTabInto(); + if(focus_flash) + { + gFocusMgr.triggerFocusFlash(); + } + } + return TRUE; + } + return FALSE; } BOOL LLUICtrl::focusNextItem(BOOL text_fields_only) { - // this assumes that this method is called on the focus root. - LLViewQuery query = getTabOrderQuery(); - static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); - if(text_fields_only || tab_to_text_fields_only) - { - query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); - } - child_list_t result = query(this); - return focusNext(result); + // this assumes that this method is called on the focus root. + LLViewQuery query = getTabOrderQuery(); + static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) + { + query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); + } + child_list_t result = query(this); + return focusNext(result); } BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only) { - // this assumes that this method is called on the focus root. - LLViewQuery query = getTabOrderQuery(); - static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); - if(text_fields_only || tab_to_text_fields_only) - { - query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); - } - child_list_t result = query(this); - return focusPrev(result); + // this assumes that this method is called on the focus root. + LLViewQuery query = getTabOrderQuery(); + static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) + { + query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); + } + child_list_t result = query(this); + return focusPrev(result); } LLUICtrl* LLUICtrl::findRootMostFocusRoot() { - LLUICtrl* focus_root = NULL; - LLUICtrl* next_view = this; - while(next_view && next_view->hasTabStop()) - { - if (next_view->isFocusRoot()) - { - focus_root = next_view; - } - next_view = next_view->getParentUICtrl(); - } + LLUICtrl* focus_root = NULL; + LLUICtrl* next_view = this; + while(next_view && next_view->hasTabStop()) + { + if (next_view->isFocusRoot()) + { + focus_root = next_view; + } + next_view = next_view->getParentUICtrl(); + } - return focus_root; + return focus_root; } // Skip over any parents that are not LLUICtrl's // Used in focus logic since only LLUICtrl elements can have focus LLUICtrl* LLUICtrl::getParentUICtrl() const { - LLView* parent = getParent(); - while (parent) - { - if (parent->isCtrl()) - { - return (LLUICtrl*)(parent); - } - else - { - parent = parent->getParent(); - } - } - return NULL; + LLView* parent = getParent(); + while (parent) + { + if (parent->isCtrl()) + { + return (LLUICtrl*)(parent); + } + else + { + parent = parent->getParent(); + } + } + return NULL; } bool LLUICtrl::findHelpTopic(std::string& help_topic_out) { - LLUICtrl* ctrl = this; - - // search back through the control's parents for a panel - // or tab with a help_topic string defined - while (ctrl) - { - LLPanel *panel = dynamic_cast<LLPanel *>(ctrl); - - if (panel) - { - - LLView *child; - LLPanel *subpanel = NULL; - - // does the panel have a sub-panel with a help topic? - bfs_tree_iterator_t it = beginTreeBFS(); - // skip ourselves - ++it; - for (; it != endTreeBFS(); ++it) - { - child = *it; - // do we have a panel with a help topic? - LLPanel *panel = dynamic_cast<LLPanel *>(child); - if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty()) - { - subpanel = panel; - break; - } - } - - if (subpanel) - { - help_topic_out = subpanel->getHelpTopic(); - return true; // success (subpanel) - } - - // does the panel have an active tab with a help topic? - LLPanel *tab_panel = NULL; - - it = beginTreeBFS(); - // skip ourselves - ++it; - for (; it != endTreeBFS(); ++it) - { - child = *it; - LLPanel *curTabPanel = NULL; - - // do we have a tab container? - LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child); - if (tab && tab->getVisible()) - { - curTabPanel = tab->getCurrentPanel(); - } - - // do we have an accordion tab? - LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child); - if (accordion && accordion->getDisplayChildren()) - { - curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView()); - } - - // if we found a valid tab, does it have a help topic? - if (curTabPanel && !curTabPanel->getHelpTopic().empty()) - { - tab_panel = curTabPanel; - break; - } - } - - if (tab_panel) - { - help_topic_out = tab_panel->getHelpTopic(); - return true; // success (tab) - } - - // otherwise, does the panel have a help topic itself? - if (!panel->getHelpTopic().empty()) - { - help_topic_out = panel->getHelpTopic(); - return true; // success (panel) - } - } - - ctrl = ctrl->getParentUICtrl(); - } - - return false; // no help topic found + LLUICtrl* ctrl = this; + + // search back through the control's parents for a panel + // or tab with a help_topic string defined + while (ctrl) + { + LLPanel *panel = dynamic_cast<LLPanel *>(ctrl); + + if (panel) + { + + LLView *child; + LLPanel *subpanel = NULL; + + // does the panel have a sub-panel with a help topic? + bfs_tree_iterator_t it = beginTreeBFS(); + // skip ourselves + ++it; + for (; it != endTreeBFS(); ++it) + { + child = *it; + // do we have a panel with a help topic? + LLPanel *panel = dynamic_cast<LLPanel *>(child); + if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty()) + { + subpanel = panel; + break; + } + } + + if (subpanel) + { + help_topic_out = subpanel->getHelpTopic(); + return true; // success (subpanel) + } + + // does the panel have an active tab with a help topic? + LLPanel *tab_panel = NULL; + + it = beginTreeBFS(); + // skip ourselves + ++it; + for (; it != endTreeBFS(); ++it) + { + child = *it; + LLPanel *curTabPanel = NULL; + + // do we have a tab container? + LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child); + if (tab && tab->getVisible()) + { + curTabPanel = tab->getCurrentPanel(); + } + + // do we have an accordion tab? + LLAccordionCtrlTab* accordion = dynamic_cast<LLAccordionCtrlTab *>(child); + if (accordion && accordion->getDisplayChildren()) + { + curTabPanel = dynamic_cast<LLPanel *>(accordion->getAccordionView()); + } + + // if we found a valid tab, does it have a help topic? + if (curTabPanel && !curTabPanel->getHelpTopic().empty()) + { + tab_panel = curTabPanel; + break; + } + } + + if (tab_panel) + { + help_topic_out = tab_panel->getHelpTopic(); + return true; // success (tab) + } + + // otherwise, does the panel have a help topic itself? + if (!panel->getHelpTopic().empty()) + { + help_topic_out = panel->getHelpTopic(); + return true; // success (panel) + } + } + + ctrl = ctrl->getParentUICtrl(); + } + + return false; // no help topic found } // *TODO: Deprecate; for backwards compatability only: boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data) { - return setCommitCallback( boost::bind(cb, _1, data)); + return setCommitCallback( boost::bind(cb, _1, data)); } boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ) { - if (!mValidateSignal) mValidateSignal = new enable_signal_t(); + if (!mValidateSignal) mValidateSignal = new enable_signal_t(); - return mValidateSignal->connect(boost::bind(cb, _2)); + return mValidateSignal->connect(boost::bind(cb, _2)); } // virtual -void LLUICtrl::setTentative(BOOL b) -{ - mTentative = b; +void LLUICtrl::setTentative(BOOL b) +{ + mTentative = b; } // virtual -BOOL LLUICtrl::getTentative() const -{ - return mTentative; +BOOL LLUICtrl::getTentative() const +{ + return mTentative; } // virtual -void LLUICtrl::setColor(const LLColor4& color) +void LLUICtrl::setColor(const LLColor4& color) { } F32 LLUICtrl::getCurrentTransparency() { - F32 alpha = 0; + F32 alpha = 0; - switch(mTransparencyType) - { - case TT_DEFAULT: - alpha = getDrawContext().mAlpha; - break; + switch(mTransparencyType) + { + case TT_DEFAULT: + alpha = getDrawContext().mAlpha; + break; - case TT_ACTIVE: - alpha = sActiveControlTransparency; - break; + case TT_ACTIVE: + alpha = sActiveControlTransparency; + break; - case TT_INACTIVE: - alpha = sInactiveControlTransparency; - break; + case TT_INACTIVE: + alpha = sInactiveControlTransparency; + break; - case TT_FADING: - alpha = sInactiveControlTransparency / 2; - break; - } + case TT_FADING: + alpha = sInactiveControlTransparency / 2; + break; + } - return alpha; + return alpha; } void LLUICtrl::setTransparencyType(ETypeTransparency type) { - mTransparencyType = type; + mTransparencyType = type; } boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb) { - return setCommitCallback(initCommitCallback(cb)); + return setCommitCallback(initCommitCallback(cb)); } boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb) { - return setValidateCallback(initEnableCallback(cb)); + return setValidateCallback(initEnableCallback(cb)); } -boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mCommitSignal) mCommitSignal = new commit_signal_t(); +boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mCommitSignal) mCommitSignal = new commit_signal_t(); - return mCommitSignal->connect(cb); + return mCommitSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) -{ - if (!mValidateSignal) mValidateSignal = new enable_signal_t(); +boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) +{ + if (!mValidateSignal) mValidateSignal = new enable_signal_t(); - return mValidateSignal->connect(cb); + return mValidateSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t(); +boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t(); - return mMouseEnterSignal->connect(cb); + return mMouseEnterSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) -{ - if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t(); +boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t(); - return mMouseLeaveSignal->connect(cb); + return mMouseLeaveSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) -{ - if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t(); +boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) +{ + if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t(); - return mMouseDownSignal->connect(cb); + return mMouseDownSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) -{ - if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t(); +boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) +{ + if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t(); - return mMouseUpSignal->connect(cb); + return mMouseUpSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) -{ - if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t(); +boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) +{ + if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t(); - return mRightMouseDownSignal->connect(cb); + return mRightMouseDownSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) -{ - if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t(); +boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) +{ + if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t(); - return mRightMouseUpSignal->connect(cb); + return mRightMouseUpSignal->connect(cb); } -boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) -{ - if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t(); +boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) +{ + if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t(); - return mDoubleClickSignal->connect(cb); + return mDoubleClickSignal->connect(cb); } void LLUICtrl::addInfo(LLSD & info) { - LLView::addInfo(info); - info["value"] = getValue(); + LLView::addInfo(info); + info["value"] = getValue(); } diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index cffb9933d4..d21e8dc1c6 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -1,4 +1,4 @@ -/** +/** * @file lluictrl.h * @author James Cook, Richard Nelson, Tom Yedwab * @brief Abstract base class for UI controls @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,304 +36,305 @@ #include "llinitparam.h" #include "llview.h" -#include "llviewmodel.h" // *TODO move dependency to .cpp file +#include "llviewmodel.h" // *TODO move dependency to .cpp file #include "llsearchablecontrol.h" const BOOL TAKE_FOCUS_YES = TRUE; const BOOL TAKE_FOCUS_NO = FALSE; +const S32 DROP_SHADOW_FLOATER = 5; class LLUICtrl - : public LLView, public boost::signals2::trackable + : public LLView, public boost::signals2::trackable { public: - typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t; - typedef boost::signals2::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t; - // *TODO: add xml support for this type of signal in the future - typedef boost::signals2::signal<void (LLUICtrl* ctrl, S32 x, S32 y, MASK mask)> mouse_signal_t; - - typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t; - typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t; - - struct CallbackParam : public LLInitParam::Block<CallbackParam> - { - Ignored name; - - Optional<std::string> function_name; - Optional<LLSD> parameter; - - Optional<std::string> control_name; - - CallbackParam(); - }; - - struct CommitCallbackParam : public LLInitParam::Block<CommitCallbackParam, CallbackParam > - { - Optional<commit_callback_t> function; - }; - - // also used for visible callbacks - struct EnableCallbackParam : public LLInitParam::Block<EnableCallbackParam, CallbackParam > - { - Optional<enable_callback_t> function; - }; - - struct EnableControls : public LLInitParam::ChoiceBlock<EnableControls> - { - Alternative<std::string> enabled; - Alternative<std::string> disabled; - - EnableControls(); - }; - struct ControlVisibility : public LLInitParam::ChoiceBlock<ControlVisibility> - { - Alternative<std::string> visible; - Alternative<std::string> invisible; - - ControlVisibility(); - }; - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Optional<std::string> label; - Optional<bool> tab_stop, - chrome, - requests_front; - Optional<LLSD> initial_value; - - Optional<CommitCallbackParam> init_callback, - commit_callback; - Optional<EnableCallbackParam> validate_callback; - - Optional<CommitCallbackParam> mouseenter_callback, - mouseleave_callback; - - Optional<std::string> control_name; - Optional<EnableControls> enabled_controls; - Optional<ControlVisibility> controls_visibility; - - // font params - Optional<const LLFontGL*> font; - Optional<LLFontGL::HAlign> font_halign; - Optional<LLFontGL::VAlign> font_valign; - - // cruft from LLXMLNode implementation - Ignored type, - length; - - Params(); - }; - - enum ETypeTransparency - { - TT_DEFAULT, - TT_ACTIVE, // focused floater - TT_INACTIVE, // other floaters - TT_FADING, // fading toast - }; - /*virtual*/ ~LLUICtrl(); - - void initFromParams(const Params& p); + typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t; + typedef boost::signals2::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t; + // *TODO: add xml support for this type of signal in the future + typedef boost::signals2::signal<void (LLUICtrl* ctrl, S32 x, S32 y, MASK mask)> mouse_signal_t; + + typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t; + typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t; + + struct CallbackParam : public LLInitParam::Block<CallbackParam> + { + Ignored name; + + Optional<std::string> function_name; + Optional<LLSD> parameter; + + Optional<std::string> control_name; + + CallbackParam(); + }; + + struct CommitCallbackParam : public LLInitParam::Block<CommitCallbackParam, CallbackParam > + { + Optional<commit_callback_t> function; + }; + + // also used for visible callbacks + struct EnableCallbackParam : public LLInitParam::Block<EnableCallbackParam, CallbackParam > + { + Optional<enable_callback_t> function; + }; + + struct EnableControls : public LLInitParam::ChoiceBlock<EnableControls> + { + Alternative<std::string> enabled; + Alternative<std::string> disabled; + + EnableControls(); + }; + struct ControlVisibility : public LLInitParam::ChoiceBlock<ControlVisibility> + { + Alternative<std::string> visible; + Alternative<std::string> invisible; + + ControlVisibility(); + }; + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Optional<std::string> label; + Optional<bool> tab_stop, + chrome, + requests_front; + Optional<LLSD> initial_value; + + Optional<CommitCallbackParam> init_callback, + commit_callback; + Optional<EnableCallbackParam> validate_callback; + + Optional<CommitCallbackParam> mouseenter_callback, + mouseleave_callback; + + Optional<std::string> control_name; + Optional<EnableControls> enabled_controls; + Optional<ControlVisibility> controls_visibility; + + // font params + Optional<const LLFontGL*> font; + Optional<LLFontGL::HAlign> font_halign; + Optional<LLFontGL::VAlign> font_valign; + + // cruft from LLXMLNode implementation + Ignored type, + length; + + Params(); + }; + + enum ETypeTransparency + { + TT_DEFAULT, + TT_ACTIVE, // focused floater + TT_INACTIVE, // other floaters + TT_FADING, // fading toast + }; + /*virtual*/ ~LLUICtrl(); + + void initFromParams(const Params& p); protected: - friend class LLUICtrlFactory; - static const Params& getDefaultParams(); - LLUICtrl(const Params& p = getDefaultParams(), + friend class LLUICtrlFactory; + static const Params& getDefaultParams(); + LLUICtrl(const Params& p = getDefaultParams(), const LLViewModelPtr& viewmodel=LLViewModelPtr(new LLViewModel)); - - commit_signal_t::slot_type initCommitCallback(const CommitCallbackParam& cb); - enable_signal_t::slot_type initEnableCallback(const EnableCallbackParam& cb); - // We need this virtual so we can override it with derived versions - virtual LLViewModel* getViewModel() const; + commit_signal_t::slot_type initCommitCallback(const CommitCallbackParam& cb); + enable_signal_t::slot_type initEnableCallback(const EnableCallbackParam& cb); + + // We need this virtual so we can override it with derived versions + virtual LLViewModel* getViewModel() const; // We shouldn't ever need to set this directly //virtual void setViewModel(const LLViewModelPtr&); - virtual BOOL postBuild(); - + virtual BOOL postBuild(); + public: - // LLView interface - /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - /*virtual*/ BOOL isCtrl() const; - /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL canFocusChildren() const; - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - - // From LLFocusableElement - /*virtual*/ void setFocus( BOOL b ); - /*virtual*/ BOOL hasFocus() const; - - // New virtuals - - // Return NULL by default (overrride if the class has the appropriate interface) - virtual class LLCtrlSelectionInterface* getSelectionInterface(); - virtual class LLCtrlListInterface* getListInterface(); - virtual class LLCtrlScrollInterface* getScrollInterface(); - - bool setControlValue(const LLSD& value); - void setControlVariable(LLControlVariable* control); - virtual void setControlName(const std::string& control, LLView *context = NULL); + // LLView interface + /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + /*virtual*/ BOOL isCtrl() const; + /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL canFocusChildren() const; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + + // From LLFocusableElement + /*virtual*/ void setFocus( BOOL b ); + /*virtual*/ BOOL hasFocus() const; + + // New virtuals + + // Return NULL by default (overrride if the class has the appropriate interface) + virtual class LLCtrlSelectionInterface* getSelectionInterface(); + virtual class LLCtrlListInterface* getListInterface(); + virtual class LLCtrlScrollInterface* getScrollInterface(); + + bool setControlValue(const LLSD& value); + void setControlVariable(LLControlVariable* control); + virtual void setControlName(const std::string& control, LLView *context = NULL); void removeControlVariable(); - - LLControlVariable* getControlVariable() { return mControlVariable; } - - void setEnabledControlVariable(LLControlVariable* control); - void setDisabledControlVariable(LLControlVariable* control); - void setMakeVisibleControlVariable(LLControlVariable* control); - void setMakeInvisibleControlVariable(LLControlVariable* control); - - void setFunctionName(const std::string& function_name); - - virtual void setTentative(BOOL b); - virtual BOOL getTentative() const; - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; + + LLControlVariable* getControlVariable() { return mControlVariable; } + + void setEnabledControlVariable(LLControlVariable* control); + void setDisabledControlVariable(LLControlVariable* control); + void setMakeVisibleControlVariable(LLControlVariable* control); + void setMakeInvisibleControlVariable(LLControlVariable* control); + + void setFunctionName(const std::string& function_name); + + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; + virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; /// When two widgets are displaying the same data (e.g. during a skin /// change), share their ViewModel. virtual void shareViewModelFrom(const LLUICtrl& other); - virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); - virtual void setIsChrome(BOOL is_chrome); - - virtual BOOL acceptsTextInput() const; // Defaults to false - - // A control is dirty if the user has modified its value. - // Editable controls should override this. - virtual BOOL isDirty() const; // Defauls to false - virtual void resetDirty(); //Defaults to no-op - - // Call appropriate callback - virtual void onCommit(); - - // Default to no-op: - virtual void onTabInto(); - - // Clear any user-provided input (text in a text editor, checked checkbox, - // selected radio button, etc.). Defaults to no-op. - virtual void clear(); - - virtual void setColor(const LLColor4& color); - - // Ansariel: Changed to virtual. We might want to change the transparency ourself! - virtual F32 getCurrentTransparency(); - - void setTransparencyType(ETypeTransparency type); - ETypeTransparency getTransparencyType() const {return mTransparencyType;} - - BOOL focusNextItem(BOOL text_entry_only); - BOOL focusPrevItem(BOOL text_entry_only); - BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); - - // Non Virtuals - LLHandle<LLUICtrl> getHandle() const { return getDerivedHandle<LLUICtrl>(); } - BOOL getIsChrome() const; - - void setTabStop( BOOL b ); - BOOL hasTabStop() const; - - LLUICtrl* getParentUICtrl() const; - - // return true if help topic found by crawling through parents - - // topic then put in help_topic_out - bool findHelpTopic(std::string& help_topic_out); - - boost::signals2::connection setCommitCallback(const CommitCallbackParam& cb); - boost::signals2::connection setValidateCallback(const EnableCallbackParam& cb); - - boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ); - - boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ); - boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ); - - boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); - boost::signals2::connection setMouseUpCallback( const mouse_signal_t::slot_type& cb ); - boost::signals2::connection setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ); - boost::signals2::connection setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ); - - boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ); - - // *TODO: Deprecate; for backwards compatability only: - boost::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data); - boost::signals2::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ); - - LLUICtrl* findRootMostFocusRoot(); - - class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter> - { - LLSINGLETON_EMPTY_CTOR(LLTextInputFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override - { - return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->acceptsTextInput(), TRUE); - } - }; - - template <typename F, typename DERIVED> class CallbackRegistry : public LLRegistrySingleton<std::string, F, DERIVED > - {}; - - class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry> - { - LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry); - }; - // the enable callback registry is also used for visiblity callbacks - class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry> - { - LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); - }; - + virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); + virtual void setIsChrome(BOOL is_chrome); + + virtual BOOL acceptsTextInput() const; // Defaults to false + + // A control is dirty if the user has modified its value. + // Editable controls should override this. + virtual BOOL isDirty() const; // Defauls to false + virtual void resetDirty(); //Defaults to no-op + + // Call appropriate callback + virtual void onCommit(); + + // Default to no-op: + virtual void onTabInto(); + + // Clear any user-provided input (text in a text editor, checked checkbox, + // selected radio button, etc.). Defaults to no-op. + virtual void clear(); + + virtual void setColor(const LLColor4& color); + + // Ansariel: Changed to virtual. We might want to change the transparency ourself! + virtual F32 getCurrentTransparency(); + + void setTransparencyType(ETypeTransparency type); + ETypeTransparency getTransparencyType() const {return mTransparencyType;} + + BOOL focusNextItem(BOOL text_entry_only); + BOOL focusPrevItem(BOOL text_entry_only); + BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); + + // Non Virtuals + LLHandle<LLUICtrl> getHandle() const { return getDerivedHandle<LLUICtrl>(); } + BOOL getIsChrome() const; + + void setTabStop( BOOL b ); + BOOL hasTabStop() const; + + LLUICtrl* getParentUICtrl() const; + + // return true if help topic found by crawling through parents - + // topic then put in help_topic_out + bool findHelpTopic(std::string& help_topic_out); + + boost::signals2::connection setCommitCallback(const CommitCallbackParam& cb); + boost::signals2::connection setValidateCallback(const EnableCallbackParam& cb); + + boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ); + + boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ); + + boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ); + boost::signals2::connection setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ); + + boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ); + + // *TODO: Deprecate; for backwards compatability only: + boost::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data); + boost::signals2::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ); + + LLUICtrl* findRootMostFocusRoot(); + + class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter> + { + LLSINGLETON_EMPTY_CTOR(LLTextInputFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override + { + return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->acceptsTextInput(), TRUE); + } + }; + + template <typename F, typename DERIVED> class CallbackRegistry : public LLRegistrySingleton<std::string, F, DERIVED > + {}; + + class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry> + { + LLSINGLETON_EMPTY_CTOR(CommitCallbackRegistry); + }; + // the enable callback registry is also used for visiblity callbacks + class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry> + { + LLSINGLETON_EMPTY_CTOR(EnableCallbackRegistry); + }; + protected: - static bool controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type); + static bool controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type); + + commit_signal_t* mCommitSignal; + enable_signal_t* mValidateSignal; - commit_signal_t* mCommitSignal; - enable_signal_t* mValidateSignal; + commit_signal_t* mMouseEnterSignal; + commit_signal_t* mMouseLeaveSignal; - commit_signal_t* mMouseEnterSignal; - commit_signal_t* mMouseLeaveSignal; - - mouse_signal_t* mMouseDownSignal; - mouse_signal_t* mMouseUpSignal; - mouse_signal_t* mRightMouseDownSignal; - mouse_signal_t* mRightMouseUpSignal; + mouse_signal_t* mMouseDownSignal; + mouse_signal_t* mMouseUpSignal; + mouse_signal_t* mRightMouseDownSignal; + mouse_signal_t* mRightMouseUpSignal; + + mouse_signal_t* mDoubleClickSignal; - mouse_signal_t* mDoubleClickSignal; - LLViewModelPtr mViewModel; - LLControlVariable* mControlVariable; - boost::signals2::connection mControlConnection; - LLControlVariable* mEnabledControlVariable; - boost::signals2::connection mEnabledControlConnection; - LLControlVariable* mDisabledControlVariable; - boost::signals2::connection mDisabledControlConnection; - LLControlVariable* mMakeVisibleControlVariable; - boost::signals2::connection mMakeVisibleControlConnection; - LLControlVariable* mMakeInvisibleControlVariable; - boost::signals2::connection mMakeInvisibleControlConnection; - - std::string mFunctionName; - - static F32 sActiveControlTransparency; - static F32 sInactiveControlTransparency; - - virtual void addInfo(LLSD & info); - + LLControlVariable* mControlVariable; + boost::signals2::connection mControlConnection; + LLControlVariable* mEnabledControlVariable; + boost::signals2::connection mEnabledControlConnection; + LLControlVariable* mDisabledControlVariable; + boost::signals2::connection mDisabledControlConnection; + LLControlVariable* mMakeVisibleControlVariable; + boost::signals2::connection mMakeVisibleControlConnection; + LLControlVariable* mMakeInvisibleControlVariable; + boost::signals2::connection mMakeInvisibleControlConnection; + + std::string mFunctionName; + + static F32 sActiveControlTransparency; + static F32 sInactiveControlTransparency; + + virtual void addInfo(LLSD & info); + private: - BOOL mIsChrome; - BOOL mRequestsFront; - BOOL mTabStop; - BOOL mTentative; + BOOL mIsChrome; + BOOL mRequestsFront; + BOOL mTabStop; + BOOL mTentative; - ETypeTransparency mTransparencyType; + ETypeTransparency mTransparencyType; }; // Build time optimization, generate once in .cpp file #ifndef LLUICTRL_CPP extern template class LLUICtrl* LLView::getChild<class LLUICtrl>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif // LL_LLUICTRL_H diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index a85db17c7f..f3649d68a7 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lluictrlfactory.cpp * @brief Factory class for creating UI controls * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,17 +50,17 @@ class LLUICtrlLocate : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Params() - { - name = "locate"; - tab_stop = false; - } - }; - - LLUICtrlLocate(const Params& p) : LLUICtrl(p) {} - virtual void draw() { } + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Params() + { + name = "locate"; + tab_stop = false; + } + }; + + LLUICtrlLocate(const Params& p) : LLUICtrl(p) {} + virtual void draw() { } }; @@ -73,83 +73,83 @@ template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance( // LLUICtrlFactory() //----------------------------------------------------------------------------- LLUICtrlFactory::LLUICtrlFactory() - : mDummyPanel(NULL) // instantiated when first needed + : mDummyPanel(NULL) // instantiated when first needed { } LLUICtrlFactory::~LLUICtrlFactory() { - // go ahead and leak mDummyPanel since this is static destructor time - //delete mDummyPanel; - //mDummyPanel = NULL; + // go ahead and leak mDummyPanel since this is static destructor time + //delete mDummyPanel; + //mDummyPanel = NULL; } void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block) { - std::string filename = gDirUtilp->add("widgets", widget_tag + ".xml"); - LLXMLNodePtr root_node; - std::vector<std::string> search_paths = - gDirUtilp->findSkinnedFilenames(LLDir::XUI, filename); - - if (search_paths.empty()) - { - return; - } - - // "en" version, the default-language version of the file. - std::string base_filename = search_paths.front(); - if (!base_filename.empty()) - { - LLUICtrlFactory::instance().pushFileName(base_filename); - - if (!LLXMLNode::getLayeredXMLNode(root_node, search_paths)) - { - LL_WARNS() << "Couldn't parse widget from: " << base_filename << LL_ENDL; - return; - } - LLXUIParser parser; - parser.readXUI(root_node, block, base_filename); - LLUICtrlFactory::instance().popFileName(); - } + std::string filename = gDirUtilp->add("widgets", widget_tag + ".xml"); + LLXMLNodePtr root_node; + std::vector<std::string> search_paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, filename); + + if (search_paths.empty()) + { + return; + } + + // "en" version, the default-language version of the file. + std::string base_filename = search_paths.front(); + if (!base_filename.empty()) + { + LLUICtrlFactory::instance().pushFileName(base_filename); + + if (!LLXMLNode::getLayeredXMLNode(root_node, search_paths)) + { + LL_WARNS() << "Couldn't parse widget from: " << base_filename << LL_ENDL; + return; + } + LLXUIParser parser; + parser.readXUI(root_node, block, base_filename); + LLUICtrlFactory::instance().popFileName(); + } } -//static +//static void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if (node.isNull()) return; - - for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) - { - LLXMLNodePtr outputChild; - if (output_node) - { - outputChild = output_node->createChild("", FALSE); - } - - if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, registry, outputChild)) - { - // child_node is not a valid child for the current parent - std::string child_name = std::string(child_node->getName()->mString); - if (LLDefaultChildRegistry::instance().getValue(child_name)) - { - // This means that the registry assocaited with the parent widget does not have an entry - // for the child widget - // You might need to add something like: - // static ParentWidgetRegistry::Register<ChildWidgetType> register("child_widget_name"); - LL_WARNS() << child_name << " is not a valid child of " << node->getName()->mString << LL_ENDL; - } - else - { - LL_WARNS() << "Could not create widget named " << child_node->getName()->mString << LL_ENDL; - } - } - - if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty()) - { - output_node->deleteChild(outputChild); - } - } + if (node.isNull()) return; + + for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) + { + LLXMLNodePtr outputChild; + if (output_node) + { + outputChild = output_node->createChild("", FALSE); + } + + if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, registry, outputChild)) + { + // child_node is not a valid child for the current parent + std::string child_name = std::string(child_node->getName()->mString); + if (LLDefaultChildRegistry::instance().getValue(child_name)) + { + // This means that the registry assocaited with the parent widget does not have an entry + // for the child widget + // You might need to add something like: + // static ParentWidgetRegistry::Register<ChildWidgetType> register("child_widget_name"); + LL_WARNS() << child_name << " is not a valid child of " << node->getName()->mString << LL_ENDL; + } + else + { + LL_WARNS() << "Could not create widget named " << child_node->getName()->mString << LL_ENDL; + } + } + + if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty()) + { + output_node->deleteChild(outputChild); + } + } } @@ -160,16 +160,16 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo LLDir::ESkinConstraint constraint) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - std::vector<std::string> paths = - gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint); + std::vector<std::string> paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint); - if (paths.empty()) - { - // sometimes whole path is passed in as filename - paths.push_back(xui_filename); - } + if (paths.empty()) + { + // sometimes whole path is passed in as filename + paths.push_back(xui_filename); + } - return LLXMLNode::getLayeredXMLNode(root, paths); + return LLXMLNode::getLayeredXMLNode(root, paths); } @@ -178,7 +178,7 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo //----------------------------------------------------------------------------- S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename) { - return 0; + return 0; } //----------------------------------------------------------------------------- @@ -187,93 +187,93 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename) LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - std::string ctrl_type = node->getName()->mString; - LLStringUtil::toLower(ctrl_type); - - const LLWidgetCreatorFunc* funcp = registry.getValue(ctrl_type); - if (funcp == NULL) - { - return NULL; - } - - if (parent == NULL) - { - if (mDummyPanel == NULL) - { - LLPanel::Params p; - mDummyPanel = create<LLPanel>(p); - } - parent = mDummyPanel; - } - LLView *view = (*funcp)(node, parent, output_node); - - return view; + std::string ctrl_type = node->getName()->mString; + LLStringUtil::toLower(ctrl_type); + + const LLWidgetCreatorFunc* funcp = registry.getValue(ctrl_type); + if (funcp == NULL) + { + return NULL; + } + + if (parent == NULL) + { + if (mDummyPanel == NULL) + { + LLPanel::Params p; + mDummyPanel = create<LLPanel>(p); + } + parent = mDummyPanel; + } + LLView *view = (*funcp)(node, parent, output_node); + + return view; } -std::string LLUICtrlFactory::getCurFileName() -{ - return mFileNames.empty() ? "" : mFileNames.back(); +std::string LLUICtrlFactory::getCurFileName() +{ + return mFileNames.empty() ? "" : mFileNames.back(); } -void LLUICtrlFactory::pushFileName(const std::string& name) +void LLUICtrlFactory::pushFileName(const std::string& name) { - // Here we seem to be looking for the default language file ("en") rather - // than the localized one, if any. - mFileNames.push_back(gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, name)); + // Here we seem to be looking for the default language file ("en") rather + // than the localized one, if any. + mFileNames.push_back(gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, name)); } -void LLUICtrlFactory::popFileName() -{ - mFileNames.pop_back(); +void LLUICtrlFactory::popFileName() +{ + mFileNames.pop_back(); } //static void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group) { - if (tab_group == S32_MAX) tab_group = parent->getLastTabGroup(); - parent->addChild(view, tab_group); + if (tab_group == S32_MAX) tab_group = parent->getLastTabGroup(); + parent->addChild(view, tab_group); } -//static +//static void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest) { - dest->setName(src->getName()->mString); + dest->setName(src->getName()->mString); } template<typename T> const LLInitParam::BaseBlock& get_empty_param_block() { - static typename T::Params params; - return params; + static typename T::Params params; + return params; } // adds a widget and its param block to various registries -//static +//static void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& name) { - // associate parameter block type with template .xml file - std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type); - if (existing_name != NULL) - { - if(*existing_name != name) - { - std::cerr << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << std::endl; - // forcing crash here - char* foo = 0; - *foo = 1; - } - else - { - // widget already registered this name - return; - } - } - - LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, name); - //FIXME: comment this in when working on schema generation - //LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type); - //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>); + // associate parameter block type with template .xml file + std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type); + if (existing_name != NULL) + { + if(*existing_name != name) + { + std::cerr << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << std::endl; + // forcing crash here + char* foo = 0; + *foo = 1; + } + else + { + // widget already registered this name + return; + } + } + + LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, name); + //FIXME: comment this in when working on schema generation + //LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type); + //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>); } diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 6e585abfc0..a07f9b7dae 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -1,25 +1,25 @@ -/** +/** * @file lluictrlfactory.h * @brief Factory class for creating UI controls * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,39 +44,39 @@ template <typename DERIVED_TYPE> class LLChildRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> { public: - typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t; - // local static instance for registering a particular widget - template<typename T> - class Register : public super_t::StaticRegistrar - { - public: - // register with either the provided builder, or the generic templated builder - Register(const char* tag, LLWidgetCreatorFunc func = NULL); - }; + typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t; + // local static instance for registering a particular widget + template<typename T> + class Register : public super_t::StaticRegistrar + { + public: + // register with either the provided builder, or the generic templated builder + Register(const char* tag, LLWidgetCreatorFunc func = NULL); + }; protected: - LLChildRegistry() {} + LLChildRegistry() {} }; class LLDefaultChildRegistry : public LLChildRegistry<LLDefaultChildRegistry> { - LLSINGLETON_EMPTY_CTOR(LLDefaultChildRegistry); + LLSINGLETON_EMPTY_CTOR(LLDefaultChildRegistry); }; // lookup widget name by type -class LLWidgetNameRegistry -: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry> +class LLWidgetNameRegistry +: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry> { - LLSINGLETON_EMPTY_CTOR(LLWidgetNameRegistry); + LLSINGLETON_EMPTY_CTOR(LLWidgetNameRegistry); }; // lookup function for generating empty param block by widget type // this is used for schema generation //typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)(); //class LLDefaultParamBlockRegistry -//: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry> +//: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry> //{ -// LLSINGLETON(LLDefaultParamBlockRegistry); +// LLSINGLETON(LLDefaultParamBlockRegistry); //}; // Build time optimization, generate this once in .cpp file @@ -86,221 +86,221 @@ extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getIn class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory> { - LLSINGLETON(LLUICtrlFactory); - ~LLUICtrlFactory(); - - // only partial specialization allowed in inner classes, so use extra dummy parameter - template <typename PARAM_BLOCK, int DUMMY> - class ParamDefaults - { - public: - ParamDefaults(); - const PARAM_BLOCK& get() { return mPrototype; } - - private: - PARAM_BLOCK mPrototype; - }; - - // base case for recursion, there are NO base classes of LLInitParam::BaseBlock - template<int DUMMY> - class ParamDefaults<LLInitParam::BaseBlock, DUMMY> - { - public: - ParamDefaults(); - const LLInitParam::BaseBlock& get() { return mBaseBlock; } - private: - LLInitParam::BaseBlock mBaseBlock; - }; + LLSINGLETON(LLUICtrlFactory); + ~LLUICtrlFactory(); + + // only partial specialization allowed in inner classes, so use extra dummy parameter + template <typename PARAM_BLOCK, int DUMMY> + class ParamDefaults + { + public: + ParamDefaults(); + const PARAM_BLOCK& get() { return mPrototype; } + + private: + PARAM_BLOCK mPrototype; + }; + + // base case for recursion, there are NO base classes of LLInitParam::BaseBlock + template<int DUMMY> + class ParamDefaults<LLInitParam::BaseBlock, DUMMY> + { + public: + ParamDefaults(); + const LLInitParam::BaseBlock& get() { return mBaseBlock; } + private: + LLInitParam::BaseBlock mBaseBlock; + }; public: - // get default parameter block for widget of a specific type - template<typename T> - static const typename T::Params& getDefaultParams() - { - return instance().mParamDefaultsMap.obtain< ParamDefaults<typename T::Params, 0> >().get(); - } - - // Does what you want for LLFloaters and LLPanels - // Returns 0 on success - S32 saveToXML(LLView* viewp, const std::string& filename); - - // filename tracking for debugging info - std::string getCurFileName(); - void pushFileName(const std::string& name); - void popFileName(); - - template<typename T> - static T* create(typename T::Params& params, LLView* parent = NULL) - { - params.fillFrom(instance().mParamDefaultsMap.obtain< - ParamDefaults<typename T::Params, 0> >().get()); - - T* widget = createWidgetImpl<T>(params, parent); - if (widget) - { - widget->postBuild(); - } - - return widget; - } - - LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t&, LLXMLNodePtr output_node ); - - template<typename T> - static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry) - { - T* widget = NULL; - - instance().pushFileName(filename); - { - LLXMLNodePtr root_node; - - if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) - { + // get default parameter block for widget of a specific type + template<typename T> + static const typename T::Params& getDefaultParams() + { + return instance().mParamDefaultsMap.obtain< ParamDefaults<typename T::Params, 0> >().get(); + } + + // Does what you want for LLFloaters and LLPanels + // Returns 0 on success + S32 saveToXML(LLView* viewp, const std::string& filename); + + // filename tracking for debugging info + std::string getCurFileName(); + void pushFileName(const std::string& name); + void popFileName(); + + template<typename T> + static T* create(typename T::Params& params, LLView* parent = NULL) + { + params.fillFrom(instance().mParamDefaultsMap.obtain< + ParamDefaults<typename T::Params, 0> >().get()); + + T* widget = createWidgetImpl<T>(params, parent); + if (widget) + { + widget->postBuild(); + } + + return widget; + } + + LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t&, LLXMLNodePtr output_node ); + + template<typename T> + static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry) + { + T* widget = NULL; + + instance().pushFileName(filename); + { + LLXMLNodePtr root_node; + + if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) + { LL_WARNS() << "Couldn't parse XUI from path: " << instance().getCurFileName() << ", from filename: " << filename << LL_ENDL; - goto fail; - } - - LLView* view = getInstance()->createFromXML(root_node, parent, filename, registry, NULL); - if (view) - { - widget = dynamic_cast<T*>(view); - // not of right type, so delete it - if (!widget) - { - LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL; - - deleteView(view); - view = NULL; - } - } - } + goto fail; + } + + LLView* view = getInstance()->createFromXML(root_node, parent, filename, registry, NULL); + if (view) + { + widget = dynamic_cast<T*>(view); + // not of right type, so delete it + if (!widget) + { + LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL; + + deleteView(view); + view = NULL; + } + } + } fail: - instance().popFileName(); - return widget; - } + instance().popFileName(); + return widget; + } - template<class T> - static T* getDefaultWidget(const std::string& name) - { - typename T::Params widget_params; - widget_params.name = name; - return create<T>(widget_params); - } + template<class T> + static T* getDefaultWidget(const std::string& name) + { + typename T::Params widget_params; + widget_params.name = name; + return create<T>(widget_params); + } - static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL); + static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL); - static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root, - LLDir::ESkinConstraint constraint=LLDir::CURRENT_SKIN); + static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root, + LLDir::ESkinConstraint constraint=LLDir::CURRENT_SKIN); private: - //NOTE: both friend declarations are necessary to keep both gcc and msvc happy - template <typename T> friend class LLChildRegistry; - template <typename T> template <typename U> friend class LLChildRegistry<T>::Register; + //NOTE: both friend declarations are necessary to keep both gcc and msvc happy + template <typename T> friend class LLChildRegistry; + template <typename T> template <typename U> friend class LLChildRegistry<T>::Register; - static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest); + static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest); - // helper function for adding widget type info to various registries - static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag); + // helper function for adding widget type info to various registries + static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag); - static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); + static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); - template<typename T> - static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL) - { + template<typename T> + static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - T* widget = NULL; - - if (!params.validateBlock()) - { - LL_WARNS() << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << LL_ENDL; - //return NULL; - } - - widget = new T(params); - - widget->initFromParams(params); - - if (parent) - { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX; - setCtrlParent(widget, parent, tab_group); - } - return widget; - } - - template<typename T> - static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) - { + T* widget = NULL; + + if (!params.validateBlock()) + { + LL_WARNS() << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << LL_ENDL; + //return NULL; + } + + widget = new T(params); + + widget->initFromParams(params); + + if (parent) + { + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX; + setCtrlParent(widget, parent, tab_group); + } + return widget; + } + + template<typename T> + static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - typename T::Params params(getDefaultParams<T>()); + typename T::Params params(getDefaultParams<T>()); - LLXUIParser parser; - parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); + LLXUIParser parser; + parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); - if (output_node) - { - // We always want to output top-left coordinates - typename T::Params output_params(params); - T::setupParamsForExport(output_params, parent); - copyName(node, output_node); - parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &getDefaultParams<T>()); - } + if (output_node) + { + // We always want to output top-left coordinates + typename T::Params output_params(params); + T::setupParamsForExport(output_params, parent); + copyName(node, output_node); + parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &getDefaultParams<T>()); + } - // Apply layout transformations, usually munging rect - params.from_xui = true; - T::applyXUILayout(params, parent); - T* widget = createWidgetImpl<T>(params, parent); + // Apply layout transformations, usually munging rect + params.from_xui = true; + T::applyXUILayout(params, parent); + T* widget = createWidgetImpl<T>(params, parent); - typedef typename T::child_registry_t registry_t; + typedef typename T::child_registry_t registry_t; - createChildren(widget, node, registry_t::instance(), output_node); + createChildren(widget, node, registry_t::instance(), output_node); - if (widget && !widget->postBuild()) - { - delete widget; - widget = NULL; - } + if (widget && !widget->postBuild()) + { + delete widget; + widget = NULL; + } - return widget; - } + return widget; + } - // this exists to get around dependency on llview - static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); + // this exists to get around dependency on llview + static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); - class LLPanel* mDummyPanel; - std::vector<std::string> mFileNames; + class LLPanel* mDummyPanel; + std::vector<std::string> mFileNames; - // store ParamDefaults specializations - // Each ParamDefaults specialization used to be an LLSingleton in its own - // right. But the 2016 changes to the LLSingleton mechanism, making - // LLSingleton instances polymorphic, are incompatible with current - // LLInitParam::BaseBlock functionality. (Thanks NickyD for spotting - // that!) Moreover, instances of the private nested ParamDefaults template - // aren't global resources -- which is what LLSingleton is designed for. - // This is simply a cache looked up by type. Its lifespan is tied to - // LLUICtrlFactory. Use LLHeteroMap for this cache. - LLHeteroMap mParamDefaultsMap; + // store ParamDefaults specializations + // Each ParamDefaults specialization used to be an LLSingleton in its own + // right. But the 2016 changes to the LLSingleton mechanism, making + // LLSingleton instances polymorphic, are incompatible with current + // LLInitParam::BaseBlock functionality. (Thanks NickyD for spotting + // that!) Moreover, instances of the private nested ParamDefaults template + // aren't global resources -- which is what LLSingleton is designed for. + // This is simply a cache looked up by type. Its lifespan is tied to + // LLUICtrlFactory. Use LLHeteroMap for this cache. + LLHeteroMap mParamDefaultsMap; }; template <typename PARAM_BLOCK, int DUMMY> LLUICtrlFactory::ParamDefaults<PARAM_BLOCK, DUMMY>::ParamDefaults() { - // look up template file for this param block... - const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK)); - if (param_block_tag) - { // ...and if it exists, back fill values using the most specific template first - PARAM_BLOCK params; - LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, params); - mPrototype.fillFrom(params); - } - // recursively fill from base class param block - ((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom( - LLUICtrlFactory::instance().mParamDefaultsMap.obtain< - ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY> >().get()); + // look up template file for this param block... + const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK)); + if (param_block_tag) + { // ...and if it exists, back fill values using the most specific template first + PARAM_BLOCK params; + LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, params); + mPrototype.fillFrom(params); + } + // recursively fill from base class param block + ((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom( + LLUICtrlFactory::instance().mParamDefaultsMap.obtain< + ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY> >().get()); } @@ -309,17 +309,17 @@ LLUICtrlFactory::ParamDefaults<LLInitParam::BaseBlock, DUMMY>::ParamDefaults() { // this is here to make gcc happy with reference to LLUICtrlFactory template<typename DERIVED> -template<typename T> +template<typename T> LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreatorFunc func) -: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func) +: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func) { - // add this widget to various registries - LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag); - - // since registry_t depends on T, do this in line here - // TODO: uncomment this for schema generation - //typedef typename T::child_registry_t registry_t; - //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance()); + // add this widget to various registries + LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag); + + // since registry_t depends on T, do this in line here + // TODO: uncomment this for schema generation + //typedef typename T::child_registry_t registry_t; + //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance()); } #endif //LLUICTRLFACTORY_H diff --git a/indra/llui/lluifwd.h b/indra/llui/lluifwd.h index a68629a091..940774cf46 100644 --- a/indra/llui/lluifwd.h +++ b/indra/llui/lluifwd.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 98d0c215e6..bfadeb8428 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lluistring.cpp * @brief LLUIString implementation. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,122 +35,122 @@ LLTrace::BlockTimerStatHandle FTM_UI_STRING("UI String"); LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args) -: mOrig(instring), - mArgs(new LLStringUtil::format_map_t(args)) +: mOrig(instring), + mArgs(new LLStringUtil::format_map_t(args)) { - dirty(); + dirty(); } void LLUIString::assign(const std::string& s) { - mOrig = s; - dirty(); + mOrig = s; + dirty(); } void LLUIString::setArgList(const LLStringUtil::format_map_t& args) { - getArgs() = args; - dirty(); + getArgs() = args; + dirty(); } void LLUIString::setArgs(const LLSD& sd) { - LL_RECORD_BLOCK_TIME(FTM_UI_STRING); - - if (!sd.isMap()) return; - for(LLSD::map_const_iterator sd_it = sd.beginMap(); - sd_it != sd.endMap(); - ++sd_it) - { - setArg(sd_it->first, sd_it->second.asString()); - } - dirty(); + LL_RECORD_BLOCK_TIME(FTM_UI_STRING); + + if (!sd.isMap()) return; + for(LLSD::map_const_iterator sd_it = sd.beginMap(); + sd_it != sd.endMap(); + ++sd_it) + { + setArg(sd_it->first, sd_it->second.asString()); + } + dirty(); } void LLUIString::setArg(const std::string& key, const std::string& replacement) { - getArgs()[key] = replacement; - dirty(); + getArgs()[key] = replacement; + dirty(); } void LLUIString::truncate(S32 maxchars) { - if (getUpdatedWResult().size() > (size_t)maxchars) - { - LLWStringUtil::truncate(getUpdatedWResult(), maxchars); - mResult = wstring_to_utf8str(getUpdatedWResult()); - } + if (getUpdatedWResult().size() > (size_t)maxchars) + { + LLWStringUtil::truncate(getUpdatedWResult(), maxchars); + mResult = wstring_to_utf8str(getUpdatedWResult()); + } } void LLUIString::erase(S32 charidx, S32 len) { - getUpdatedWResult().erase(charidx, len); - mResult = wstring_to_utf8str(getUpdatedWResult()); + getUpdatedWResult().erase(charidx, len); + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::insert(S32 charidx, const LLWString& wchars) { - getUpdatedWResult().insert(charidx, wchars); - mResult = wstring_to_utf8str(getUpdatedWResult()); + getUpdatedWResult().insert(charidx, wchars); + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::replace(S32 charidx, llwchar wc) { - getUpdatedWResult()[charidx] = wc; - mResult = wstring_to_utf8str(getUpdatedWResult()); + getUpdatedWResult()[charidx] = wc; + mResult = wstring_to_utf8str(getUpdatedWResult()); } void LLUIString::clear() { - // Keep Args - mOrig.clear(); - mResult.clear(); - mWResult.clear(); + // Keep Args + mOrig.clear(); + mResult.clear(); + mWResult.clear(); } void LLUIString::dirty() { - mNeedsResult = true; - mNeedsWResult = true; + mNeedsResult = true; + mNeedsWResult = true; } void LLUIString::updateResult() const { - mNeedsResult = false; - - LL_RECORD_BLOCK_TIME(FTM_UI_STRING); - - // optimize for empty strings (don't attempt string replacement) - if (mOrig.empty()) - { - mResult.clear(); - mWResult.clear(); - return; - } - mResult = mOrig; - - // get the default args + local args - LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); - if (mArgs && !mArgs->empty()) - { - combined_args.insert(mArgs->begin(), mArgs->end()); - } - LLStringUtil::format(mResult, combined_args); + mNeedsResult = false; + + LL_RECORD_BLOCK_TIME(FTM_UI_STRING); + + // optimize for empty strings (don't attempt string replacement) + if (mOrig.empty()) + { + mResult.clear(); + mWResult.clear(); + return; + } + mResult = mOrig; + + // get the default args + local args + LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); + if (mArgs && !mArgs->empty()) + { + combined_args.insert(mArgs->begin(), mArgs->end()); + } + LLStringUtil::format(mResult, combined_args); } void LLUIString::updateWResult() const { - mNeedsWResult = false; + mNeedsWResult = false; - mWResult = utf8str_to_wstring(getUpdatedResult()); + mWResult = utf8str_to_wstring(getUpdatedResult()); } LLStringUtil::format_map_t& LLUIString::getArgs() { - if (!mArgs) - { - mArgs = new LLStringUtil::format_map_t; - } - return *mArgs; + if (!mArgs) + { + mArgs = new LLStringUtil::format_map_t; + } + return *mArgs; } diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index b1089a3903..0cc699f59c 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -1,4 +1,4 @@ -/** +/** * @file lluistring.h * @author: Steve Bennetts * @brief A fancy wrapper for std::string supporting argument substitutions. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -56,61 +56,61 @@ class LLUIString { public: - // These methods all perform appropriate argument substitution - // and modify mOrig where appropriate - LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {} - LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args); - LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } - LLUIString(const LLWString& instring) : mArgs(NULL) { insert(0, instring); } - ~LLUIString() { delete mArgs; } + // These methods all perform appropriate argument substitution + // and modify mOrig where appropriate + LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {} + LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args); + LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } + LLUIString(const LLWString& instring) : mArgs(NULL) { insert(0, instring); } + ~LLUIString() { delete mArgs; } - void assign(const std::string& instring); - LLUIString& operator=(const std::string& s) { assign(s); return *this; } + void assign(const std::string& instring); + LLUIString& operator=(const std::string& s) { assign(s); return *this; } - void setArgList(const LLStringUtil::format_map_t& args); - void setArgs(const LLStringUtil::format_map_t& args) { setArgList(args); } - void setArgs(const class LLSD& sd); - void setArg(const std::string& key, const std::string& replacement); + void setArgList(const LLStringUtil::format_map_t& args); + void setArgs(const LLStringUtil::format_map_t& args) { setArgList(args); } + void setArgs(const class LLSD& sd); + void setArg(const std::string& key, const std::string& replacement); - const std::string& getString() const { return getUpdatedResult(); } - operator std::string() const { return getUpdatedResult(); } + const std::string& getString() const { return getUpdatedResult(); } + operator std::string() const { return getUpdatedResult(); } - const LLWString& getWString() const { return getUpdatedWResult(); } - operator LLWString() const { return getUpdatedWResult(); } + const LLWString& getWString() const { return getUpdatedWResult(); } + operator LLWString() const { return getUpdatedWResult(); } - bool empty() const { return getUpdatedResult().empty(); } - S32 length() const { return getUpdatedWResult().size(); } + bool empty() const { return getUpdatedResult().empty(); } + S32 length() const { return getUpdatedWResult().size(); } - void clear(); - void clearArgs() { if (mArgs) mArgs->clear(); } + void clear(); + void clearArgs() { if (mArgs) mArgs->clear(); } - // These utility functions are included for text editing. - // They do not affect mOrig and do not perform argument substitution - void truncate(S32 maxchars); - void erase(S32 charidx, S32 len); - void insert(S32 charidx, const LLWString& wchars); - void replace(S32 charidx, llwchar wc); + // These utility functions are included for text editing. + // They do not affect mOrig and do not perform argument substitution + void truncate(S32 maxchars); + void erase(S32 charidx, S32 len); + void insert(S32 charidx, const LLWString& wchars); + void replace(S32 charidx, llwchar wc); private: - // something changed, requiring reformatting of strings - void dirty(); + // something changed, requiring reformatting of strings + void dirty(); - std::string& getUpdatedResult() const { if (mNeedsResult) { updateResult(); } return mResult; } - LLWString& getUpdatedWResult() const{ if (mNeedsWResult) { updateWResult(); } return mWResult; } + std::string& getUpdatedResult() const { if (mNeedsResult) { updateResult(); } return mResult; } + LLWString& getUpdatedWResult() const{ if (mNeedsWResult) { updateWResult(); } return mWResult; } - // do actual work of updating strings (non-inlined) - void updateResult() const; - void updateWResult() const; - LLStringUtil::format_map_t& getArgs(); + // do actual work of updating strings (non-inlined) + void updateResult() const; + void updateWResult() const; + LLStringUtil::format_map_t& getArgs(); - std::string mOrig; - mutable std::string mResult; - mutable LLWString mWResult; // for displaying - LLStringUtil::format_map_t* mArgs; + std::string mOrig; + mutable std::string mResult; + mutable LLWString mWResult; // for displaying + LLStringUtil::format_map_t* mArgs; - // controls lazy evaluation - mutable bool mNeedsResult; - mutable bool mNeedsWResult; + // controls lazy evaluation + mutable bool mNeedsResult; + mutable bool mNeedsWResult; }; #endif // LL_LLUISTRING_H diff --git a/indra/llui/lluiusage.cpp b/indra/llui/lluiusage.cpp index ccae6643b9..e617f60aba 100644 --- a/indra/llui/lluiusage.cpp +++ b/indra/llui/lluiusage.cpp @@ -39,108 +39,108 @@ LLUIUsage::~LLUIUsage() // static std::string LLUIUsage::sanitized(const std::string& s) { - // Remove characters that make the ViewerStats db unhappy - std::string result(s); - std::replace(result.begin(), result.end(), '.', '_'); - std::replace(result.begin(), result.end(), ' ', '_'); - return result; + // Remove characters that make the ViewerStats db unhappy + std::string result(s); + std::replace(result.begin(), result.end(), '.', '_'); + std::replace(result.begin(), result.end(), ' ', '_'); + return result; } // static void LLUIUsage::setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val) { - // Keep the last max_elts components of the specified path - std::vector<std::string> fields; - boost::split(fields, path, boost::is_any_of("/")); - auto first_pos = std::max(fields.begin(), fields.end() - max_elts); - auto end_pos = fields.end(); - std::vector<std::string> last_fields(first_pos,end_pos); - - setLLSDNested(sd, last_fields, val); + // Keep the last max_elts components of the specified path + std::vector<std::string> fields; + boost::split(fields, path, boost::is_any_of("/")); + auto first_pos = std::max(fields.begin(), fields.end() - max_elts); + auto end_pos = fields.end(); + std::vector<std::string> last_fields(first_pos,end_pos); + + setLLSDNested(sd, last_fields, val); } // setLLSDNested() -// Accomplish the equivalent of +// Accomplish the equivalent of // sd[fields[0]][fields[1]]... = val; // for an arbitrary number of fields. // This might be useful as an LLSD utility function; is not specific to LLUIUsage -// +// // static void LLUIUsage::setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val) { - LLSD* fsd = &sd; - for (auto it=fields.begin(); it!=fields.end(); ++it) - { - if (it == fields.end()-1) - { - (*fsd)[*it] = val; - } - else - { - if (!(*fsd)[*it].isMap()) - { - (*fsd)[*it] = LLSD::emptyMap(); - } - fsd = &(*fsd)[*it]; - } - } + LLSD* fsd = &sd; + for (auto it=fields.begin(); it!=fields.end(); ++it) + { + if (it == fields.end()-1) + { + (*fsd)[*it] = val; + } + else + { + if (!(*fsd)[*it].isMap()) + { + (*fsd)[*it] = LLSD::emptyMap(); + } + fsd = &(*fsd)[*it]; + } + } } void LLUIUsage::logCommand(const std::string& command) { - mCommandCounts[sanitized(command)]++; - LL_DEBUGS("UIUsage") << "command " << command << LL_ENDL; + mCommandCounts[sanitized(command)]++; + LL_DEBUGS("UIUsage") << "command " << command << LL_ENDL; } void LLUIUsage::logControl(const std::string& control) { - mControlCounts[sanitized(control)]++; - LL_DEBUGS("UIUsage") << "control " << control << LL_ENDL; + mControlCounts[sanitized(control)]++; + LL_DEBUGS("UIUsage") << "control " << control << LL_ENDL; } void LLUIUsage::logFloater(const std::string& floater) { - mFloaterCounts[sanitized(floater)]++; - LL_DEBUGS("UIUsage") << "floater " << floater << LL_ENDL; + mFloaterCounts[sanitized(floater)]++; + LL_DEBUGS("UIUsage") << "floater " << floater << LL_ENDL; } void LLUIUsage::logPanel(const std::string& p) { - mPanelCounts[sanitized(p)]++; - LL_DEBUGS("UIUsage") << "panel " << p << LL_ENDL; + mPanelCounts[sanitized(p)]++; + LL_DEBUGS("UIUsage") << "panel " << p << LL_ENDL; } LLSD LLUIUsage::asLLSD() const { - LLSD result; - for (auto const& it : mCommandCounts) - { - result["commands"][it.first] = LLSD::Integer(it.second); - } - for (auto const& it : mControlCounts) - { - setLLSDPath(result["controls"], it.first, 2, LLSD::Integer(it.second)); - } - for (auto const& it : mFloaterCounts) - { - result["floaters"][it.first] = LLSD::Integer(it.second); - } - for (auto const& it : mPanelCounts) - { - result["panels"][it.first] = LLSD::Integer(it.second); - } - return result; + LLSD result; + for (auto const& it : mCommandCounts) + { + result["commands"][it.first] = LLSD::Integer(it.second); + } + for (auto const& it : mControlCounts) + { + setLLSDPath(result["controls"], it.first, 2, LLSD::Integer(it.second)); + } + for (auto const& it : mFloaterCounts) + { + result["floaters"][it.first] = LLSD::Integer(it.second); + } + for (auto const& it : mPanelCounts) + { + result["panels"][it.first] = LLSD::Integer(it.second); + } + return result; } // Clear up some junk content generated during initial login/UI initialization void LLUIUsage::clear() { - LL_DEBUGS("UIUsage") << "clear" << LL_ENDL; - mCommandCounts.clear(); - mControlCounts.clear(); - mFloaterCounts.clear(); - mPanelCounts.clear(); + LL_DEBUGS("UIUsage") << "clear" << LL_ENDL; + mCommandCounts.clear(); + mControlCounts.clear(); + mFloaterCounts.clear(); + mPanelCounts.clear(); } diff --git a/indra/llui/lluiusage.h b/indra/llui/lluiusage.h index a30cd80db3..13f1e44a33 100644 --- a/indra/llui/lluiusage.h +++ b/indra/llui/lluiusage.h @@ -35,23 +35,23 @@ class LLUIUsage : public LLSingleton<LLUIUsage> { public: - LLSINGLETON(LLUIUsage); - ~LLUIUsage(); + LLSINGLETON(LLUIUsage); + ~LLUIUsage(); public: - static std::string sanitized(const std::string& s); - static void setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val); - static void setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val); - void logCommand(const std::string& command); - void logControl(const std::string& control); - void logFloater(const std::string& floater); - void logPanel(const std::string& p); - LLSD asLLSD() const; - void clear(); + static std::string sanitized(const std::string& s); + static void setLLSDPath(LLSD& sd, const std::string& path, S32 max_elts, const LLSD& val); + static void setLLSDNested(LLSD& sd, const std::vector<std::string>& fields, const LLSD& val); + void logCommand(const std::string& command); + void logControl(const std::string& control); + void logFloater(const std::string& floater); + void logPanel(const std::string& p); + LLSD asLLSD() const; + void clear(); private: - std::map<std::string,U32> mCommandCounts; - std::map<std::string,U32> mControlCounts; - std::map<std::string,U32> mFloaterCounts; - std::map<std::string,U32> mPanelCounts; + std::map<std::string,U32> mCommandCounts; + std::map<std::string,U32> mControlCounts; + std::map<std::string,U32> mFloaterCounts; + std::map<std::string,U32> mPanelCounts; }; #endif // LLUIUIUSAGE.h diff --git a/indra/llui/llundo.cpp b/indra/llui/llundo.cpp index 7c4c183a30..d5ff70d31a 100644 --- a/indra/llui/llundo.cpp +++ b/indra/llui/llundo.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llundo.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,24 +36,24 @@ //----------------------------------------------------------------------------- LLUndoBuffer::LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ) { - mNextAction = 0; - mLastAction = 0; - mFirstAction = 0; - mOperationID = 0; - - mNumActions = initial_count; - - mActions = new LLUndoAction *[initial_count]; - - //initialize buffer with actions - for (S32 i = 0; i < initial_count; i++) - { - mActions[i] = create_func(); - if (!mActions[i]) - { - LL_ERRS() << "Unable to create action for undo buffer" << LL_ENDL; - } - } + mNextAction = 0; + mLastAction = 0; + mFirstAction = 0; + mOperationID = 0; + + mNumActions = initial_count; + + mActions = new LLUndoAction *[initial_count]; + + //initialize buffer with actions + for (S32 i = 0; i < initial_count; i++) + { + mActions[i] = create_func(); + if (!mActions[i]) + { + LL_ERRS() << "Unable to create action for undo buffer" << LL_ENDL; + } + } } //----------------------------------------------------------------------------- @@ -61,12 +61,12 @@ LLUndoBuffer::LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ) //----------------------------------------------------------------------------- LLUndoBuffer::~LLUndoBuffer() { - for (S32 i = 0; i < mNumActions; i++) - { - delete mActions[i]; - } + for (S32 i = 0; i < mNumActions; i++) + { + delete mActions[i]; + } - delete [] mActions; + delete [] mActions; } //----------------------------------------------------------------------------- @@ -74,24 +74,24 @@ LLUndoBuffer::~LLUndoBuffer() //----------------------------------------------------------------------------- LLUndoBuffer::LLUndoAction* LLUndoBuffer::getNextAction(BOOL setClusterBegin) { - LLUndoAction *nextAction = mActions[mNextAction]; + LLUndoAction *nextAction = mActions[mNextAction]; - if (setClusterBegin) - { - mOperationID++; - } - mActions[mNextAction]->mClusterID = mOperationID; + if (setClusterBegin) + { + mOperationID++; + } + mActions[mNextAction]->mClusterID = mOperationID; - mNextAction = (mNextAction + 1) % mNumActions; - mLastAction = mNextAction; + mNextAction = (mNextAction + 1) % mNumActions; + mLastAction = mNextAction; - if (mNextAction == mFirstAction) - { - mActions[mFirstAction]->cleanup(); - mFirstAction = (mFirstAction + 1) % mNumActions; - } + if (mNextAction == mFirstAction) + { + mActions[mFirstAction]->cleanup(); + mFirstAction = (mFirstAction + 1) % mNumActions; + } - return nextAction; + return nextAction; } //----------------------------------------------------------------------------- @@ -99,35 +99,35 @@ LLUndoBuffer::LLUndoAction* LLUndoBuffer::getNextAction(BOOL setClusterBegin) //----------------------------------------------------------------------------- BOOL LLUndoBuffer::undoAction() { - if (!canUndo()) - { - return FALSE; - } + if (!canUndo()) + { + return FALSE; + } - S32 prevAction = (mNextAction + mNumActions - 1) % mNumActions; + S32 prevAction = (mNextAction + mNumActions - 1) % mNumActions; - while(mActions[prevAction]->mClusterID == mOperationID) - { - // go ahead and decrement action index - mNextAction = prevAction; + while(mActions[prevAction]->mClusterID == mOperationID) + { + // go ahead and decrement action index + mNextAction = prevAction; - // undo this action - mActions[mNextAction]->undo(); + // undo this action + mActions[mNextAction]->undo(); - // we're at the first action, so we don't know if we've actually undid everything - if (mNextAction == mFirstAction) - { - mOperationID--; - return FALSE; - } + // we're at the first action, so we don't know if we've actually undid everything + if (mNextAction == mFirstAction) + { + mOperationID--; + return FALSE; + } - // do wrap-around of index, but avoid negative numbers for modulo operator - prevAction = (mNextAction + mNumActions - 1) % mNumActions; - } + // do wrap-around of index, but avoid negative numbers for modulo operator + prevAction = (mNextAction + mNumActions - 1) % mNumActions; + } - mOperationID--; + mOperationID--; - return TRUE; + return TRUE; } //----------------------------------------------------------------------------- @@ -135,27 +135,27 @@ BOOL LLUndoBuffer::undoAction() //----------------------------------------------------------------------------- BOOL LLUndoBuffer::redoAction() { - if (!canRedo()) - { - return FALSE; - } + if (!canRedo()) + { + return FALSE; + } - mOperationID++; + mOperationID++; - while(mActions[mNextAction]->mClusterID == mOperationID) - { - if (mNextAction == mLastAction) - { - return FALSE; - } + while(mActions[mNextAction]->mClusterID == mOperationID) + { + if (mNextAction == mLastAction) + { + return FALSE; + } - mActions[mNextAction]->redo(); + mActions[mNextAction]->redo(); - // do wrap-around of index - mNextAction = (mNextAction + 1) % mNumActions; - } + // do wrap-around of index + mNextAction = (mNextAction + 1) % mNumActions; + } - return TRUE; + return TRUE; } //----------------------------------------------------------------------------- @@ -163,12 +163,12 @@ BOOL LLUndoBuffer::redoAction() //----------------------------------------------------------------------------- void LLUndoBuffer::flushActions() { - for (S32 i = 0; i < mNumActions; i++) - { - mActions[i]->cleanup(); - } - mNextAction = 0; - mLastAction = 0; - mFirstAction = 0; - mOperationID = 0; + for (S32 i = 0; i < mNumActions; i++) + { + mActions[i]->cleanup(); + } + mNextAction = 0; + mLastAction = 0; + mFirstAction = 0; + mOperationID = 0; } diff --git a/indra/llui/llundo.h b/indra/llui/llundo.h index a6da550126..19cb09e6bb 100644 --- a/indra/llui/llundo.h +++ b/indra/llui/llundo.h @@ -1,25 +1,25 @@ -/** +/** * @file llundo.h * @brief Generic interface for undo/redo circular buffer. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,38 +31,38 @@ class LLUndoBuffer { public: - class LLUndoAction - { - friend class LLUndoBuffer; - public: - virtual void undo() = 0; - virtual void redo() = 0; - virtual void cleanup() {}; - protected: - LLUndoAction(): mClusterID(0) {}; - virtual ~LLUndoAction(){}; - private: - S32 mClusterID; - }; + class LLUndoAction + { + friend class LLUndoBuffer; + public: + virtual void undo() = 0; + virtual void redo() = 0; + virtual void cleanup() {}; + protected: + LLUndoAction(): mClusterID(0) {}; + virtual ~LLUndoAction(){}; + private: + S32 mClusterID; + }; - LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ); - virtual ~LLUndoBuffer(); + LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ); + virtual ~LLUndoBuffer(); - LLUndoAction *getNextAction(BOOL setClusterBegin = TRUE); - BOOL undoAction(); - BOOL redoAction(); - BOOL canUndo() { return (mNextAction != mFirstAction); } - BOOL canRedo() { return (mNextAction != mLastAction); } + LLUndoAction *getNextAction(BOOL setClusterBegin = TRUE); + BOOL undoAction(); + BOOL redoAction(); + BOOL canUndo() { return (mNextAction != mFirstAction); } + BOOL canRedo() { return (mNextAction != mLastAction); } - void flushActions(); + void flushActions(); private: - LLUndoAction **mActions; // array of pointers to undoactions - S32 mNumActions; // total number of actions in ring buffer - S32 mNextAction; // next action to perform undo/redo on - S32 mLastAction; // last action actually added to undo buffer - S32 mFirstAction; // beginning of ring buffer (don't undo any further) - S32 mOperationID; // current operation id, for undoing and redoing in clusters + LLUndoAction **mActions; // array of pointers to undoactions + S32 mNumActions; // total number of actions in ring buffer + S32 mNextAction; // next action to perform undo/redo on + S32 mLastAction; // last action actually added to undo buffer + S32 mFirstAction; // beginning of ring buffer (don't undo any further) + S32 mOperationID; // current operation id, for undoing and redoing in clusters }; #endif //LL_LLUNDO_H diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 8216046174..b6b450c2a1 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llurlaction.cpp * @author Martin Reddy * @brief A set of actions that can performed on Urls @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,193 +33,193 @@ // global state for the callback functions -LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback; -LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback; -LLUrlAction::url_callback_t LLUrlAction::sOpenURLExternalCallback; +LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback; +LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback; +LLUrlAction::url_callback_t LLUrlAction::sOpenURLExternalCallback; LLUrlAction::execute_url_callback_t LLUrlAction::sExecuteSLURLCallback; void LLUrlAction::setOpenURLCallback(url_callback_t cb) { - sOpenURLCallback = cb; + sOpenURLCallback = cb; } void LLUrlAction::setOpenURLInternalCallback(url_callback_t cb) { - sOpenURLInternalCallback = cb; + sOpenURLInternalCallback = cb; } void LLUrlAction::setOpenURLExternalCallback(url_callback_t cb) { - sOpenURLExternalCallback = cb; + sOpenURLExternalCallback = cb; } void LLUrlAction::setExecuteSLURLCallback(execute_url_callback_t cb) { - sExecuteSLURLCallback = cb; + sExecuteSLURLCallback = cb; } void LLUrlAction::openURL(std::string url) { - if (sOpenURLCallback) - { - sOpenURLCallback(url); - } + if (sOpenURLCallback) + { + sOpenURLCallback(url); + } } void LLUrlAction::openURLInternal(std::string url) { - if (sOpenURLInternalCallback) - { - sOpenURLInternalCallback(url); - } + if (sOpenURLInternalCallback) + { + sOpenURLInternalCallback(url); + } } void LLUrlAction::openURLExternal(std::string url) { - if (sOpenURLExternalCallback) - { - sOpenURLExternalCallback(url); - } + if (sOpenURLExternalCallback) + { + sOpenURLExternalCallback(url); + } } bool LLUrlAction::executeSLURL(std::string url, bool trusted_content) { - if (sExecuteSLURLCallback) - { - return sExecuteSLURLCallback(url, trusted_content); - } - return false; + if (sExecuteSLURLCallback) + { + return sExecuteSLURLCallback(url, trusted_content); + } + return false; } void LLUrlAction::clickAction(std::string url, bool trusted_content) { - // Try to handle as SLURL first, then http Url - if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url, trusted_content) ) - { - if (sOpenURLCallback) - { - sOpenURLCallback(url); - } - } + // Try to handle as SLURL first, then http Url + if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url, trusted_content) ) + { + if (sOpenURLCallback) + { + sOpenURLCallback(url); + } + } } void LLUrlAction::teleportToLocation(std::string url) { - LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) - { - if (! match.getLocation().empty()) - { - executeSLURL("secondlife:///app/teleport/" + match.getLocation()); - } - } + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + if (! match.getLocation().empty()) + { + executeSLURL("secondlife:///app/teleport/" + match.getLocation()); + } + } } void LLUrlAction::showLocationOnMap(std::string url) { - LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) - { - if (! match.getLocation().empty()) - { - executeSLURL("secondlife:///app/worldmap/" + match.getLocation()); - } - } + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + if (! match.getLocation().empty()) + { + executeSLURL("secondlife:///app/worldmap/" + match.getLocation()); + } + } } void LLUrlAction::copyURLToClipboard(std::string url) { - LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url)); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url)); } void LLUrlAction::copyLabelToClipboard(std::string url) { - LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) - { - LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); - } + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); + } } void LLUrlAction::showProfile(std::string url) { - // Get id from 'secondlife:///app/{cmd}/{id}/{action}' - // and show its profile - LLURI uri(url); - LLSD path_array = uri.pathArray(); - if (path_array.size() == 4) - { - std::string id_str = path_array.get(2).asString(); - if (LLUUID::validate(id_str)) - { - std::string cmd_str = path_array.get(1).asString(); - executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about"); - } - } + // Get id from 'secondlife:///app/{cmd}/{id}/{action}' + // and show its profile + LLURI uri(url); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string id_str = path_array.get(2).asString(); + if (LLUUID::validate(id_str)) + { + std::string cmd_str = path_array.get(1).asString(); + executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about"); + } + } } std::string LLUrlAction::getUserID(std::string url) { - LLURI uri(url); - LLSD path_array = uri.pathArray(); - std::string id_str; - if (path_array.size() == 4) - { - id_str = path_array.get(2).asString(); - } - return id_str; + LLURI uri(url); + LLSD path_array = uri.pathArray(); + std::string id_str; + if (path_array.size() == 4) + { + id_str = path_array.get(2).asString(); + } + return id_str; } std::string LLUrlAction::getObjectId(std::string url) { - LLURI uri(url); - LLSD path_array = uri.pathArray(); - std::string id_str; - if (path_array.size() >= 3) - { - id_str = path_array.get(2).asString(); - } - return id_str; + LLURI uri(url); + LLSD path_array = uri.pathArray(); + std::string id_str; + if (path_array.size() >= 3) + { + id_str = path_array.get(2).asString(); + } + return id_str; } std::string LLUrlAction::getObjectName(std::string url) { - LLURI uri(url); - LLSD query_map = uri.queryMap(); - std::string name; - if (query_map.has("name")) - { - name = query_map["name"].asString(); - } - return name; + LLURI uri(url); + LLSD query_map = uri.queryMap(); + std::string name; + if (query_map.has("name")) + { + name = query_map["name"].asString(); + } + return name; } void LLUrlAction::sendIM(std::string url) { - std::string id_str = getUserID(url); - if (LLUUID::validate(id_str)) - { - executeSLURL("secondlife:///app/agent/" + id_str + "/im"); - } + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/im"); + } } void LLUrlAction::addFriend(std::string url) { - std::string id_str = getUserID(url); - if (LLUUID::validate(id_str)) - { - executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend"); - } + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend"); + } } void LLUrlAction::removeFriend(std::string url) { - std::string id_str = getUserID(url); - if (LLUUID::validate(id_str)) - { - executeSLURL("secondlife:///app/agent/" + id_str + "/removefriend"); - } + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/removefriend"); + } } void LLUrlAction::reportAbuse(std::string url) @@ -233,12 +233,12 @@ void LLUrlAction::reportAbuse(std::string url) void LLUrlAction::blockObject(std::string url) { - std::string object_id = getObjectId(url); - std::string object_name = getObjectName(url); - if (LLUUID::validate(object_id)) - { - executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + LLURI::escape(object_name)); - } + std::string object_id = getObjectId(url); + std::string object_name = getObjectName(url); + if (LLUUID::validate(object_id)) + { + executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + LLURI::escape(object_name)); + } } void LLUrlAction::unblockObject(std::string url) diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index c2c576254d..0f54b66299 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -1,4 +1,4 @@ -/** +/** * @file llurlaction.h * @author Martin Reddy * @brief A set of actions that can performed on Urls @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,63 +45,63 @@ class LLUrlAction { public: - LLUrlAction(); + LLUrlAction(); - /// load a Url in the user's preferred web browser - static void openURL(std::string url); + /// load a Url in the user's preferred web browser + static void openURL(std::string url); - /// load a Url in the internal Second Life web browser - static void openURLInternal(std::string url); + /// load a Url in the internal Second Life web browser + static void openURLInternal(std::string url); - /// load a Url in the operating system's default web browser - static void openURLExternal(std::string url); + /// load a Url in the operating system's default web browser + static void openURLExternal(std::string url); - /// execute the given secondlife: SLURL - static bool executeSLURL(std::string url, bool trusted_content = true); + /// execute the given secondlife: SLURL + static bool executeSLURL(std::string url, bool trusted_content = true); - /// if the Url specifies an SL location, teleport there - static void teleportToLocation(std::string url); + /// if the Url specifies an SL location, teleport there + static void teleportToLocation(std::string url); - /// if the Url specifies an SL location, show it on a map - static void showLocationOnMap(std::string url); + /// if the Url specifies an SL location, show it on a map + static void showLocationOnMap(std::string url); - /// perform the appropriate action for left-clicking on a Url - static void clickAction(std::string url, bool trusted_content); + /// perform the appropriate action for left-clicking on a Url + static void clickAction(std::string url, bool trusted_content); - /// copy the label for a Url to the clipboard - static void copyLabelToClipboard(std::string url); + /// copy the label for a Url to the clipboard + static void copyLabelToClipboard(std::string url); - /// copy a Url to the clipboard - static void copyURLToClipboard(std::string url); + /// copy a Url to the clipboard + static void copyURLToClipboard(std::string url); - /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile - static void showProfile(std::string url); - static std::string getUserID(std::string url); - static std::string getObjectName(std::string url); - static std::string getObjectId(std::string url); - static void sendIM(std::string url); - static void addFriend(std::string url); - static void removeFriend(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile + static void showProfile(std::string url); + static std::string getUserID(std::string url); + static std::string getObjectName(std::string url); + static std::string getObjectId(std::string url); + static void sendIM(std::string url); + static void addFriend(std::string url); + static void removeFriend(std::string url); static void reportAbuse(std::string url); - static void blockObject(std::string url); - static void unblockObject(std::string url); + static void blockObject(std::string url); + static void unblockObject(std::string url); - /// specify the callbacks to enable this class's functionality - typedef boost::function<void (const std::string&)> url_callback_t; - typedef boost::function<bool(const std::string& url, bool trusted_content)> execute_url_callback_t; + /// specify the callbacks to enable this class's functionality + typedef boost::function<void (const std::string&)> url_callback_t; + typedef boost::function<bool(const std::string& url, bool trusted_content)> execute_url_callback_t; - static void setOpenURLCallback(url_callback_t cb); - static void setOpenURLInternalCallback(url_callback_t cb); - static void setOpenURLExternalCallback(url_callback_t cb); - static void setExecuteSLURLCallback(execute_url_callback_t cb); + static void setOpenURLCallback(url_callback_t cb); + static void setOpenURLInternalCallback(url_callback_t cb); + static void setOpenURLExternalCallback(url_callback_t cb); + static void setExecuteSLURLCallback(execute_url_callback_t cb); private: - // callbacks for operations we can perform on Urls - static url_callback_t sOpenURLCallback; - static url_callback_t sOpenURLInternalCallback; - static url_callback_t sOpenURLExternalCallback; + // callbacks for operations we can perform on Urls + static url_callback_t sOpenURLCallback; + static url_callback_t sOpenURLInternalCallback; + static url_callback_t sOpenURLExternalCallback; - static execute_url_callback_t sExecuteSLURLCallback; + static execute_url_callback_t sExecuteSLURLCallback; }; #endif diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 05d821f5d8..45afc9efee 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llurlentry.cpp * @author Martin Reddy * @brief Describes the Url types that can be registered in LLUrlRegistry @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,135 +59,135 @@ LLUrlEntryBase::~LLUrlEntryBase() std::string LLUrlEntryBase::getUrl(const std::string &string) const { - return escapeUrl(string); + return escapeUrl(string); } //virtual std::string LLUrlEntryBase::getIcon(const std::string &url) { - return mIcon; + return mIcon; } LLStyle::Params LLUrlEntryBase::getStyle() const { - LLStyle::Params style_params; - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.font.style = "UNDERLINE"; - return style_params; + LLStyle::Params style_params; + style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.font.style = "UNDERLINE"; + return style_params; } std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const { - // return the id from a SLURL in the format /app/{cmd}/{id}/about - LLURI uri(url); - LLSD path_array = uri.pathArray(); - if (path_array.size() == 4) - { - return path_array.get(2).asString(); - } - return ""; + // return the id from a SLURL in the format /app/{cmd}/{id}/about + LLURI uri(url); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + return path_array.get(2).asString(); + } + return ""; } std::string LLUrlEntryBase::unescapeUrl(const std::string &url) const { - return LLURI::unescape(url); + return LLURI::unescape(url); } std::string LLUrlEntryBase::escapeUrl(const std::string &url) const { - static std::string no_escape_chars; - static bool initialized = false; - if (!initialized) - { - no_escape_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "-._~!$?&()*+,@:;=/%#"; - - std::sort(no_escape_chars.begin(), no_escape_chars.end()); - initialized = true; - } - return LLURI::escape(url, no_escape_chars, true); + static std::string no_escape_chars; + static bool initialized = false; + if (!initialized) + { + no_escape_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~!$?&()*+,@:;=/%#"; + + std::sort(no_escape_chars.begin(), no_escape_chars.end()); + initialized = true; + } + return LLURI::escape(url, no_escape_chars, true); } std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) const { - // return the label part from [http://www.example.org Label] - const char *text = url.c_str(); - S32 start = 0; - while (! isspace(text[start])) - { - start++; - } - while (text[start] == ' ' || text[start] == '\t') - { - start++; - } - return unescapeUrl(url.substr(start, url.size()-start-1)); + // return the label part from [http://www.example.org Label] + const char *text = url.c_str(); + S32 start = 0; + while (! isspace(text[start])) + { + start++; + } + while (text[start] == ' ' || text[start] == '\t') + { + start++; + } + return unescapeUrl(url.substr(start, url.size()-start-1)); } std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) const { - // return the url part from [http://www.example.org Label] - const char *text = string.c_str(); - S32 end = 0; - while (! isspace(text[end])) - { - end++; - } - return escapeUrl(string.substr(1, end-1)); + // return the url part from [http://www.example.org Label] + const char *text = string.c_str(); + S32 end = 0; + while (! isspace(text[end])) + { + end++; + } + return escapeUrl(string.substr(1, end-1)); } void LLUrlEntryBase::addObserver(const std::string &id, - const std::string &url, - const LLUrlLabelCallback &cb) -{ - // add a callback to be notified when we have a label for the uuid - LLUrlEntryObserver observer; - observer.url = url; - observer.signal = new LLUrlLabelSignal(); - if (observer.signal) - { - observer.signal->connect(cb); - mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer)); - } + const std::string &url, + const LLUrlLabelCallback &cb) +{ + // add a callback to be notified when we have a label for the uuid + LLUrlEntryObserver observer; + observer.url = url; + observer.signal = new LLUrlLabelSignal(); + if (observer.signal) + { + observer.signal->connect(cb); + mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer)); + } } // *NOTE: See also LLUrlEntryAgent::callObservers() void LLUrlEntryBase::callObservers(const std::string &id, - const std::string &label, - const std::string &icon) -{ - // notify all callbacks waiting on the given uuid - typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; - std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); - for (observer_it it = matching_range.first; it != matching_range.second;) - { - // call the callback - give it the new label - LLUrlEntryObserver &observer = it->second; - (*observer.signal)(it->second.url, label, icon); - // then remove the signal - we only need to call it once - delete observer.signal; - mObservers.erase(it++); - } + const std::string &label, + const std::string &icon) +{ + // notify all callbacks waiting on the given uuid + typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; + std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); + for (observer_it it = matching_range.first; it != matching_range.second;) + { + // call the callback - give it the new label + LLUrlEntryObserver &observer = it->second; + (*observer.signal)(it->second.url, label, icon); + // then remove the signal - we only need to call it once + delete observer.signal; + mObservers.erase(it++); + } } /// is this a match for a URL that should not be hyperlinked? bool LLUrlEntryBase::isLinkDisabled() const { - // this allows us to have a global setting to turn off text hyperlink highlighting/action - static LLCachedControl<bool> globally_disabled(*LLUI::getInstance()->mSettingGroups["config"], "DisableTextHyperlinkActions", false); + // this allows us to have a global setting to turn off text hyperlink highlighting/action + static LLCachedControl<bool> globally_disabled(*LLUI::getInstance()->mSettingGroups["config"], "DisableTextHyperlinkActions", false); - return globally_disabled; + return globally_disabled; } bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const { - LLWString wlabel = utf8str_to_wstring(getLabelFromWikiLink(labeled_url)); - wlabel.erase(std::remove(wlabel.begin(), wlabel.end(), L'\u200B'), wlabel.end()); + LLWString wlabel = utf8str_to_wstring(getLabelFromWikiLink(labeled_url)); + wlabel.erase(std::remove(wlabel.begin(), wlabel.end(), L'\u200B'), wlabel.end()); // Unicode URL validation, see SL-15243 std::replace_if(wlabel.begin(), @@ -229,7 +229,7 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const label = "http://" + label; } - return (LLUrlRegistry::instance().hasUrl(label)) ? false : true; + return (LLUrlRegistry::instance().hasUrl(label)) ? false : true; } std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const @@ -238,8 +238,8 @@ std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) cons { return url; } - LLUriParser up(escapeUrl(url)); - if (up.normalize() == 0) + LLUriParser up(escapeUrl(url)); + if (up.normalize() == 0) { std::string label; up.extractParts(); @@ -252,69 +252,69 @@ std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) cons std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const { - std::string escaped_url = escapeUrl(url); - LLUriParser up(escaped_url); + std::string escaped_url = escapeUrl(url); + LLUriParser up(escaped_url); - std::string label; - up.extractParts(); - up.glueFirst(label, false); + std::string label; + up.extractParts(); + up.glueFirst(label, false); - size_t pos = escaped_url.find(label); - if (pos == std::string::npos) - { - return ""; - } - pos += label.size(); - return unescapeUrl(escaped_url.substr(pos)); + size_t pos = escaped_url.find(label); + if (pos == std::string::npos) + { + return ""; + } + pos += label.size(); + return unescapeUrl(escaped_url.substr(pos)); } static std::string getStringAfterToken(const std::string str, const std::string token) { - size_t pos = str.find(token); - if (pos == std::string::npos) - { - return ""; - } + size_t pos = str.find(token); + if (pos == std::string::npos) + { + return ""; + } - pos += token.size(); - return str.substr(pos, str.size() - pos); + pos += token.size(); + return str.substr(pos, str.size() - pos); } // // LLUrlEntryHTTP Describes generic http: and https: Urls // LLUrlEntryHTTP::LLUrlEntryHTTP() - : LLUrlEntryBase() + : LLUrlEntryBase() { - mPattern = boost::regex("https?://([^\\s/?\\.#]+\\.?)+\\.\\w+(:\\d+)?(/\\S*)?", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); + mPattern = boost::regex("https?://([^\\s/?\\.#]+\\.?)+\\.\\w+(:\\d+)?(/\\S*)?", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); } std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return urlToLabelWithGreyQuery(url); + return urlToLabelWithGreyQuery(url); } std::string LLUrlEntryHTTP::getQuery(const std::string &url) const { - return urlToGreyQuery(url); + return urlToGreyQuery(url); } std::string LLUrlEntryHTTP::getUrl(const std::string &string) const { - if (string.find("://") == std::string::npos) - { - return "http://" + escapeUrl(string); - } - return escapeUrl(string); + if (string.find("://") == std::string::npos) + { + return "http://" + escapeUrl(string); + } + return escapeUrl(string); } std::string LLUrlEntryHTTP::getTooltip(const std::string &url) const { - return unescapeUrl(url); + return unescapeUrl(url); } // @@ -323,110 +323,110 @@ std::string LLUrlEntryHTTP::getTooltip(const std::string &url) const // LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel() { - mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); + mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); } std::string LLUrlEntryHTTPLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - std::string label = getLabelFromWikiLink(url); - return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url); + std::string label = getLabelFromWikiLink(url); + return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url); } std::string LLUrlEntryHTTPLabel::getTooltip(const std::string &string) const { - return getUrl(string); + return getUrl(string); } std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const { - return getUrlFromWikiLink(string); + return getUrlFromWikiLink(string); } LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL() - : LLUrlEntryBase() + : LLUrlEntryBase() { - mPattern = boost::regex("(https?://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); + mPattern = boost::regex("(https?://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); } std::string LLUrlEntryInvalidSLURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return escapeUrl(url); + return escapeUrl(url); } std::string LLUrlEntryInvalidSLURL::getUrl(const std::string &string) const { - return escapeUrl(string); + return escapeUrl(string); } std::string LLUrlEntryInvalidSLURL::getTooltip(const std::string &url) const { - return unescapeUrl(url); + return unescapeUrl(url); } bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const { - S32 actual_parts; - - if(url.find(".com/secondlife/") != std::string::npos) - { - actual_parts = 5; - } - else if(url.find("/app/") != std::string::npos) - { - actual_parts = 6; - } - else - { - actual_parts = 3; - } - - LLURI uri(url); - LLSD path_array = uri.pathArray(); - S32 path_parts = path_array.size(); - S32 x,y,z; - - if (path_parts == actual_parts) - { - // handle slurl with (X,Y,Z) coordinates - LLStringUtil::convertToS32(path_array[path_parts-3],x); - LLStringUtil::convertToS32(path_array[path_parts-2],y); - LLStringUtil::convertToS32(path_array[path_parts-1],z); - - if((x>= 0 && x<= 256) && (y>= 0 && y<= 256) && (z>= 0)) - { - return TRUE; - } - } - else if (path_parts == (actual_parts-1)) - { - // handle slurl with (X,Y) coordinates - - LLStringUtil::convertToS32(path_array[path_parts-2],x); - LLStringUtil::convertToS32(path_array[path_parts-1],y); - ; - if((x>= 0 && x<= 256) && (y>= 0 && y<= 256)) - { - return TRUE; - } - } - else if (path_parts == (actual_parts-2)) - { - // handle slurl with (X) coordinate - LLStringUtil::convertToS32(path_array[path_parts-1],x); - if(x>= 0 && x<= 256) - { - return TRUE; - } - } - - return FALSE; + S32 actual_parts; + + if(url.find(".com/secondlife/") != std::string::npos) + { + actual_parts = 5; + } + else if(url.find("/app/") != std::string::npos) + { + actual_parts = 6; + } + else + { + actual_parts = 3; + } + + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + S32 x,y,z; + + if (path_parts == actual_parts) + { + // handle slurl with (X,Y,Z) coordinates + LLStringUtil::convertToS32(path_array[path_parts-3],x); + LLStringUtil::convertToS32(path_array[path_parts-2],y); + LLStringUtil::convertToS32(path_array[path_parts-1],z); + + if((x>= 0 && x<= 256) && (y>= 0 && y<= 256) && (z>= 0)) + { + return TRUE; + } + } + else if (path_parts == (actual_parts-1)) + { + // handle slurl with (X,Y) coordinates + + LLStringUtil::convertToS32(path_array[path_parts-2],x); + LLStringUtil::convertToS32(path_array[path_parts-1],y); + ; + if((x>= 0 && x<= 256) && (y>= 0 && y<= 256)) + { + return TRUE; + } + } + else if (path_parts == (actual_parts-2)) + { + // handle slurl with (X) coordinate + LLStringUtil::convertToS32(path_array[path_parts-1],x); + if(x>= 0 && x<= 256) + { + return TRUE; + } + } + + return FALSE; } // @@ -434,120 +434,120 @@ bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const // LLUrlEntrySLURL::LLUrlEntrySLURL() { - // see http://slurl.com/about.php for details on the SLURL format - mPattern = boost::regex("https?://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", - boost::regex::perl|boost::regex::icase); - mIcon = "Hand"; - mMenuName = "menu_url_slurl.xml"; - mTooltip = LLTrans::getString("TooltipSLURL"); + // see http://slurl.com/about.php for details on the SLURL format + mPattern = boost::regex("https?://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", + boost::regex::perl|boost::regex::icase); + mIcon = "Hand"; + mMenuName = "menu_url_slurl.xml"; + mTooltip = LLTrans::getString("TooltipSLURL"); } std::string LLUrlEntrySLURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - // - // we handle SLURLs in the following formats: - // - http://slurl.com/secondlife/Place/X/Y/Z - // - http://slurl.com/secondlife/Place/X/Y - // - http://slurl.com/secondlife/Place/X - // - http://slurl.com/secondlife/Place - // - - LLURI uri(url); - LLSD path_array = uri.pathArray(); - S32 path_parts = path_array.size(); - if (path_parts == 5) - { - // handle slurl with (X,Y,Z) coordinates - std::string location = unescapeUrl(path_array[path_parts-4]); - std::string x = path_array[path_parts-3]; - std::string y = path_array[path_parts-2]; - std::string z = path_array[path_parts-1]; - return location + " (" + x + "," + y + "," + z + ")"; - } - else if (path_parts == 4) - { - // handle slurl with (X,Y) coordinates - std::string location = unescapeUrl(path_array[path_parts-3]); - std::string x = path_array[path_parts-2]; - std::string y = path_array[path_parts-1]; - return location + " (" + x + "," + y + ")"; - } - else if (path_parts == 3) - { - // handle slurl with (X) coordinate - std::string location = unescapeUrl(path_array[path_parts-2]); - std::string x = path_array[path_parts-1]; - return location + " (" + x + ")"; - } - else if (path_parts == 2) - { - // handle slurl with no coordinates - std::string location = unescapeUrl(path_array[path_parts-1]); - return location; - } - - return url; + // + // we handle SLURLs in the following formats: + // - http://slurl.com/secondlife/Place/X/Y/Z + // - http://slurl.com/secondlife/Place/X/Y + // - http://slurl.com/secondlife/Place/X + // - http://slurl.com/secondlife/Place + // + + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + if (path_parts == 5) + { + // handle slurl with (X,Y,Z) coordinates + std::string location = unescapeUrl(path_array[path_parts-4]); + std::string x = path_array[path_parts-3]; + std::string y = path_array[path_parts-2]; + std::string z = path_array[path_parts-1]; + return location + " (" + x + "," + y + "," + z + ")"; + } + else if (path_parts == 4) + { + // handle slurl with (X,Y) coordinates + std::string location = unescapeUrl(path_array[path_parts-3]); + std::string x = path_array[path_parts-2]; + std::string y = path_array[path_parts-1]; + return location + " (" + x + "," + y + ")"; + } + else if (path_parts == 3) + { + // handle slurl with (X) coordinate + std::string location = unescapeUrl(path_array[path_parts-2]); + std::string x = path_array[path_parts-1]; + return location + " (" + x + ")"; + } + else if (path_parts == 2) + { + // handle slurl with no coordinates + std::string location = unescapeUrl(path_array[path_parts-1]); + return location; + } + + return url; } std::string LLUrlEntrySLURL::getLocation(const std::string &url) const { - // return the part of the Url after slurl.com/secondlife/ - const std::string search_string = "/secondlife"; - size_t pos = url.find(search_string); - if (pos == std::string::npos) - { - return ""; - } + // return the part of the Url after slurl.com/secondlife/ + const std::string search_string = "/secondlife"; + size_t pos = url.find(search_string); + if (pos == std::string::npos) + { + return ""; + } - pos += search_string.size() + 1; - return url.substr(pos, url.size() - pos); + pos += search_string.size() + 1; + return url.substr(pos, url.size() - pos); } // // LLUrlEntrySeconlifeURL Describes *secondlife.com/ *lindenlab.com/ *secondlifegrid.net/ and *tilia-inc.com/ urls to substitute icon 'hand.png' before link // LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() -{ - mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com)" - "|" - "(http://([-\\w\\.]*\\.)?secondlifegrid\\.net)" - "|" - "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)" - "|" - "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?)" - "|" - "(https?://([-\\w\\.]*\\.)?secondlife\\.io(:\\d{1,5})?))" - "\\/\\S*", - boost::regex::perl|boost::regex::icase); - - mIcon = "Hand"; - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); +{ + mPattern = boost::regex("((http://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com)" + "|" + "(http://([-\\w\\.]*\\.)?secondlifegrid\\.net)" + "|" + "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)" + "|" + "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?)" + "|" + "(https?://([-\\w\\.]*\\.)?secondlife\\.io(:\\d{1,5})?))" + "\\/\\S*", + boost::regex::perl|boost::regex::icase); + + mIcon = "Hand"; + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); } /// Return the url from a string that matched the regex std::string LLUrlEntrySecondlifeURL::getUrl(const std::string &string) const { - if (string.find("://") == std::string::npos) - { - return "https://" + escapeUrl(string); - } - return escapeUrl(string); + if (string.find("://") == std::string::npos) + { + return "https://" + escapeUrl(string); + } + return escapeUrl(string); } std::string LLUrlEntrySecondlifeURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return urlToLabelWithGreyQuery(url); + return urlToLabelWithGreyQuery(url); } std::string LLUrlEntrySecondlifeURL::getQuery(const std::string &url) const { - return urlToGreyQuery(url); + return urlToGreyQuery(url); } std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const { - return url; + return url; } // @@ -555,13 +555,13 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const // LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() { - mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\S)" - "|" - "https?://([-\\w\\.]*\\.)?secondlifegrid\\.net(?!\\S)", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\S)" + "|" + "https?://([-\\w\\.]*\\.)?secondlifegrid\\.net(?!\\S)", + boost::regex::perl|boost::regex::icase); - mIcon = "Hand"; - mMenuName = "menu_url_http.xml"; + mIcon = "Hand"; + mMenuName = "menu_url_http.xml"; } // @@ -571,194 +571,194 @@ LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() // LLUrlEntryAgent::LLUrlEntryAgent() { - mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_agent.xml"; - mIcon = "Generic_Person"; + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_agent.xml"; + mIcon = "Generic_Person"; } // virtual void LLUrlEntryAgent::callObservers(const std::string &id, - const std::string &label, - const std::string &icon) -{ - // notify all callbacks waiting on the given uuid - typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; - std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); - for (observer_it it = matching_range.first; it != matching_range.second;) - { - // call the callback - give it the new label - LLUrlEntryObserver &observer = it->second; - std::string final_label = localize_slapp_label(observer.url, label); - (*observer.signal)(observer.url, final_label, icon); - // then remove the signal - we only need to call it once - delete observer.signal; - mObservers.erase(it++); - } + const std::string &label, + const std::string &icon) +{ + // notify all callbacks waiting on the given uuid + typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; + std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); + for (observer_it it = matching_range.first; it != matching_range.second;) + { + // call the callback - give it the new label + LLUrlEntryObserver &observer = it->second; + std::string final_label = localize_slapp_label(observer.url, label); + (*observer.signal)(observer.url, final_label, icon); + // then remove the signal - we only need to call it once + delete observer.signal; + mObservers.erase(it++); + } } void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id, - const LLAvatarName& av_name) + const LLAvatarName& av_name) { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } - - std::string label = av_name.getCompleteName(); + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } - // received the agent name from the server - tell our observers - callObservers(id.asString(), label, mIcon); + std::string label = av_name.getCompleteName(); + + // received the agent name from the server - tell our observers + callObservers(id.asString(), label, mIcon); } -LLUUID LLUrlEntryAgent::getID(const std::string &string) const +LLUUID LLUrlEntryAgent::getID(const std::string &string) const { - return LLUUID(getIDStringFromUrl(string)); + return LLUUID(getIDStringFromUrl(string)); } std::string LLUrlEntryAgent::getTooltip(const std::string &string) const { - // return a tooltip corresponding to the URL type instead of the generic one - std::string url = getUrl(string); - - if (LLStringUtil::endsWith(url, "/inspect")) - { - return LLTrans::getString("TooltipAgentInspect"); - } - if (LLStringUtil::endsWith(url, "/mute")) - { - return LLTrans::getString("TooltipAgentMute"); - } - if (LLStringUtil::endsWith(url, "/unmute")) - { - return LLTrans::getString("TooltipAgentUnmute"); - } - if (LLStringUtil::endsWith(url, "/im")) - { - return LLTrans::getString("TooltipAgentIM"); - } - if (LLStringUtil::endsWith(url, "/pay")) - { - return LLTrans::getString("TooltipAgentPay"); - } - if (LLStringUtil::endsWith(url, "/offerteleport")) - { - return LLTrans::getString("TooltipAgentOfferTeleport"); - } - if (LLStringUtil::endsWith(url, "/requestfriend")) - { - return LLTrans::getString("TooltipAgentRequestFriend"); - } - return LLTrans::getString("TooltipAgentUrl"); + // return a tooltip corresponding to the URL type instead of the generic one + std::string url = getUrl(string); + + if (LLStringUtil::endsWith(url, "/inspect")) + { + return LLTrans::getString("TooltipAgentInspect"); + } + if (LLStringUtil::endsWith(url, "/mute")) + { + return LLTrans::getString("TooltipAgentMute"); + } + if (LLStringUtil::endsWith(url, "/unmute")) + { + return LLTrans::getString("TooltipAgentUnmute"); + } + if (LLStringUtil::endsWith(url, "/im")) + { + return LLTrans::getString("TooltipAgentIM"); + } + if (LLStringUtil::endsWith(url, "/pay")) + { + return LLTrans::getString("TooltipAgentPay"); + } + if (LLStringUtil::endsWith(url, "/offerteleport")) + { + return LLTrans::getString("TooltipAgentOfferTeleport"); + } + if (LLStringUtil::endsWith(url, "/requestfriend")) + { + return LLTrans::getString("TooltipAgentRequestFriend"); + } + return LLTrans::getString("TooltipAgentUrl"); } bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const { - std::string url = getUrl(string); - return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect"); + std::string url = getUrl(string); + return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect"); } std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - if (!gCacheName) - { - // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); - } - - std::string agent_id_string = getIDStringFromUrl(url); - if (agent_id_string.empty()) - { - // something went wrong, just give raw url - return unescapeUrl(url); - } - - LLUUID agent_id(agent_id_string); - if (agent_id.isNull()) - { - return LLTrans::getString("AvatarNameNobody"); - } - - LLAvatarName av_name; - if (LLAvatarNameCache::get(agent_id, &av_name)) - { - std::string label = av_name.getCompleteName(); - - // handle suffixes like /mute or /offerteleport - label = localize_slapp_label(url, label); - return label; - } - else - { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } - mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); - - addObserver(agent_id_string, url, cb); - return LLTrans::getString("LoadingData"); - } + if (!gCacheName) + { + // probably at the login screen, use short string for layout + return LLTrans::getString("LoadingData"); + } + + std::string agent_id_string = getIDStringFromUrl(url); + if (agent_id_string.empty()) + { + // something went wrong, just give raw url + return unescapeUrl(url); + } + + LLUUID agent_id(agent_id_string); + if (agent_id.isNull()) + { + return LLTrans::getString("AvatarNameNobody"); + } + + LLAvatarName av_name; + if (LLAvatarNameCache::get(agent_id, &av_name)) + { + std::string label = av_name.getCompleteName(); + + // handle suffixes like /mute or /offerteleport + label = localize_slapp_label(url, label); + return label; + } + else + { + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + + addObserver(agent_id_string, url, cb); + return LLTrans::getString("LoadingData"); + } } LLStyle::Params LLUrlEntryAgent::getStyle() const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - return style_params; + LLStyle::Params style_params = LLUrlEntryBase::getStyle(); + style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + return style_params; } std::string localize_slapp_label(const std::string& url, const std::string& full_name) { - // customize label string based on agent SLapp suffix - if (LLStringUtil::endsWith(url, "/mute")) - { - return LLTrans::getString("SLappAgentMute") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/unmute")) - { - return LLTrans::getString("SLappAgentUnmute") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/im")) - { - return LLTrans::getString("SLappAgentIM") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/pay")) - { - return LLTrans::getString("SLappAgentPay") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/offerteleport")) - { - return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/requestfriend")) - { - return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name; - } - if (LLStringUtil::endsWith(url, "/removefriend")) - { - return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name; - } - return full_name; + // customize label string based on agent SLapp suffix + if (LLStringUtil::endsWith(url, "/mute")) + { + return LLTrans::getString("SLappAgentMute") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/unmute")) + { + return LLTrans::getString("SLappAgentUnmute") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/im")) + { + return LLTrans::getString("SLappAgentIM") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/pay")) + { + return LLTrans::getString("SLappAgentPay") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/offerteleport")) + { + return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/requestfriend")) + { + return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name; + } + if (LLStringUtil::endsWith(url, "/removefriend")) + { + return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name; + } + return full_name; } std::string LLUrlEntryAgent::getIcon(const std::string &url) { - // *NOTE: Could look up a badge here by calling getIDStringFromUrl() - // and looking up the badge for the agent. - return mIcon; + // *NOTE: Could look up a badge here by calling getIDStringFromUrl() + // and looking up the badge for the agent. + return mIcon; } // @@ -770,71 +770,71 @@ LLUrlEntryAgentName::LLUrlEntryAgentName() {} void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, - const LLAvatarName& av_name) + const LLAvatarName& av_name) { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } - std::string label = getName(av_name); - // received the agent name from the server - tell our observers - callObservers(id.asString(), label, mIcon); + std::string label = getName(av_name); + // received the agent name from the server - tell our observers + callObservers(id.asString(), label, mIcon); } std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - if (!gCacheName) - { - // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); - } - - std::string agent_id_string = getIDStringFromUrl(url); - if (agent_id_string.empty()) - { - // something went wrong, just give raw url - return unescapeUrl(url); - } - - LLUUID agent_id(agent_id_string); - if (agent_id.isNull()) - { - return LLTrans::getString("AvatarNameNobody"); - } - - LLAvatarName av_name; - if (LLAvatarNameCache::get(agent_id, &av_name)) - { - return getName(av_name); - } - else - { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } - mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); - - addObserver(agent_id_string, url, cb); - return LLTrans::getString("LoadingData"); - } + if (!gCacheName) + { + // probably at the login screen, use short string for layout + return LLTrans::getString("LoadingData"); + } + + std::string agent_id_string = getIDStringFromUrl(url); + if (agent_id_string.empty()) + { + // something went wrong, just give raw url + return unescapeUrl(url); + } + + LLUUID agent_id(agent_id_string); + if (agent_id.isNull()) + { + return LLTrans::getString("AvatarNameNobody"); + } + + LLAvatarName av_name; + if (LLAvatarNameCache::get(agent_id, &av_name)) + { + return getName(av_name); + } + else + { + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + + addObserver(agent_id_string, url, cb); + return LLTrans::getString("LoadingData"); + } } LLStyle::Params LLUrlEntryAgentName::getStyle() const { - // don't override default colors - return LLStyle::Params().is_link(false); + // don't override default colors + return LLStyle::Params().is_link(false); } // @@ -844,13 +844,13 @@ LLStyle::Params LLUrlEntryAgentName::getStyle() const // LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName() { - mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name) { - return avatar_name.getCompleteName(true, true); + return avatar_name.getCompleteName(true, true); } // @@ -860,13 +860,13 @@ std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name // LLUrlEntryAgentLegacyName::LLUrlEntryAgentLegacyName() { - mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/legacyname", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/legacyname", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryAgentLegacyName::getName(const LLAvatarName& avatar_name) { - return avatar_name.getLegacyName(); + return avatar_name.getLegacyName(); } // @@ -876,13 +876,13 @@ std::string LLUrlEntryAgentLegacyName::getName(const LLAvatarName& avatar_name) // LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName() { - mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name) { - return avatar_name.getDisplayName(true); + return avatar_name.getDisplayName(true); } // @@ -892,13 +892,13 @@ std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name) // LLUrlEntryAgentUserName::LLUrlEntryAgentUserName() { - mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) { - return avatar_name.getAccountName(); + return avatar_name.getAccountName(); } // @@ -909,70 +909,70 @@ std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) // LLUrlEntryGroup::LLUrlEntryGroup() { - mPattern = boost::regex(APP_HEADER_REGEX "/group/[\\da-f-]+/\\w+", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_group.xml"; - mIcon = "Generic_Group"; - mTooltip = LLTrans::getString("TooltipGroupUrl"); + mPattern = boost::regex(APP_HEADER_REGEX "/group/[\\da-f-]+/\\w+", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_group.xml"; + mIcon = "Generic_Group"; + mTooltip = LLTrans::getString("TooltipGroupUrl"); } void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id, - const std::string& name, - bool is_group) + const std::string& name, + bool is_group) { - // received the group name from the server - tell our observers - callObservers(id.asString(), name, mIcon); + // received the group name from the server - tell our observers + callObservers(id.asString(), name, mIcon); } -LLUUID LLUrlEntryGroup::getID(const std::string &string) const +LLUUID LLUrlEntryGroup::getID(const std::string &string) const { - return LLUUID(getIDStringFromUrl(string)); + return LLUUID(getIDStringFromUrl(string)); } std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - if (!gCacheName) - { - // probably at login screen, give something short for layout - return LLTrans::getString("LoadingData"); - } - - std::string group_id_string = getIDStringFromUrl(url); - if (group_id_string.empty()) - { - // something went wrong, give raw url - return unescapeUrl(url); - } - - LLUUID group_id(group_id_string); - std::string group_name; - if (group_id.isNull()) - { - return LLTrans::getString("GroupNameNone"); - } - else if (gCacheName->getGroupName(group_id, group_name)) - { - return group_name; - } - else - { - gCacheName->getGroup(group_id, - boost::bind(&LLUrlEntryGroup::onGroupNameReceived, - this, _1, _2, _3)); - addObserver(group_id_string, url, cb); - return LLTrans::getString("LoadingData"); - } + if (!gCacheName) + { + // probably at login screen, give something short for layout + return LLTrans::getString("LoadingData"); + } + + std::string group_id_string = getIDStringFromUrl(url); + if (group_id_string.empty()) + { + // something went wrong, give raw url + return unescapeUrl(url); + } + + LLUUID group_id(group_id_string); + std::string group_name; + if (group_id.isNull()) + { + return LLTrans::getString("GroupNameNone"); + } + else if (gCacheName->getGroupName(group_id, group_name)) + { + return group_name; + } + else + { + gCacheName->getGroup(group_id, + boost::bind(&LLUrlEntryGroup::onGroupNameReceived, + this, _1, _2, _3)); + addObserver(group_id_string, url, cb); + return LLTrans::getString("LoadingData"); + } } LLStyle::Params LLUrlEntryGroup::getStyle() const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - return style_params; + LLStyle::Params style_params = LLUrlEntryBase::getStyle(); + style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + return style_params; } @@ -982,19 +982,19 @@ LLStyle::Params LLUrlEntryGroup::getStyle() const // LLUrlEntryInventory::LLUrlEntryInventory() { - //*TODO: add supporting of inventory item names with whitespaces - //this pattern cann't parse for example - //secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value - //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value - mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_inventory.xml"; + //*TODO: add supporting of inventory item names with whitespaces + //this pattern cann't parse for example + //secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value + //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value + mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_inventory.xml"; } std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - std::string label = getStringAfterToken(url, "name="); - return LLURI::unescape(label.empty() ? url : label); + std::string label = getStringAfterToken(url, "name="); + return LLURI::unescape(label.empty() ? url : label); } // @@ -1003,27 +1003,27 @@ std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLab // LLUrlEntryObjectIM::LLUrlEntryObjectIM() { - mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\?\\S*\\w", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_objectim.xml"; + mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\?\\S*\\w", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_objectim.xml"; } std::string LLUrlEntryObjectIM::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - LLURI uri(url); - LLSD query_map = uri.queryMap(); - if (query_map.has("name")) - return query_map["name"]; - return unescapeUrl(url); + LLURI uri(url); + LLSD query_map = uri.queryMap(); + if (query_map.has("name")) + return query_map["name"]; + return unescapeUrl(url); } std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const { - LLURI uri(url); - LLSD query_map = uri.queryMap(); - if (query_map.has("slurl")) - return query_map["slurl"]; - return LLUrlEntryBase::getLocation(url); + LLURI uri(url); + LLSD query_map = uri.queryMap(); + if (query_map.has("slurl")) + return query_map["slurl"]; + return LLUrlEntryBase::getLocation(url); } // @@ -1045,10 +1045,10 @@ std::string LLUrlEntryChat::getLabel(const std::string &url, const LLUrlLabelCal } // LLUrlEntryParcel statics. -LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null); -LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); -LLHost LLUrlEntryParcel::sRegionHost; -bool LLUrlEntryParcel::sDisconnected(false); +LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null); +LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); +LLHost LLUrlEntryParcel::sRegionHost; +bool LLUrlEntryParcel::sDisconnected(false); std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers; /// @@ -1058,90 +1058,90 @@ std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers; /// LLUrlEntryParcel::LLUrlEntryParcel() { - mPattern = boost::regex(APP_HEADER_REGEX "/parcel/[\\da-f-]+/about", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_parcel.xml"; - mTooltip = LLTrans::getString("TooltipParcelUrl"); + mPattern = boost::regex(APP_HEADER_REGEX "/parcel/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_parcel.xml"; + mTooltip = LLTrans::getString("TooltipParcelUrl"); - sParcelInfoObservers.insert(this); + sParcelInfoObservers.insert(this); } LLUrlEntryParcel::~LLUrlEntryParcel() { - sParcelInfoObservers.erase(this); + sParcelInfoObservers.erase(this); } std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - LLSD path_array = LLURI(url).pathArray(); - S32 path_parts = path_array.size(); + LLSD path_array = LLURI(url).pathArray(); + S32 path_parts = path_array.size(); - if (path_parts < 3) // no parcel id - { - LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; - return url; - } + if (path_parts < 3) // no parcel id + { + LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; + return url; + } - std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id + std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id - // Add an observer to call LLUrlLabelCallback when we have parcel name. - addObserver(parcel_id_string, url, cb); + // Add an observer to call LLUrlLabelCallback when we have parcel name. + addObserver(parcel_id_string, url, cb); - LLUUID parcel_id(parcel_id_string); + LLUUID parcel_id(parcel_id_string); - sendParcelInfoRequest(parcel_id); + sendParcelInfoRequest(parcel_id); - return unescapeUrl(url); + return unescapeUrl(url); } void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id) { - if (sRegionHost.isInvalid() || sDisconnected) return; + if (sRegionHost.isInvalid() || sDisconnected) return; - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("ParcelInfoRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, sAgentID ); - msg->addUUID("SessionID", sSessionID); - msg->nextBlock("Data"); - msg->addUUID("ParcelID", parcel_id); - msg->sendReliable(sRegionHost); + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("ParcelInfoRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, sAgentID ); + msg->addUUID("SessionID", sSessionID); + msg->nextBlock("Data"); + msg->addUUID("ParcelID", parcel_id); + msg->sendReliable(sRegionHost); } void LLUrlEntryParcel::onParcelInfoReceived(const std::string &id, const std::string &label) { - callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon); + callObservers(id, label.empty() ? LLTrans::getString("RegionInfoError") : label, mIcon); } // static void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) { - std::string label(LLStringUtil::null); - if (!parcel_data.name.empty()) - { - label = parcel_data.name; - } - // If parcel name is empty use Sim_name (x, y, z) for parcel label. - else if (!parcel_data.sim_name.empty()) - { - S32 region_x = ll_round(parcel_data.global_x) % REGION_WIDTH_UNITS; - S32 region_y = ll_round(parcel_data.global_y) % REGION_WIDTH_UNITS; - S32 region_z = ll_round(parcel_data.global_z); - - label = llformat("%s (%d, %d, %d)", - parcel_data.sim_name.c_str(), region_x, region_y, region_z); - } - - for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin(); - iter != sParcelInfoObservers.end(); - ++iter) - { - LLUrlEntryParcel* url_entry = *iter; - if (url_entry) - { - url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); - } - } + std::string label(LLStringUtil::null); + if (!parcel_data.name.empty()) + { + label = parcel_data.name; + } + // If parcel name is empty use Sim_name (x, y, z) for parcel label. + else if (!parcel_data.sim_name.empty()) + { + S32 region_x = ll_round(parcel_data.global_x) % REGION_WIDTH_UNITS; + S32 region_y = ll_round(parcel_data.global_y) % REGION_WIDTH_UNITS; + S32 region_z = ll_round(parcel_data.global_z); + + label = llformat("%s (%d, %d, %d)", + parcel_data.sim_name.c_str(), region_x, region_y, region_z); + } + + for (std::set<LLUrlEntryParcel*>::iterator iter = sParcelInfoObservers.begin(); + iter != sParcelInfoObservers.end(); + ++iter) + { + LLUrlEntryParcel* url_entry = *iter; + if (url_entry) + { + url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); + } + } } // @@ -1149,46 +1149,46 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) // LLUrlEntryPlace::LLUrlEntryPlace() { - mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_slurl.xml"; - mTooltip = LLTrans::getString("TooltipSLURL"); + mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slurl.xml"; + mTooltip = LLTrans::getString("TooltipSLURL"); } std::string LLUrlEntryPlace::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - // - // we handle SLURLs in the following formats: - // - secondlife://Place/X/Y/Z - // - secondlife://Place/X/Y - // - LLURI uri(url); - std::string location = unescapeUrl(uri.hostName()); - LLSD path_array = uri.pathArray(); - S32 path_parts = path_array.size(); - if (path_parts == 3) - { - // handle slurl with (X,Y,Z) coordinates - std::string x = path_array[0]; - std::string y = path_array[1]; - std::string z = path_array[2]; - return location + " (" + x + "," + y + "," + z + ")"; - } - else if (path_parts == 2) - { - // handle slurl with (X,Y) coordinates - std::string x = path_array[0]; - std::string y = path_array[1]; - return location + " (" + x + "," + y + ")"; - } - - return url; + // + // we handle SLURLs in the following formats: + // - secondlife://Place/X/Y/Z + // - secondlife://Place/X/Y + // + LLURI uri(url); + std::string location = unescapeUrl(uri.hostName()); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + if (path_parts == 3) + { + // handle slurl with (X,Y,Z) coordinates + std::string x = path_array[0]; + std::string y = path_array[1]; + std::string z = path_array[2]; + return location + " (" + x + "," + y + "," + z + ")"; + } + else if (path_parts == 2) + { + // handle slurl with (X,Y) coordinates + std::string x = path_array[0]; + std::string y = path_array[1]; + return location + " (" + x + "," + y + ")"; + } + + return url; } std::string LLUrlEntryPlace::getLocation(const std::string &url) const { - // return the part of the Url after secondlife:// part - return ::getStringAfterToken(url, "://"); + // return the part of the Url after secondlife:// part + return ::getStringAfterToken(url, "://"); } // @@ -1197,61 +1197,61 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const // LLUrlEntryRegion::LLUrlEntryRegion() { - mPattern = boost::regex("secondlife:///app/region/[A-Za-z0-9()_%]+(/\\d+)?(/\\d+)?(/\\d+)?/?", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_slurl.xml"; - mTooltip = LLTrans::getString("TooltipSLURL"); + mPattern = boost::regex("secondlife:///app/region/[A-Za-z0-9()_%]+(/\\d+)?(/\\d+)?(/\\d+)?/?", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slurl.xml"; + mTooltip = LLTrans::getString("TooltipSLURL"); } std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - // - // we handle SLURLs in the following formats: - // - secondlife:///app/region/Place/X/Y/Z - // - secondlife:///app/region/Place/X/Y - // - secondlife:///app/region/Place/X - // - secondlife:///app/region/Place - // + // + // we handle SLURLs in the following formats: + // - secondlife:///app/region/Place/X/Y/Z + // - secondlife:///app/region/Place/X/Y + // - secondlife:///app/region/Place/X + // - secondlife:///app/region/Place + // - LLSD path_array = LLURI(url).pathArray(); - S32 path_parts = path_array.size(); + LLSD path_array = LLURI(url).pathArray(); + S32 path_parts = path_array.size(); - if (path_parts < 3) // no region name - { - LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; - return url; - } - - std::string label = unescapeUrl(path_array[2]); // region name + if (path_parts < 3) // no region name + { + LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; + return url; + } - if (path_parts > 3) // secondlife:///app/region/Place/X - { - std::string x = path_array[3]; - label += " (" + x; + std::string label = unescapeUrl(path_array[2]); // region name - if (path_parts > 4) // secondlife:///app/region/Place/X/Y - { - std::string y = path_array[4]; - label += "," + y; + if (path_parts > 3) // secondlife:///app/region/Place/X + { + std::string x = path_array[3]; + label += " (" + x; - if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z - { - std::string z = path_array[5]; - label = label + "," + z; - } - } + if (path_parts > 4) // secondlife:///app/region/Place/X/Y + { + std::string y = path_array[4]; + label += "," + y; + + if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z + { + std::string z = path_array[5]; + label = label + "," + z; + } + } - label += ")"; - } + label += ")"; + } - return label; + return label; } std::string LLUrlEntryRegion::getLocation(const std::string &url) const { - LLSD path_array = LLURI(url).pathArray(); - std::string region_name = unescapeUrl(path_array[2]); - return region_name; + LLSD path_array = LLURI(url).pathArray(); + std::string region_name = unescapeUrl(path_array[2]); + return region_name; } // @@ -1261,68 +1261,68 @@ std::string LLUrlEntryRegion::getLocation(const std::string &url) const // LLUrlEntryTeleport::LLUrlEntryTeleport() { - mPattern = boost::regex(APP_HEADER_REGEX "/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_teleport.xml"; - mTooltip = LLTrans::getString("TooltipTeleportUrl"); + mPattern = boost::regex(APP_HEADER_REGEX "/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_teleport.xml"; + mTooltip = LLTrans::getString("TooltipTeleportUrl"); } std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - // - // we handle teleport SLURLs in the following formats: - // - secondlife:///app/teleport/Place/X/Y/Z - // - secondlife:///app/teleport/Place/X/Y - // - secondlife:///app/teleport/Place/X - // - secondlife:///app/teleport/Place - // - LLURI uri(url); - LLSD path_array = uri.pathArray(); - S32 path_parts = path_array.size(); - std::string host = uri.hostName(); - std::string label = LLTrans::getString("SLurlLabelTeleport"); - if (!host.empty()) - { - label += " " + host; - } - if (path_parts == 6) - { - // handle teleport url with (X,Y,Z) coordinates - std::string location = unescapeUrl(path_array[path_parts-4]); - std::string x = path_array[path_parts-3]; - std::string y = path_array[path_parts-2]; - std::string z = path_array[path_parts-1]; - return label + " " + location + " (" + x + "," + y + "," + z + ")"; - } - else if (path_parts == 5) - { - // handle teleport url with (X,Y) coordinates - std::string location = unescapeUrl(path_array[path_parts-3]); - std::string x = path_array[path_parts-2]; - std::string y = path_array[path_parts-1]; - return label + " " + location + " (" + x + "," + y + ")"; - } - else if (path_parts == 4) - { - // handle teleport url with (X) coordinate only - std::string location = unescapeUrl(path_array[path_parts-2]); - std::string x = path_array[path_parts-1]; - return label + " " + location + " (" + x + ")"; - } - else if (path_parts == 3) - { - // handle teleport url with no coordinates - std::string location = unescapeUrl(path_array[path_parts-1]); - return label + " " + location; - } - - return url; + // + // we handle teleport SLURLs in the following formats: + // - secondlife:///app/teleport/Place/X/Y/Z + // - secondlife:///app/teleport/Place/X/Y + // - secondlife:///app/teleport/Place/X + // - secondlife:///app/teleport/Place + // + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + std::string host = uri.hostName(); + std::string label = LLTrans::getString("SLurlLabelTeleport"); + if (!host.empty()) + { + label += " " + host; + } + if (path_parts == 6) + { + // handle teleport url with (X,Y,Z) coordinates + std::string location = unescapeUrl(path_array[path_parts-4]); + std::string x = path_array[path_parts-3]; + std::string y = path_array[path_parts-2]; + std::string z = path_array[path_parts-1]; + return label + " " + location + " (" + x + "," + y + "," + z + ")"; + } + else if (path_parts == 5) + { + // handle teleport url with (X,Y) coordinates + std::string location = unescapeUrl(path_array[path_parts-3]); + std::string x = path_array[path_parts-2]; + std::string y = path_array[path_parts-1]; + return label + " " + location + " (" + x + "," + y + ")"; + } + else if (path_parts == 4) + { + // handle teleport url with (X) coordinate only + std::string location = unescapeUrl(path_array[path_parts-2]); + std::string x = path_array[path_parts-1]; + return label + " " + location + " (" + x + ")"; + } + else if (path_parts == 3) + { + // handle teleport url with no coordinates + std::string location = unescapeUrl(path_array[path_parts-1]); + return label + " " + location; + } + + return url; } std::string LLUrlEntryTeleport::getLocation(const std::string &url) const { - // return the part of the Url after ///app/teleport - return ::getStringAfterToken(url, "app/teleport/"); + // return the part of the Url after ///app/teleport + return ::getStringAfterToken(url, "app/teleport/"); } // @@ -1331,15 +1331,15 @@ std::string LLUrlEntryTeleport::getLocation(const std::string &url) const // LLUrlEntrySL::LLUrlEntrySL() { - mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_slapp.xml"; - mTooltip = LLTrans::getString("TooltipSLAPP"); + mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slapp.xml"; + mTooltip = LLTrans::getString("TooltipSLAPP"); } std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return unescapeUrl(url); + return unescapeUrl(url); } // @@ -1348,48 +1348,48 @@ std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallb // LLUrlEntrySLLabel::LLUrlEntrySLLabel() { - mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_slapp.xml"; - mTooltip = LLTrans::getString("TooltipSLAPP"); + mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slapp.xml"; + mTooltip = LLTrans::getString("TooltipSLAPP"); } std::string LLUrlEntrySLLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - std::string label = getLabelFromWikiLink(url); - return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url); + std::string label = getLabelFromWikiLink(url); + return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url); } std::string LLUrlEntrySLLabel::getUrl(const std::string &string) const { - return getUrlFromWikiLink(string); + return getUrlFromWikiLink(string); } std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const { - // return a tooltip corresponding to the URL type instead of the generic one (EXT-4574) - std::string url = getUrl(string); - LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) - { - return match.getTooltip(); - } + // return a tooltip corresponding to the URL type instead of the generic one (EXT-4574) + std::string url = getUrl(string); + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.getTooltip(); + } - // unrecognized URL? should not happen - return LLUrlEntryBase::getTooltip(string); + // unrecognized URL? should not happen + return LLUrlEntryBase::getTooltip(string); } bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const { - std::string url = getUrl(string); - LLUrlMatch match; - if (LLUrlRegistry::instance().findUrl(url, match)) - { - return match.underlineOnHoverOnly(); - } + std::string url = getUrl(string); + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.underlineOnHoverOnly(); + } - // unrecognized URL? should not happen - return LLUrlEntryBase::underlineOnHoverOnly(string); + // unrecognized URL? should not happen + return LLUrlEntryBase::underlineOnHoverOnly(string); } // @@ -1397,40 +1397,40 @@ bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const // LLUrlEntryWorldMap::LLUrlEntryWorldMap() { - mPattern = boost::regex(APP_HEADER_REGEX "/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", - boost::regex::perl|boost::regex::icase); - mMenuName = "menu_url_map.xml"; - mTooltip = LLTrans::getString("TooltipMapUrl"); + mPattern = boost::regex(APP_HEADER_REGEX "/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_map.xml"; + mTooltip = LLTrans::getString("TooltipMapUrl"); } std::string LLUrlEntryWorldMap::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - // - // we handle SLURLs in the following formats: - // - secondlife:///app/worldmap/PLACE/X/Y/Z - // - secondlife:///app/worldmap/PLACE/X/Y - // - secondlife:///app/worldmap/PLACE/X - // - LLURI uri(url); - LLSD path_array = uri.pathArray(); - S32 path_parts = path_array.size(); - if (path_parts < 3) - { - return url; - } - - const std::string label = LLTrans::getString("SLurlLabelShowOnMap"); - std::string location = unescapeUrl(path_array[2]); - std::string x = (path_parts > 3) ? path_array[3] : "128"; - std::string y = (path_parts > 4) ? path_array[4] : "128"; - std::string z = (path_parts > 5) ? path_array[5] : "0"; - return label + " " + location + " (" + x + "," + y + "," + z + ")"; + // + // we handle SLURLs in the following formats: + // - secondlife:///app/worldmap/PLACE/X/Y/Z + // - secondlife:///app/worldmap/PLACE/X/Y + // - secondlife:///app/worldmap/PLACE/X + // + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + if (path_parts < 3) + { + return url; + } + + const std::string label = LLTrans::getString("SLurlLabelShowOnMap"); + std::string location = unescapeUrl(path_array[2]); + std::string x = (path_parts > 3) ? path_array[3] : "128"; + std::string y = (path_parts > 4) ? path_array[4] : "128"; + std::string z = (path_parts > 5) ? path_array[5] : "0"; + return label + " " + location + " (" + x + "," + y + "," + z + ")"; } std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const { - // return the part of the Url after secondlife:///app/worldmap/ part - return ::getStringAfterToken(url, "app/worldmap/"); + // return the part of the Url after secondlife:///app/worldmap/ part + return ::getStringAfterToken(url, "app/worldmap/"); } // @@ -1438,25 +1438,25 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const // LLUrlEntryNoLink::LLUrlEntryNoLink() { - mPattern = boost::regex("<nolink>.*?</nolink>", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex("<nolink>.*?</nolink>", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryNoLink::getUrl(const std::string &url) const { - // return the text between the <nolink> and </nolink> tags - return url.substr(8, url.size()-8-9); + // return the text between the <nolink> and </nolink> tags + return url.substr(8, url.size()-8-9); } std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return getUrl(url); + return getUrl(url); } -LLStyle::Params LLUrlEntryNoLink::getStyle() const -{ - // Don't render as URL (i.e. no context menu or hand cursor). - return LLStyle::Params().is_link(false); +LLStyle::Params LLUrlEntryNoLink::getStyle() const +{ + // Don't render as URL (i.e. no context menu or hand cursor). + return LLStyle::Params().is_link(false); } @@ -1465,64 +1465,64 @@ LLStyle::Params LLUrlEntryNoLink::getStyle() const // LLUrlEntryIcon::LLUrlEntryIcon() { - mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>", + boost::regex::perl|boost::regex::icase); } std::string LLUrlEntryIcon::getUrl(const std::string &url) const { - return LLStringUtil::null; + return LLStringUtil::null; } std::string LLUrlEntryIcon::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return LLStringUtil::null; + return LLStringUtil::null; } std::string LLUrlEntryIcon::getIcon(const std::string &url) { - // Grep icon info between <icon>...</icon> tags - // matches[1] contains the icon name/path - boost::match_results<std::string::const_iterator> matches; - mIcon = (ll_regex_match(url, matches, mPattern) && matches[1].matched) - ? matches[1] - : LLStringUtil::null; - LLStringUtil::trim(mIcon); - return mIcon; + // Grep icon info between <icon>...</icon> tags + // matches[1] contains the icon name/path + boost::match_results<std::string::const_iterator> matches; + mIcon = (ll_regex_match(url, matches, mPattern) && matches[1].matched) + ? matches[1] + : LLStringUtil::null; + LLStringUtil::trim(mIcon); + return mIcon; } // // LLUrlEntryEmail Describes a generic mailto: Urls // LLUrlEntryEmail::LLUrlEntryEmail() - : LLUrlEntryBase() + : LLUrlEntryBase() { - mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,63}", - boost::regex::perl | boost::regex::icase); - mMenuName = "menu_url_email.xml"; - mTooltip = LLTrans::getString("TooltipEmail"); + mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,63}", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_email.xml"; + mTooltip = LLTrans::getString("TooltipEmail"); } std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - int pos = url.find("mailto:"); + int pos = url.find("mailto:"); - if (pos == std::string::npos) - { - return escapeUrl(url); - } + if (pos == std::string::npos) + { + return escapeUrl(url); + } - std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8)); - return ret; + std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8)); + return ret; } std::string LLUrlEntryEmail::getUrl(const std::string &string) const { - if (string.find("mailto:") == std::string::npos) - { - return "mailto:" + escapeUrl(string); - } - return escapeUrl(string); + if (string.find("mailto:") == std::string::npos) + { + return "mailto:" + escapeUrl(string); + } + return escapeUrl(string); } LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile() @@ -1530,7 +1530,7 @@ LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile() mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/profile", boost::regex::perl|boost::regex::icase); mIcon = "Generic_Experience"; - mMenuName = "menu_url_experience.xml"; + mMenuName = "menu_url_experience.xml"; } std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const LLUrlLabelCallback &cb ) @@ -1557,7 +1557,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); if(!experience_details.isUndefined()) { - std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); return experience_name_string.empty() ? LLTrans::getString("ExperienceNameUntitled") : experience_name_string; } @@ -1569,11 +1569,11 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_details ) { - std::string name = experience_details[LLExperienceCache::NAME].asString(); - if(name.empty()) - { - name = LLTrans::getString("ExperienceNameUntitled"); - } + std::string name = experience_details[LLExperienceCache::NAME].asString(); + if(name.empty()) + { + name = LLTrans::getString("ExperienceNameUntitled"); + } callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null); } @@ -1581,41 +1581,41 @@ void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_de // LLUrlEntryEmail Describes an IPv6 address // LLUrlEntryIPv6::LLUrlEntryIPv6() - : LLUrlEntryBase() + : LLUrlEntryBase() { - mHostPath = "https?://\\[([a-f0-9:]+:+)+[a-f0-9]+]"; - mPattern = boost::regex(mHostPath + "(:\\d{1,5})?(/\\S*)?", - boost::regex::perl | boost::regex::icase); - mMenuName = "menu_url_http.xml"; - mTooltip = LLTrans::getString("TooltipHttpUrl"); + mHostPath = "https?://\\[([a-f0-9:]+:+)+[a-f0-9]+]"; + mPattern = boost::regex(mHostPath + "(:\\d{1,5})?(/\\S*)?", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); } std::string LLUrlEntryIPv6::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); - boost::match_results<std::string::const_iterator> matches; + boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; - if (boost::regex_search(url, matches, regex)) - { - return url.substr(0, matches[0].length()); - } - else - { - return url; - } + if (boost::regex_search(url, matches, regex)) + { + return url.substr(0, matches[0].length()); + } + else + { + return url; + } } std::string LLUrlEntryIPv6::getQuery(const std::string &url) const { - boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); - boost::match_results<std::string::const_iterator> matches; + boost::regex regex = boost::regex(mHostPath, boost::regex::perl | boost::regex::icase); + boost::match_results<std::string::const_iterator> matches; - return boost::regex_replace(url, regex, ""); + return boost::regex_replace(url, regex, ""); } std::string LLUrlEntryIPv6::getUrl(const std::string &string) const { - return string; + return string; } diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 5d0f5479f6..c878a74c5f 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -1,4 +1,4 @@ -/** +/** * @file llurlentry.h * @author Martin Reddy * @brief Describes the Url types that can be registered in LLUrlRegistry @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,12 +43,12 @@ class LLAvatarName; typedef boost::signals2::signal<void (const std::string& url, - const std::string& label, - const std::string& icon)> LLUrlLabelSignal; + const std::string& label, + const std::string& icon)> LLUrlLabelSignal; typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback; /// -/// LLUrlEntryBase is the base class of all Url types registered in the +/// LLUrlEntryBase is the base class of all Url types registered in the /// LLUrlRegistry. Each derived classes provides a regular expression /// to match the Url type (e.g., http://... or secondlife://...) along /// with an optional icon to display next to instances of the Url in @@ -66,70 +66,70 @@ typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback; class LLUrlEntryBase { public: - LLUrlEntryBase(); - virtual ~LLUrlEntryBase(); - - /// Return the regex pattern that matches this Url - boost::regex getPattern() const { return mPattern; } + LLUrlEntryBase(); + virtual ~LLUrlEntryBase(); + + /// Return the regex pattern that matches this Url + boost::regex getPattern() const { return mPattern; } - /// Return the url from a string that matched the regex - virtual std::string getUrl(const std::string &string) const; + /// Return the url from a string that matched the regex + virtual std::string getUrl(const std::string &string) const; - /// Given a matched Url, return a label for the Url - virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; } + /// Given a matched Url, return a label for the Url + virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; } - /// Return port, query and fragment parts for the Url - virtual std::string getQuery(const std::string &url) const { return ""; } + /// Return port, query and fragment parts for the Url + virtual std::string getQuery(const std::string &url) const { return ""; } - /// Return an icon that can be displayed next to Urls of this type - virtual std::string getIcon(const std::string &url); + /// Return an icon that can be displayed next to Urls of this type + virtual std::string getIcon(const std::string &url); - /// Return the style to render the displayed text - virtual LLStyle::Params getStyle() const; + /// Return the style to render the displayed text + virtual LLStyle::Params getStyle() const; - /// Given a matched Url, return a tooltip string for the hyperlink - virtual std::string getTooltip(const std::string &string) const { return mTooltip; } + /// Given a matched Url, return a tooltip string for the hyperlink + virtual std::string getTooltip(const std::string &string) const { return mTooltip; } - /// Return the name of a XUI file containing the context menu items - std::string getMenuName() const { return mMenuName; } + /// Return the name of a XUI file containing the context menu items + std::string getMenuName() const { return mMenuName; } - /// Return the name of a SL location described by this Url, if any - virtual std::string getLocation(const std::string &url) const { return ""; } + /// Return the name of a SL location described by this Url, if any + virtual std::string getLocation(const std::string &url) const { return ""; } - /// Should this link text be underlined only when mouse is hovered over it? - virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } + /// Should this link text be underlined only when mouse is hovered over it? + virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } - virtual bool isTrusted() const { return false; } + virtual bool isTrusted() const { return false; } - virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } + virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } - bool isLinkDisabled() const; + bool isLinkDisabled() const; - bool isWikiLinkCorrect(const std::string &url) const; + bool isWikiLinkCorrect(const std::string &url) const; - virtual bool isSLURLvalid(const std::string &url) const { return TRUE; }; + virtual bool isSLURLvalid(const std::string &url) const { return TRUE; }; protected: - std::string getIDStringFromUrl(const std::string &url) const; - std::string escapeUrl(const std::string &url) const; - std::string unescapeUrl(const std::string &url) const; - std::string getLabelFromWikiLink(const std::string &url) const; - std::string getUrlFromWikiLink(const std::string &string) const; - void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb); - std::string urlToLabelWithGreyQuery(const std::string &url) const; - std::string urlToGreyQuery(const std::string &url) const; - virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon); - - typedef struct { - std::string url; - LLUrlLabelSignal *signal; - } LLUrlEntryObserver; - - boost::regex mPattern; - std::string mIcon; - std::string mMenuName; - std::string mTooltip; - std::multimap<std::string, LLUrlEntryObserver> mObservers; + std::string getIDStringFromUrl(const std::string &url) const; + std::string escapeUrl(const std::string &url) const; + std::string unescapeUrl(const std::string &url) const; + std::string getLabelFromWikiLink(const std::string &url) const; + std::string getUrlFromWikiLink(const std::string &string) const; + void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb); + std::string urlToLabelWithGreyQuery(const std::string &url) const; + std::string urlToGreyQuery(const std::string &url) const; + virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon); + + typedef struct { + std::string url; + LLUrlLabelSignal *signal; + } LLUrlEntryObserver; + + boost::regex mPattern; + std::string mIcon; + std::string mMenuName; + std::string mTooltip; + std::multimap<std::string, LLUrlEntryObserver> mObservers; }; /// @@ -138,11 +138,11 @@ protected: class LLUrlEntryHTTP : public LLUrlEntryBase { public: - LLUrlEntryHTTP(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getQuery(const std::string &url) const; - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getTooltip(const std::string &url) const; + LLUrlEntryHTTP(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getQuery(const std::string &url) const; + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getTooltip(const std::string &url) const; }; /// @@ -151,21 +151,21 @@ public: class LLUrlEntryHTTPLabel : public LLUrlEntryBase { public: - LLUrlEntryHTTPLabel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ std::string getUrl(const std::string &string) const; + LLUrlEntryHTTPLabel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getTooltip(const std::string &string) const; + /*virtual*/ std::string getUrl(const std::string &string) const; }; class LLUrlEntryInvalidSLURL : public LLUrlEntryBase { public: - LLUrlEntryInvalidSLURL(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getTooltip(const std::string &url) const; + LLUrlEntryInvalidSLURL(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getTooltip(const std::string &url) const; - bool isSLURLvalid(const std::string &url) const; + bool isSLURLvalid(const std::string &url) const; }; /// @@ -174,10 +174,10 @@ public: class LLUrlEntrySLURL : public LLUrlEntryBase { public: - LLUrlEntrySLURL(); - /*virtual*/ bool isTrusted() const { return true; } - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntrySLURL(); + /*virtual*/ bool isTrusted() const { return true; } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; }; /// @@ -186,12 +186,12 @@ public: class LLUrlEntrySecondlifeURL : public LLUrlEntryBase { public: - LLUrlEntrySecondlifeURL(); - /*virtual*/ bool isTrusted() const { return true; } - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getQuery(const std::string &url) const; - /*virtual*/ std::string getTooltip(const std::string &url) const; + LLUrlEntrySecondlifeURL(); + /*virtual*/ bool isTrusted() const { return true; } + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getQuery(const std::string &url) const; + /*virtual*/ std::string getTooltip(const std::string &url) const; }; /// @@ -200,7 +200,7 @@ public: class LLUrlEntrySimpleSecondlifeURL : public LLUrlEntrySecondlifeURL { public: - LLUrlEntrySimpleSecondlifeURL(); + LLUrlEntrySimpleSecondlifeURL(); }; /// @@ -209,31 +209,31 @@ public: class LLUrlEntryAgent : public LLUrlEntryBase { public: - LLUrlEntryAgent(); - ~LLUrlEntryAgent() - { - for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - } - mAvatarNameCacheConnections.clear(); - } - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getIcon(const std::string &url); - /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ LLStyle::Params getStyle() const; - /*virtual*/ LLUUID getID(const std::string &string) const; - /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; + LLUrlEntryAgent(); + ~LLUrlEntryAgent() + { + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); + } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getIcon(const std::string &url); + /*virtual*/ std::string getTooltip(const std::string &string) const; + /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLUUID getID(const std::string &string) const; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; protected: - /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); + /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); private: - void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); + void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; - avatar_name_cache_connection_map_t mAvatarNameCacheConnections; + typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; /// @@ -244,28 +244,28 @@ private: class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::trackable { public: - LLUrlEntryAgentName(); - ~LLUrlEntryAgentName() - { - for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - } - mAvatarNameCacheConnections.clear(); - } - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ LLStyle::Params getStyle() const; + LLUrlEntryAgentName(); + ~LLUrlEntryAgentName() + { + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); + } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ LLStyle::Params getStyle() const; protected: - // override this to pull out relevant name fields - virtual std::string getName(const LLAvatarName& avatar_name) = 0; + // override this to pull out relevant name fields + virtual std::string getName(const LLAvatarName& avatar_name) = 0; private: - void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); + void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; - avatar_name_cache_connection_map_t mAvatarNameCacheConnections; + typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; @@ -277,17 +277,17 @@ private: class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName { public: - LLUrlEntryAgentCompleteName(); + LLUrlEntryAgentCompleteName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; class LLUrlEntryAgentLegacyName : public LLUrlEntryAgentName { public: - LLUrlEntryAgentLegacyName(); + LLUrlEntryAgentLegacyName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; /// @@ -298,9 +298,9 @@ private: class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName { public: - LLUrlEntryAgentDisplayName(); + LLUrlEntryAgentDisplayName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; /// @@ -311,9 +311,9 @@ private: class LLUrlEntryAgentUserName : public LLUrlEntryAgentName { public: - LLUrlEntryAgentUserName(); + LLUrlEntryAgentUserName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; /// @@ -337,12 +337,12 @@ private: class LLUrlEntryGroup : public LLUrlEntryBase { public: - LLUrlEntryGroup(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ LLStyle::Params getStyle() const; - /*virtual*/ LLUUID getID(const std::string &string) const; + LLUrlEntryGroup(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLUUID getID(const std::string &string) const; private: - void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group); + void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group); }; /// @@ -352,8 +352,8 @@ private: class LLUrlEntryInventory : public LLUrlEntryBase { public: - LLUrlEntryInventory(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + LLUrlEntryInventory(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); private: }; @@ -364,9 +364,9 @@ private: class LLUrlEntryObjectIM : public LLUrlEntryBase { public: - LLUrlEntryObjectIM(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntryObjectIM(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; private: }; @@ -388,44 +388,44 @@ public: class LLUrlEntryParcel : public LLUrlEntryBase { public: - struct LLParcelData - { - LLUUID parcel_id; - std::string name; - std::string sim_name; - F32 global_x; - F32 global_y; - F32 global_z; - }; - - LLUrlEntryParcel(); - ~LLUrlEntryParcel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - - // Sends a parcel info request to sim. - void sendParcelInfoRequest(const LLUUID& parcel_id); - - // Calls observers of certain parcel id providing them with parcel label. - void onParcelInfoReceived(const std::string &id, const std::string &label); - - // Processes parcel label and triggers notifying observers. - static void processParcelInfo(const LLParcelData& parcel_data); - - // Next 4 setters are used to update agent and viewer connection information - // upon events like user login, viewer disconnect and user changing region host. - // These setters are made public to be accessible from newview and should not be - // used in other cases. - static void setAgentID(const LLUUID& id) { sAgentID = id; } - static void setSessionID(const LLUUID& id) { sSessionID = id; } - static void setRegionHost(const LLHost& host) { sRegionHost = host; } - static void setDisconnected(bool disconnected) { sDisconnected = disconnected; } + struct LLParcelData + { + LLUUID parcel_id; + std::string name; + std::string sim_name; + F32 global_x; + F32 global_y; + F32 global_z; + }; + + LLUrlEntryParcel(); + ~LLUrlEntryParcel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + + // Sends a parcel info request to sim. + void sendParcelInfoRequest(const LLUUID& parcel_id); + + // Calls observers of certain parcel id providing them with parcel label. + void onParcelInfoReceived(const std::string &id, const std::string &label); + + // Processes parcel label and triggers notifying observers. + static void processParcelInfo(const LLParcelData& parcel_data); + + // Next 4 setters are used to update agent and viewer connection information + // upon events like user login, viewer disconnect and user changing region host. + // These setters are made public to be accessible from newview and should not be + // used in other cases. + static void setAgentID(const LLUUID& id) { sAgentID = id; } + static void setSessionID(const LLUUID& id) { sSessionID = id; } + static void setRegionHost(const LLHost& host) { sRegionHost = host; } + static void setDisconnected(bool disconnected) { sDisconnected = disconnected; } private: - static LLUUID sAgentID; - static LLUUID sSessionID; - static LLHost sRegionHost; - static bool sDisconnected; - static std::set<LLUrlEntryParcel*> sParcelInfoObservers; + static LLUUID sAgentID; + static LLUUID sSessionID; + static LLHost sRegionHost; + static bool sDisconnected; + static std::set<LLUrlEntryParcel*> sParcelInfoObservers; }; /// @@ -435,9 +435,9 @@ private: class LLUrlEntryPlace : public LLUrlEntryBase { public: - LLUrlEntryPlace(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntryPlace(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; }; /// @@ -447,9 +447,9 @@ public: class LLUrlEntryRegion : public LLUrlEntryBase { public: - LLUrlEntryRegion(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntryRegion(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; }; /// @@ -459,9 +459,9 @@ public: class LLUrlEntryTeleport : public LLUrlEntryBase { public: - LLUrlEntryTeleport(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntryTeleport(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; }; /// @@ -471,8 +471,8 @@ public: class LLUrlEntrySL : public LLUrlEntryBase { public: - LLUrlEntrySL(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + LLUrlEntrySL(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); }; /// @@ -482,11 +482,11 @@ public: class LLUrlEntrySLLabel : public LLUrlEntryBase { public: - LLUrlEntrySLLabel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; + LLUrlEntrySLLabel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getTooltip(const std::string &string) const; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; }; /// @@ -496,9 +496,9 @@ public: class LLUrlEntryWorldMap : public LLUrlEntryBase { public: - LLUrlEntryWorldMap(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + LLUrlEntryWorldMap(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; }; /// @@ -507,10 +507,10 @@ public: class LLUrlEntryNoLink : public LLUrlEntryBase { public: - LLUrlEntryNoLink(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ LLStyle::Params getStyle() const; + LLUrlEntryNoLink(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ LLStyle::Params getStyle() const; }; /// @@ -519,10 +519,10 @@ public: class LLUrlEntryIcon : public LLUrlEntryBase { public: - LLUrlEntryIcon(); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getIcon(const std::string &url); + LLUrlEntryIcon(); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getIcon(const std::string &url); }; /// @@ -531,9 +531,9 @@ public: class LLUrlEntryEmail : public LLUrlEntryBase { public: - LLUrlEntryEmail(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; + LLUrlEntryEmail(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; }; /// @@ -542,12 +542,12 @@ public: class LLUrlEntryIPv6 : public LLUrlEntryBase { public: - LLUrlEntryIPv6(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getQuery(const std::string &url) const; + LLUrlEntryIPv6(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getQuery(const std::string &url) const; - std::string mHostPath; + std::string mHostPath; }; class LLKeyBindingToStringHandler; diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index 2f2ac969e1..bfa3b167b1 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llurlmatch.cpp * @author Martin Reddy * @brief Specifies a matched Url in a string, as returned by LLUrlRegistry @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,37 +29,37 @@ #include "llurlmatch.h" LLUrlMatch::LLUrlMatch() : - mStart(0), - mEnd(0), - mUrl(""), - mLabel(""), - mTooltip(""), - mIcon(""), - mMenuName(""), - mLocation(""), - mUnderlineOnHoverOnly(false), - mTrusted(false) + mStart(0), + mEnd(0), + mUrl(""), + mLabel(""), + mTooltip(""), + mIcon(""), + mMenuName(""), + mLocation(""), + mUnderlineOnHoverOnly(false), + mTrusted(false) { } void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std::string &label, - const std::string& query, const std::string &tooltip, - const std::string &icon, const LLStyle::Params& style, - const std::string &menu, const std::string &location, - const LLUUID& id, bool underline_on_hover_only, bool trusted) + const std::string& query, const std::string &tooltip, + const std::string &icon, const LLStyle::Params& style, + const std::string &menu, const std::string &location, + const LLUUID& id, bool underline_on_hover_only, bool trusted) { - mStart = start; - mEnd = end; - mUrl = url; - mLabel = label; - mQuery = query; - mTooltip = tooltip; - mIcon = icon; - mStyle = style; - mStyle.link_href = url; - mMenuName = menu; - mLocation = location; - mID = id; - mUnderlineOnHoverOnly = underline_on_hover_only; - mTrusted = trusted; + mStart = start; + mEnd = end; + mUrl = url; + mLabel = label; + mQuery = query; + mTooltip = tooltip; + mIcon = icon; + mStyle = style; + mStyle.link_href = url; + mMenuName = menu; + mLocation = location; + mID = id; + mUnderlineOnHoverOnly = underline_on_hover_only; + mTrusted = trusted; } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index ff699902ca..ba822fbda6 100644 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -1,4 +1,4 @@ -/** +/** * @file llurlmatch.h * @author Martin Reddy * @brief Specifies a matched Url in a string, as returned by LLUrlRegistry @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #include "llstyle.h" /// -/// LLUrlMatch describes a single Url that was matched within a string by +/// LLUrlMatch describes a single Url that was matched within a string by /// the LLUrlRegistry::findUrl() method. It includes the actual Url that /// was matched along with its first/last character offset in the string. /// An alternate label is also provided for creating a hyperlink, as well @@ -45,69 +45,69 @@ class LLUrlMatch { public: - LLUrlMatch(); + LLUrlMatch(); - /// return true if this object does not contain a valid Url match yet - bool empty() const { return mUrl.empty(); } + /// return true if this object does not contain a valid Url match yet + bool empty() const { return mUrl.empty(); } - /// return the offset in the string for the first character of the Url - U32 getStart() const { return mStart; } + /// return the offset in the string for the first character of the Url + U32 getStart() const { return mStart; } - /// return the offset in the string for the last character of the Url - U32 getEnd() const { return mEnd; } + /// return the offset in the string for the last character of the Url + U32 getEnd() const { return mEnd; } - /// return the Url that has been matched in the input string - std::string getUrl() const { return mUrl; } + /// return the Url that has been matched in the input string + std::string getUrl() const { return mUrl; } - /// return a label that can be used for the display of this Url - std::string getLabel() const { return mLabel; } + /// return a label that can be used for the display of this Url + std::string getLabel() const { return mLabel; } - /// return a right part of url which should be drawn in grey - std::string getQuery() const { return mQuery; } + /// return a right part of url which should be drawn in grey + std::string getQuery() const { return mQuery; } - /// return a message that could be displayed in a tooltip or status bar - std::string getTooltip() const { return mTooltip; } + /// return a message that could be displayed in a tooltip or status bar + std::string getTooltip() const { return mTooltip; } - /// return the filename for an icon that can be displayed next to this Url - std::string getIcon() const { return mIcon; } + /// return the filename for an icon that can be displayed next to this Url + std::string getIcon() const { return mIcon; } - /// Return the color to render the displayed text - LLStyle::Params getStyle() const { return mStyle; } + /// Return the color to render the displayed text + LLStyle::Params getStyle() const { return mStyle; } - /// Return the name of a XUI file containing the context menu items - std::string getMenuName() const { return mMenuName; } + /// Return the name of a XUI file containing the context menu items + std::string getMenuName() const { return mMenuName; } - /// return the SL location that this Url describes, or "" if none. - std::string getLocation() const { return mLocation; } + /// return the SL location that this Url describes, or "" if none. + std::string getLocation() const { return mLocation; } - /// Should this link text be underlined only when mouse is hovered over it? - bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } + /// Should this link text be underlined only when mouse is hovered over it? + bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } - /// Return true if Url is trusted. - bool isTrusted() const { return mTrusted; } + /// Return true if Url is trusted. + bool isTrusted() const { return mTrusted; } - /// Change the contents of this match object (used by LLUrlRegistry) - void setValues(U32 start, U32 end, const std::string &url, const std::string &label, - const std::string& query, const std::string &tooltip, const std::string &icon, - const LLStyle::Params& style, const std::string &menu, - const std::string &location, const LLUUID& id, - bool underline_on_hover_only = false, bool trusted = false); + /// Change the contents of this match object (used by LLUrlRegistry) + void setValues(U32 start, U32 end, const std::string &url, const std::string &label, + const std::string& query, const std::string &tooltip, const std::string &icon, + const LLStyle::Params& style, const std::string &menu, + const std::string &location, const LLUUID& id, + bool underline_on_hover_only = false, bool trusted = false); - const LLUUID& getID() const { return mID; } + const LLUUID& getID() const { return mID; } private: - U32 mStart; - U32 mEnd; - std::string mUrl; - std::string mLabel; - std::string mQuery; - std::string mTooltip; - std::string mIcon; - std::string mMenuName; - std::string mLocation; - LLUUID mID; - LLStyle::Params mStyle; - bool mUnderlineOnHoverOnly; - bool mTrusted; + U32 mStart; + U32 mEnd; + std::string mUrl; + std::string mLabel; + std::string mQuery; + std::string mTooltip; + std::string mIcon; + std::string mMenuName; + std::string mLocation; + LLUUID mID; + LLStyle::Params mStyle; + bool mUnderlineOnHoverOnly; + bool mTrusted; }; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index f1df7699e2..9c3994480c 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llurlregistry.cpp * @author Martin Reddy * @brief Contains a set of Url types that can be matched in a string @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,278 +38,278 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, LLUrlRegistry::LLUrlRegistry() { - mUrlEntry.reserve(20); - - // Urls are matched in the order that they were registered - mUrlEntryNoLink = new LLUrlEntryNoLink(); - registerUrl(mUrlEntryNoLink); - mUrlEntryIcon = new LLUrlEntryIcon(); - registerUrl(mUrlEntryIcon); - mLLUrlEntryInvalidSLURL = new LLUrlEntryInvalidSLURL(); - registerUrl(mLLUrlEntryInvalidSLURL); - registerUrl(new LLUrlEntrySLURL()); - - // decorated links for host names like: secondlife.com and lindenlab.com - registerUrl(new LLUrlEntrySecondlifeURL()); - registerUrl(new LLUrlEntrySimpleSecondlifeURL()); - - registerUrl(new LLUrlEntryHTTP()); - mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel(); - registerUrl(mUrlEntryHTTPLabel); - registerUrl(new LLUrlEntryAgentCompleteName()); - registerUrl(new LLUrlEntryAgentLegacyName()); - registerUrl(new LLUrlEntryAgentDisplayName()); - registerUrl(new LLUrlEntryAgentUserName()); - // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since - // LLUrlEntryAgent is a less specific (catchall for agent urls) - registerUrl(new LLUrlEntryAgent()); + mUrlEntry.reserve(20); + + // Urls are matched in the order that they were registered + mUrlEntryNoLink = new LLUrlEntryNoLink(); + registerUrl(mUrlEntryNoLink); + mUrlEntryIcon = new LLUrlEntryIcon(); + registerUrl(mUrlEntryIcon); + mLLUrlEntryInvalidSLURL = new LLUrlEntryInvalidSLURL(); + registerUrl(mLLUrlEntryInvalidSLURL); + registerUrl(new LLUrlEntrySLURL()); + + // decorated links for host names like: secondlife.com and lindenlab.com + registerUrl(new LLUrlEntrySecondlifeURL()); + registerUrl(new LLUrlEntrySimpleSecondlifeURL()); + + registerUrl(new LLUrlEntryHTTP()); + mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel(); + registerUrl(mUrlEntryHTTPLabel); + registerUrl(new LLUrlEntryAgentCompleteName()); + registerUrl(new LLUrlEntryAgentLegacyName()); + registerUrl(new LLUrlEntryAgentDisplayName()); + registerUrl(new LLUrlEntryAgentUserName()); + // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since + // LLUrlEntryAgent is a less specific (catchall for agent urls) + registerUrl(new LLUrlEntryAgent()); registerUrl(new LLUrlEntryChat()); - registerUrl(new LLUrlEntryGroup()); - registerUrl(new LLUrlEntryParcel()); - registerUrl(new LLUrlEntryTeleport()); - registerUrl(new LLUrlEntryRegion()); - registerUrl(new LLUrlEntryWorldMap()); - registerUrl(new LLUrlEntryObjectIM()); - registerUrl(new LLUrlEntryPlace()); - registerUrl(new LLUrlEntryInventory()); + registerUrl(new LLUrlEntryGroup()); + registerUrl(new LLUrlEntryParcel()); + registerUrl(new LLUrlEntryTeleport()); + registerUrl(new LLUrlEntryRegion()); + registerUrl(new LLUrlEntryWorldMap()); + registerUrl(new LLUrlEntryObjectIM()); + registerUrl(new LLUrlEntryPlace()); + registerUrl(new LLUrlEntryInventory()); registerUrl(new LLUrlEntryExperienceProfile()); mUrlEntryKeybinding = new LLUrlEntryKeybinding(); registerUrl(mUrlEntryKeybinding); - //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, - //so it should be registered in the end of list - registerUrl(new LLUrlEntrySL()); - mUrlEntrySLLabel = new LLUrlEntrySLLabel(); - registerUrl(mUrlEntrySLLabel); - registerUrl(new LLUrlEntryEmail()); - registerUrl(new LLUrlEntryIPv6()); + //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, + //so it should be registered in the end of list + registerUrl(new LLUrlEntrySL()); + mUrlEntrySLLabel = new LLUrlEntrySLLabel(); + registerUrl(mUrlEntrySLLabel); + registerUrl(new LLUrlEntryEmail()); + registerUrl(new LLUrlEntryIPv6()); } LLUrlRegistry::~LLUrlRegistry() { - // free all of the LLUrlEntryBase objects we are holding - std::vector<LLUrlEntryBase *>::iterator it; - for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) - { - delete *it; - } + // free all of the LLUrlEntryBase objects we are holding + std::vector<LLUrlEntryBase *>::iterator it; + for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) + { + delete *it; + } } void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front) { - if (url) - { - if (force_front) // IDEVO - mUrlEntry.insert(mUrlEntry.begin(), url); - else - mUrlEntry.push_back(url); - } + if (url) + { + if (force_front) // IDEVO + mUrlEntry.insert(mUrlEntry.begin(), url); + else + mUrlEntry.push_back(url); + } } static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end) { - boost::cmatch result; - bool found; - - found = ll_regex_search(text, result, regex); - - if (! found) - { - return false; - } - - // return the first/last character offset for the matched substring - start = static_cast<U32>(result[0].first - text); - end = static_cast<U32>(result[0].second - text) - 1; - - // we allow certain punctuation to terminate a Url but not match it, - // e.g., "http://foo.com/." should just match "http://foo.com/" - if (text[end] == '.' || text[end] == ',') - { - end--; - } - // ignore a terminating ')' when Url contains no matching '(' - // see DEV-19842 for details - else if (text[end] == ')' && std::string(text+start, end-start).find('(') == std::string::npos) - { - end--; - } - - else if (text[end] == ']' && std::string(text+start, end-start).find('[') == std::string::npos) - { - end--; - } - - return true; + boost::cmatch result; + bool found; + + found = ll_regex_search(text, result, regex); + + if (! found) + { + return false; + } + + // return the first/last character offset for the matched substring + start = static_cast<U32>(result[0].first - text); + end = static_cast<U32>(result[0].second - text) - 1; + + // we allow certain punctuation to terminate a Url but not match it, + // e.g., "http://foo.com/." should just match "http://foo.com/" + if (text[end] == '.' || text[end] == ',') + { + end--; + } + // ignore a terminating ')' when Url contains no matching '(' + // see DEV-19842 for details + else if (text[end] == ')' && std::string(text+start, end-start).find('(') == std::string::npos) + { + end--; + } + + else if (text[end] == ']' && std::string(text+start, end-start).find('[') == std::string::npos) + { + end--; + } + + return true; } static bool stringHasUrl(const std::string &text) { - // fast heuristic test for a URL in a string. This is used - // to avoid lots of costly regex calls, BUT it needs to be - // kept in sync with the LLUrlEntry regexes we support. - return (text.find("://") != std::string::npos || - text.find("www.") != std::string::npos || - text.find(".com") != std::string::npos || - text.find("<nolink>") != std::string::npos || - text.find("<icon") != std::string::npos || - text.find("@") != std::string::npos); + // fast heuristic test for a URL in a string. This is used + // to avoid lots of costly regex calls, BUT it needs to be + // kept in sync with the LLUrlEntry regexes we support. + return (text.find("://") != std::string::npos || + text.find("www.") != std::string::npos || + text.find(".com") != std::string::npos || + text.find("<nolink>") != std::string::npos || + text.find("<icon") != std::string::npos || + text.find("@") != std::string::npos); } bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) { - // avoid costly regexes if there is clearly no URL in the text - if (! stringHasUrl(text)) - { - return false; - } - - // find the first matching regex from all url entries in the registry - U32 match_start = 0, match_end = 0; - LLUrlEntryBase *match_entry = NULL; - - std::vector<LLUrlEntryBase *>::iterator it; - for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) - { - //Skip for url entry icon if content is not trusted - if((mUrlEntryIcon == *it) && ((text.find("Hand") != std::string::npos) || !is_content_trusted)) - { - continue; - } - - LLUrlEntryBase *url_entry = *it; - - U32 start = 0, end = 0; - if (matchRegex(text.c_str(), url_entry->getPattern(), start, end)) - { - // does this match occur in the string before any other match - if (start < match_start || match_entry == NULL) - { - - if (mLLUrlEntryInvalidSLURL == *it) - { - if(url_entry && url_entry->isSLURLvalid(text.substr(start, end - start + 1))) - { - continue; - } - } - - if((mUrlEntryHTTPLabel == *it) || (mUrlEntrySLLabel == *it)) - { - if(url_entry && !url_entry->isWikiLinkCorrect(text.substr(start, end - start + 1))) - { - continue; - } - } - - match_start = start; - match_end = end; - match_entry = url_entry; - } - } - } - - // did we find a match? if so, return its details in the match object - if (match_entry) - { - // Skip if link is an email with an empty username (starting with @). See MAINT-5371. - if (match_start > 0 && text.substr(match_start - 1, 1) == "@") - return false; - - // fill in the LLUrlMatch object and return it - std::string url = text.substr(match_start, match_end - match_start + 1); - - if (match_entry == mUrlEntryTrusted) - { - LLUriParser up(url); - if (up.normalize() == 0) + // avoid costly regexes if there is clearly no URL in the text + if (! stringHasUrl(text)) + { + return false; + } + + // find the first matching regex from all url entries in the registry + U32 match_start = 0, match_end = 0; + LLUrlEntryBase *match_entry = NULL; + + std::vector<LLUrlEntryBase *>::iterator it; + for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) + { + //Skip for url entry icon if content is not trusted + if((mUrlEntryIcon == *it) && ((text.find("Hand") != std::string::npos) || !is_content_trusted)) + { + continue; + } + + LLUrlEntryBase *url_entry = *it; + + U32 start = 0, end = 0; + if (matchRegex(text.c_str(), url_entry->getPattern(), start, end)) + { + // does this match occur in the string before any other match + if (start < match_start || match_entry == NULL) + { + + if (mLLUrlEntryInvalidSLURL == *it) + { + if(url_entry && url_entry->isSLURLvalid(text.substr(start, end - start + 1))) + { + continue; + } + } + + if((mUrlEntryHTTPLabel == *it) || (mUrlEntrySLLabel == *it)) + { + if(url_entry && !url_entry->isWikiLinkCorrect(text.substr(start, end - start + 1))) + { + continue; + } + } + + match_start = start; + match_end = end; + match_entry = url_entry; + } + } + } + + // did we find a match? if so, return its details in the match object + if (match_entry) + { + // Skip if link is an email with an empty username (starting with @). See MAINT-5371. + if (match_start > 0 && text.substr(match_start - 1, 1) == "@") + return false; + + // fill in the LLUrlMatch object and return it + std::string url = text.substr(match_start, match_end - match_start + 1); + + if (match_entry == mUrlEntryTrusted) + { + LLUriParser up(url); + if (up.normalize() == 0) { url = up.normalizedUri(); } - } - - match.setValues(match_start, match_end, - match_entry->getUrl(url), - match_entry->getLabel(url, cb), - match_entry->getQuery(url), - match_entry->getTooltip(url), - match_entry->getIcon(url), - match_entry->getStyle(), - match_entry->getMenuName(), - match_entry->getLocation(url), - match_entry->getID(url), - match_entry->underlineOnHoverOnly(url), - match_entry->isTrusted()); - return true; - } - - return false; + } + + match.setValues(match_start, match_end, + match_entry->getUrl(url), + match_entry->getLabel(url, cb), + match_entry->getQuery(url), + match_entry->getTooltip(url), + match_entry->getIcon(url), + match_entry->getStyle(), + match_entry->getMenuName(), + match_entry->getLocation(url), + match_entry->getID(url), + match_entry->underlineOnHoverOnly(url), + match_entry->isTrusted()); + return true; + } + + return false; } bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) { - // boost::regex_search() only works on char or wchar_t - // types, but wchar_t is only 2-bytes on Win32 (not 4). - // So we use UTF-8 to make this work the same everywhere. - std::string utf8_text = wstring_to_utf8str(text); - if (findUrl(utf8_text, match, cb)) - { - // we cannot blindly return the start/end offsets from - // the UTF-8 string because it is a variable-length - // character encoding, so we need to update the start - // and end values to be correct for the wide string. - LLWString wurl = utf8str_to_wstring(match.getUrl()); - size_t start = text.find(wurl); - if (start == std::string::npos) - { - return false; - } - S32 end = start + wurl.size() - 1; - - match.setValues(start, end, match.getUrl(), - match.getLabel(), - match.getQuery(), - match.getTooltip(), - match.getIcon(), - match.getStyle(), - match.getMenuName(), - match.getLocation(), - match.getID(), - match.underlineOnHoverOnly()); - return true; - } - return false; + // boost::regex_search() only works on char or wchar_t + // types, but wchar_t is only 2-bytes on Win32 (not 4). + // So we use UTF-8 to make this work the same everywhere. + std::string utf8_text = wstring_to_utf8str(text); + if (findUrl(utf8_text, match, cb)) + { + // we cannot blindly return the start/end offsets from + // the UTF-8 string because it is a variable-length + // character encoding, so we need to update the start + // and end values to be correct for the wide string. + LLWString wurl = utf8str_to_wstring(match.getUrl()); + size_t start = text.find(wurl); + if (start == std::string::npos) + { + return false; + } + S32 end = start + wurl.size() - 1; + + match.setValues(start, end, match.getUrl(), + match.getLabel(), + match.getQuery(), + match.getTooltip(), + match.getIcon(), + match.getStyle(), + match.getMenuName(), + match.getLocation(), + match.getID(), + match.underlineOnHoverOnly()); + return true; + } + return false; } bool LLUrlRegistry::hasUrl(const std::string &text) { - LLUrlMatch match; - return findUrl(text, match); + LLUrlMatch match; + return findUrl(text, match); } bool LLUrlRegistry::hasUrl(const LLWString &text) { - LLUrlMatch match; - return findUrl(text, match); + LLUrlMatch match; + return findUrl(text, match); } bool LLUrlRegistry::isUrl(const std::string &text) { - LLUrlMatch match; - if (findUrl(text, match)) - { - return (match.getStart() == 0 && match.getEnd() >= text.size()-1); - } - return false; + LLUrlMatch match; + if (findUrl(text, match)) + { + return (match.getStart() == 0 && match.getEnd() >= text.size()-1); + } + return false; } bool LLUrlRegistry::isUrl(const LLWString &text) { - LLUrlMatch match; - if (findUrl(text, match)) - { - return (match.getStart() == 0 && match.getEnd() >= text.size()-1); - } - return false; + LLUrlMatch match; + if (findUrl(text, match)) + { + return (match.getStart() == 0 && match.getEnd() >= text.size()-1); + } + return false; } void LLUrlRegistry::setKeybindingHandler(LLKeyBindingToStringHandler* handler) diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index 186447c0be..64cfec3960 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -1,4 +1,4 @@ -/** +/** * @file llurlregistry.h * @author Martin Reddy * @brief Contains a set of Url types that can be matched in a string @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,8 +40,8 @@ class LLKeyBindingToStringHandler; /// This default callback for findUrl() simply ignores any label updates void LLUrlRegistryNullCallback(const std::string &url, - const std::string &label, - const std::string &icon); + const std::string &label, + const std::string &icon); /// /// LLUrlRegistry is a singleton that contains a set of Url types that @@ -64,43 +64,43 @@ void LLUrlRegistryNullCallback(const std::string &url, /// class LLUrlRegistry : public LLSingleton<LLUrlRegistry> { - LLSINGLETON(LLUrlRegistry); - ~LLUrlRegistry(); + LLSINGLETON(LLUrlRegistry); + ~LLUrlRegistry(); public: - /// add a new Url handler to the registry (will be freed on destruction) - /// optionally force it to the front of the list, making it take - /// priority over other regular expression matches for URLs - void registerUrl(LLUrlEntryBase *url, bool force_front = false); + /// add a new Url handler to the registry (will be freed on destruction) + /// optionally force it to the front of the list, making it take + /// priority over other regular expression matches for URLs + void registerUrl(LLUrlEntryBase *url, bool force_front = false); - /// get the next Url in an input string, starting at a given character offset - /// your callback is invoked if the matched Url's label changes in the future - bool findUrl(const std::string &text, LLUrlMatch &match, - const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, - bool is_content_trusted = false); + /// get the next Url in an input string, starting at a given character offset + /// your callback is invoked if the matched Url's label changes in the future + bool findUrl(const std::string &text, LLUrlMatch &match, + const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, + bool is_content_trusted = false); - /// a slightly less efficient version of findUrl for wide strings - bool findUrl(const LLWString &text, LLUrlMatch &match, - const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); + /// a slightly less efficient version of findUrl for wide strings + bool findUrl(const LLWString &text, LLUrlMatch &match, + const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); - // return true if the given string contains a URL that findUrl would match - bool hasUrl(const std::string &text); - bool hasUrl(const LLWString &text); + // return true if the given string contains a URL that findUrl would match + bool hasUrl(const std::string &text); + bool hasUrl(const LLWString &text); - // return true if the given string is a URL that findUrl would match - bool isUrl(const std::string &text); - bool isUrl(const LLWString &text); + // return true if the given string is a URL that findUrl would match + bool isUrl(const std::string &text); + bool isUrl(const LLWString &text); // Set handler for url registry to be capable of parsing and populating keybindings void setKeybindingHandler(LLKeyBindingToStringHandler* handler); private: - std::vector<LLUrlEntryBase *> mUrlEntry; - LLUrlEntryBase* mUrlEntryTrusted; - LLUrlEntryBase* mUrlEntryIcon; - LLUrlEntryBase* mLLUrlEntryInvalidSLURL; - LLUrlEntryBase* mUrlEntryHTTPLabel; - LLUrlEntryBase* mUrlEntrySLLabel; - LLUrlEntryBase* mUrlEntryNoLink; + std::vector<LLUrlEntryBase *> mUrlEntry; + LLUrlEntryBase* mUrlEntryTrusted; + LLUrlEntryBase* mUrlEntryIcon; + LLUrlEntryBase* mLLUrlEntryInvalidSLURL; + LLUrlEntryBase* mUrlEntryHTTPLabel; + LLUrlEntryBase* mUrlEntrySLLabel; + LLUrlEntryBase* mUrlEntryNoLink; LLUrlEntryBase* mUrlEntryKeybinding; }; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 5768ceacd3..877585cbef 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llview.cpp * @author James Cook * @brief Container for other views, anything that draws. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,27 +57,27 @@ static const S32 LINE_HEIGHT = 15; -S32 LLView::sDepth = 0; -bool LLView::sDebugRects = false; -bool LLView::sDebugUnicode = false; -bool LLView::sDebugCamera = false; -bool LLView::sIsRectDirty = false; -LLRect LLView::sDirtyRect; -bool LLView::sDebugRectsShowNames = true; -bool LLView::sDebugKeys = false; -bool LLView::sDebugMouseHandling = false; +S32 LLView::sDepth = 0; +bool LLView::sDebugRects = false; +bool LLView::sDebugUnicode = false; +bool LLView::sDebugCamera = false; +bool LLView::sIsRectDirty = false; +LLRect LLView::sDirtyRect; +bool LLView::sDebugRectsShowNames = true; +bool LLView::sDebugKeys = false; +bool LLView::sDebugMouseHandling = false; std::string LLView::sMouseHandlerMessage; -BOOL LLView::sForceReshape = FALSE; +BOOL LLView::sForceReshape = FALSE; std::set<LLView*> LLView::sPreviewHighlightedElements; BOOL LLView::sHighlightingDiffs = FALSE; LLView* LLView::sPreviewClickedElement = NULL; -BOOL LLView::sDrawPreviewHighlights = FALSE; -S32 LLView::sLastLeftXML = S32_MIN; -S32 LLView::sLastBottomXML = S32_MIN; +BOOL LLView::sDrawPreviewHighlights = FALSE; +S32 LLView::sLastLeftXML = S32_MIN; +S32 LLView::sLastBottomXML = S32_MIN; std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack; LLView::DrilldownFunc LLView::sDrilldown = - boost::bind(&LLView::pointInView, _1, _2, _3, HIT_TEST_USE_BOUNDING_RECT); + boost::bind(&LLView::pointInView, _1, _2, _3, HIT_TEST_USE_BOUNDING_RECT); //#if LL_DEBUG BOOL LLView::sIsDrawing = FALSE; @@ -85,233 +85,233 @@ BOOL LLView::sIsDrawing = FALSE; // Compiler optimization, generate extern template template class LLView* LLView::getChild<class LLView>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; static LLDefaultChildRegistry::Register<LLView> r("view"); void deleteView(LLView *aView) { - delete aView; + delete aView; } namespace LLInitParam { - void TypeValues<LLView::EOrientation>::declareValues() - { - declare("horizontal", LLView::HORIZONTAL); - declare("vertical", LLView::VERTICAL); - } + void TypeValues<LLView::EOrientation>::declareValues() + { + declare("horizontal", LLView::HORIZONTAL); + declare("vertical", LLView::VERTICAL); + } } LLView::Follows::Follows() : string(""), - flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP) + flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP) {} LLView::Params::Params() -: name("name", std::string("unnamed")), - enabled("enabled", true), - visible("visible", true), - mouse_opaque("mouse_opaque", true), - follows("follows"), - hover_cursor("hover_cursor", "UI_CURSOR_ARROW"), - use_bounding_rect("use_bounding_rect", false), - tab_group("tab_group", 0), - default_tab_group("default_tab_group"), - tool_tip("tool_tip"), - sound_flags("sound_flags", MOUSE_UP), - layout("layout"), - rect("rect"), - bottom_delta("bottom_delta", S32_MAX), - top_pad("top_pad"), - top_delta("top_delta", S32_MAX), - left_pad("left_pad"), - left_delta("left_delta", S32_MAX), - from_xui("from_xui", false), - focus_root("focus_root", false), - needs_translate("translate"), - xmlns("xmlns"), - xmlns_xsi("xmlns:xsi"), - xsi_schemaLocation("xsi:schemaLocation"), - xsi_type("xsi:type") - -{ - addSynonym(rect, ""); +: name("name", std::string("unnamed")), + enabled("enabled", true), + visible("visible", true), + mouse_opaque("mouse_opaque", true), + follows("follows"), + hover_cursor("hover_cursor", "UI_CURSOR_ARROW"), + use_bounding_rect("use_bounding_rect", false), + tab_group("tab_group", 0), + default_tab_group("default_tab_group"), + tool_tip("tool_tip"), + sound_flags("sound_flags", MOUSE_UP), + layout("layout"), + rect("rect"), + bottom_delta("bottom_delta", S32_MAX), + top_pad("top_pad"), + top_delta("top_delta", S32_MAX), + left_pad("left_pad"), + left_delta("left_delta", S32_MAX), + from_xui("from_xui", false), + focus_root("focus_root", false), + needs_translate("translate"), + xmlns("xmlns"), + xmlns_xsi("xmlns:xsi"), + xsi_schemaLocation("xsi:schemaLocation"), + xsi_type("xsi:type") + +{ + addSynonym(rect, ""); } LLView::LLView(const LLView::Params& p) -: mVisible(p.visible), - mInDraw(false), - mName(p.name), - mParentView(NULL), - mReshapeFlags(FOLLOWS_NONE), - mFromXUI(p.from_xui), - mIsFocusRoot(p.focus_root), - mLastVisible(FALSE), - mHoverCursor(getCursorFromString(p.hover_cursor)), - mEnabled(p.enabled), - mMouseOpaque(p.mouse_opaque), - mSoundFlags(p.sound_flags), - mUseBoundingRect(p.use_bounding_rect), - mDefaultTabGroup(p.default_tab_group), - mLastTabGroup(0), - mToolTipMsg((LLStringExplicit)p.tool_tip()), - mDefaultWidgets(NULL) -{ - // create rect first, as this will supply initial follows flags - setShape(p.rect); - parseFollowsFlags(p); +: mVisible(p.visible), + mInDraw(false), + mName(p.name), + mParentView(NULL), + mReshapeFlags(FOLLOWS_NONE), + mFromXUI(p.from_xui), + mIsFocusRoot(p.focus_root), + mLastVisible(FALSE), + mHoverCursor(getCursorFromString(p.hover_cursor)), + mEnabled(p.enabled), + mMouseOpaque(p.mouse_opaque), + mSoundFlags(p.sound_flags), + mUseBoundingRect(p.use_bounding_rect), + mDefaultTabGroup(p.default_tab_group), + mLastTabGroup(0), + mToolTipMsg((LLStringExplicit)p.tool_tip()), + mDefaultWidgets(NULL) +{ + // create rect first, as this will supply initial follows flags + setShape(p.rect); + parseFollowsFlags(p); } LLView::~LLView() { - dirtyRect(); - //LL_INFOS() << "Deleting view " << mName << ":" << (void*) this << LL_ENDL; - if (LLView::sIsDrawing) - { - LL_DEBUGS() << "Deleting view " << mName << " during UI draw() phase" << LL_ENDL; - } -// llassert(LLView::sIsDrawing == FALSE); - -// llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators - - if( hasMouseCapture() ) - { - //LL_WARNS() << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << LL_ENDL; - gFocusMgr.removeMouseCaptureWithoutCallback( this ); - } - - deleteAllChildren(); - - if (mParentView != NULL) - { - mParentView->removeChild(this); - } - - if (mDefaultWidgets) - { - delete mDefaultWidgets; - mDefaultWidgets = NULL; - } + dirtyRect(); + //LL_INFOS() << "Deleting view " << mName << ":" << (void*) this << LL_ENDL; + if (LLView::sIsDrawing) + { + LL_DEBUGS() << "Deleting view " << mName << " during UI draw() phase" << LL_ENDL; + } +// llassert(LLView::sIsDrawing == FALSE); + +// llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators + + if( hasMouseCapture() ) + { + //LL_WARNS() << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << LL_ENDL; + gFocusMgr.removeMouseCaptureWithoutCallback( this ); + } + + deleteAllChildren(); + + if (mParentView != NULL) + { + mParentView->removeChild(this); + } + + if (mDefaultWidgets) + { + delete mDefaultWidgets; + mDefaultWidgets = NULL; + } } // virtual BOOL LLView::isCtrl() const { - return FALSE; + return FALSE; } // virtual BOOL LLView::isPanel() const { - return FALSE; + return FALSE; } void LLView::setToolTip(const LLStringExplicit& msg) { - mToolTipMsg = msg; + mToolTipMsg = msg; } BOOL LLView::setToolTipArg(const LLStringExplicit& key, const LLStringExplicit& text) { - mToolTipMsg.setArg(key, text); - return TRUE; + mToolTipMsg.setArg(key, text); + return TRUE; } void LLView::setToolTipArgs( const LLStringUtil::format_map_t& args ) { - mToolTipMsg.setArgList(args); + mToolTipMsg.setArgList(args); } // virtual void LLView::setRect(const LLRect& rect) { - mRect = rect; - updateBoundingRect(); + mRect = rect; + updateBoundingRect(); } -void LLView::setUseBoundingRect( BOOL use_bounding_rect ) +void LLView::setUseBoundingRect( BOOL use_bounding_rect ) { - if (mUseBoundingRect != use_bounding_rect) - { - mUseBoundingRect = use_bounding_rect; - updateBoundingRect(); - } + if (mUseBoundingRect != use_bounding_rect) + { + mUseBoundingRect = use_bounding_rect; + updateBoundingRect(); + } } BOOL LLView::getUseBoundingRect() const { - return mUseBoundingRect; + return mUseBoundingRect; } // virtual const std::string& LLView::getName() const { - static std::string no_name("(no name)"); + static std::string no_name("(no name)"); - return mName.empty() ? no_name : mName; + return mName.empty() ? no_name : mName; } void LLView::sendChildToFront(LLView* child) { -// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs - if (child && child->getParent() == this) - { - // minor optimization, but more importantly, - // won't temporarily create an empty list - if (child != mChildList.front()) - { - mChildList.remove( child ); - mChildList.push_front(child); - } - } +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs + if (child && child->getParent() == this) + { + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.front()) + { + mChildList.remove( child ); + mChildList.push_front(child); + } + } } void LLView::sendChildToBack(LLView* child) { -// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs - if (child && child->getParent() == this) - { - // minor optimization, but more importantly, - // won't temporarily create an empty list - if (child != mChildList.back()) - { - mChildList.remove( child ); - mChildList.push_back(child); - } - } +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs + if (child && child->getParent() == this) + { + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.back()) + { + mChildList.remove( child ); + mChildList.push_back(child); + } + } } // virtual bool LLView::addChild(LLView* child, S32 tab_group) { - if (!child) - { - return false; - } + if (!child) + { + return false; + } - if (this == child) - { - LL_ERRS() << "Adding view " << child->getName() << " as child of itself" << LL_ENDL; - } + if (this == child) + { + LL_ERRS() << "Adding view " << child->getName() << " as child of itself" << LL_ENDL; + } - // remove from current parent - if (child->mParentView) - { - child->mParentView->removeChild(child); - } + // remove from current parent + if (child->mParentView) + { + child->mParentView->removeChild(child); + } - // add to front of child list, as normal - mChildList.push_front(child); + // add to front of child list, as normal + mChildList.push_front(child); - // add to tab order list - if (tab_group != 0) - { - mTabOrder.insert(tab_order_pair_t(child, tab_group)); - } + // add to tab order list + if (tab_group != 0) + { + mTabOrder.insert(tab_order_pair_t(child, tab_group)); + } - child->mParentView = this; + child->mParentView = this; if (getVisible() && child->getVisible()) { // if child isn't visible it won't affect bounding rect @@ -319,119 +319,119 @@ bool LLView::addChild(LLView* child, S32 tab_group) // on visibility change updateBoundingRect(); } - mLastTabGroup = tab_group; - return true; + mLastTabGroup = tab_group; + return true; } bool LLView::addChildInBack(LLView* child, S32 tab_group) { - if(addChild(child, tab_group)) - { - sendChildToBack(child); - return true; - } + if(addChild(child, tab_group)) + { + sendChildToBack(child); + return true; + } - return false; + return false; } // remove the specified child from the view, and set it's parent to NULL. void LLView::removeChild(LLView* child) { - //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs - if (child->mParentView == this) - { - // if we are removing an item we are currently iterating over, that would be bad - llassert(child->mInDraw == false); - mChildList.remove( child ); - child->mParentView = NULL; - child_tab_order_t::iterator found = mTabOrder.find(child); - if(found != mTabOrder.end()) - { - mTabOrder.erase(found); - } - } - else - { - LL_WARNS() << "\"" << child->getName() << "\" is not a child of " << getName() << LL_ENDL; - } - updateBoundingRect(); + //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs + if (child->mParentView == this) + { + // if we are removing an item we are currently iterating over, that would be bad + llassert(child->mInDraw == false); + mChildList.remove( child ); + child->mParentView = NULL; + child_tab_order_t::iterator found = mTabOrder.find(child); + if(found != mTabOrder.end()) + { + mTabOrder.erase(found); + } + } + else + { + LL_WARNS() << "\"" << child->getName() << "\" is not a child of " << getName() << LL_ENDL; + } + updateBoundingRect(); } BOOL LLView::isInVisibleChain() const { - BOOL visible = TRUE; + BOOL visible = TRUE; + + const LLView* viewp = this; + while(viewp) + { + if (!viewp->getVisible()) + { + visible = FALSE; + break; + } + viewp = viewp->getParent(); + } - const LLView* viewp = this; - while(viewp) - { - if (!viewp->getVisible()) - { - visible = FALSE; - break; - } - viewp = viewp->getParent(); - } - - return visible; + return visible; } BOOL LLView::isInEnabledChain() const { - BOOL enabled = TRUE; + BOOL enabled = TRUE; - const LLView* viewp = this; - while(viewp) - { - if (!viewp->getEnabled()) - { - enabled = FALSE; - break; - } - viewp = viewp->getParent(); - } - - return enabled; + const LLView* viewp = this; + while(viewp) + { + if (!viewp->getEnabled()) + { + enabled = FALSE; + break; + } + viewp = viewp->getParent(); + } + + return enabled; } static void buildPathname(std::ostream& out, const LLView* view) { - if (! (view && view->getParent())) - { - return; // Don't include root in the path. - } - - buildPathname(out, view->getParent()); - - // Build pathname into ostream on the way back from recursion. - out << '/'; - - // substitute all '/' in name with appropriate code - std::string name = view->getName(); - std::size_t found = name.find('/'); - std::size_t start = 0; - while (found != std::string::npos) - { - std::size_t sub_len = found - start; - if (sub_len > 0) - { - out << name.substr(start, sub_len); - } - out << "%2F"; - start = found + 1; - found = name.find('/', start); - } - if (start < name.size()) - { - out << name.substr(start, name.size() - start); - } + if (! (view && view->getParent())) + { + return; // Don't include root in the path. + } + + buildPathname(out, view->getParent()); + + // Build pathname into ostream on the way back from recursion. + out << '/'; + + // substitute all '/' in name with appropriate code + std::string name = view->getName(); + std::size_t found = name.find('/'); + std::size_t start = 0; + while (found != std::string::npos) + { + std::size_t sub_len = found - start; + if (sub_len > 0) + { + out << name.substr(start, sub_len); + } + out << "%2F"; + start = found + 1; + found = name.find('/', start); + } + if (start < name.size()) + { + out << name.substr(start, name.size() - start); + } } std::string LLView::getPathname() const { - std::ostringstream out; - buildPathname(out, this); - return out.str(); + std::ostringstream out; + buildPathname(out, this); + return out.str(); } //static @@ -447,13 +447,13 @@ std::string LLView::getPathname(const LLView* view) // virtual BOOL LLView::canFocusChildren() const { - return TRUE; + return TRUE; } //virtual void LLView::setEnabled(BOOL enabled) { - mEnabled = enabled; + mEnabled = enabled; } //virtual @@ -471,106 +471,106 @@ bool LLView::isAvailable(const LLView* view) //virtual BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text ) { - return FALSE; + return FALSE; } //virtual LLRect LLView::getSnapRect() const { - return mRect; + return mRect; } //virtual LLRect LLView::getRequiredRect() { - return mRect; + return mRect; } BOOL LLView::focusNextRoot() { - LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); - return LLView::focusNext(result); + LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); + return LLView::focusNext(result); } BOOL LLView::focusPrevRoot() { - LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); - return LLView::focusPrev(result); + LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); + return LLView::focusPrev(result); } // static BOOL LLView::focusNext(LLView::child_list_t & result) { - LLView::child_list_reverse_iter_t focused = result.rend(); - for(LLView::child_list_reverse_iter_t iter = result.rbegin(); - iter != result.rend(); - ++iter) - { - if(gFocusMgr.childHasKeyboardFocus(*iter)) - { - focused = iter; - break; - } - } - LLView::child_list_reverse_iter_t next = focused; - next = (next == result.rend()) ? result.rbegin() : ++next; - while(next != focused) - { - // wrap around to beginning if necessary - if(next == result.rend()) - { - next = result.rbegin(); - } - if ((*next)->isCtrl() && ((LLUICtrl*)*next)->hasTabStop()) - { - LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next); - ctrl->setFocus(TRUE); - ctrl->onTabInto(); - gFocusMgr.triggerFocusFlash(); - return TRUE; - } - ++next; - } - return FALSE; + LLView::child_list_reverse_iter_t focused = result.rend(); + for(LLView::child_list_reverse_iter_t iter = result.rbegin(); + iter != result.rend(); + ++iter) + { + if(gFocusMgr.childHasKeyboardFocus(*iter)) + { + focused = iter; + break; + } + } + LLView::child_list_reverse_iter_t next = focused; + next = (next == result.rend()) ? result.rbegin() : ++next; + while(next != focused) + { + // wrap around to beginning if necessary + if(next == result.rend()) + { + next = result.rbegin(); + } + if ((*next)->isCtrl() && ((LLUICtrl*)*next)->hasTabStop()) + { + LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next); + ctrl->setFocus(TRUE); + ctrl->onTabInto(); + gFocusMgr.triggerFocusFlash(); + return TRUE; + } + ++next; + } + return FALSE; } // static BOOL LLView::focusPrev(LLView::child_list_t & result) { - LLView::child_list_iter_t focused = result.end(); - for(LLView::child_list_iter_t iter = result.begin(); - iter != result.end(); - ++iter) - { - if(gFocusMgr.childHasKeyboardFocus(*iter)) - { - focused = iter; - break; - } - } - LLView::child_list_iter_t next = focused; - next = (next == result.end()) ? result.begin() : ++next; - while(next != focused) - { - // wrap around to beginning if necessary - if(next == result.end()) - { - next = result.begin(); - } - if((*next)->isCtrl()) - { - LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next); - if (!ctrl->hasFocus()) - { - ctrl->setFocus(TRUE); - ctrl->onTabInto(); - gFocusMgr.triggerFocusFlash(); - } - return TRUE; - } - ++next; - } - return FALSE; + LLView::child_list_iter_t focused = result.end(); + for(LLView::child_list_iter_t iter = result.begin(); + iter != result.end(); + ++iter) + { + if(gFocusMgr.childHasKeyboardFocus(*iter)) + { + focused = iter; + break; + } + } + LLView::child_list_iter_t next = focused; + next = (next == result.end()) ? result.begin() : ++next; + while(next != focused) + { + // wrap around to beginning if necessary + if(next == result.end()) + { + next = result.begin(); + } + if((*next)->isCtrl()) + { + LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next); + if (!ctrl->hasFocus()) + { + ctrl->setFocus(TRUE); + ctrl->onTabInto(); + gFocusMgr.triggerFocusFlash(); + } + return TRUE; + } + ++next; + } + return FALSE; } // delete all children. Override this function if you need to @@ -578,82 +578,82 @@ BOOL LLView::focusPrev(LLView::child_list_t & result) // children, etc. void LLView::deleteAllChildren() { - // clear out the control ordering - mTabOrder.clear(); + // clear out the control ordering + mTabOrder.clear(); - while (!mChildList.empty()) - { + while (!mChildList.empty()) + { LLView* viewp = mChildList.front(); viewp->mParentView = NULL; delete viewp; mChildList.pop_front(); - } + } updateBoundingRect(); } void LLView::setAllChildrenEnabled(BOOL b) { - for (LLView* viewp : mChildList) - { - viewp->setEnabled(b); - } + for (LLView* viewp : mChildList) + { + viewp->setEnabled(b); + } } // virtual void LLView::setVisible(BOOL visible) { - if ( mVisible != visible ) - { - mVisible = visible; - - // notify children of visibility change if root, or part of visible hierarchy - if (!getParent() || getParent()->isInVisibleChain()) - { - // tell all children of this view that the visibility may have changed - dirtyRect(); - onVisibilityChange( visible ); - } - updateBoundingRect(); - } + if ( mVisible != visible ) + { + mVisible = visible; + + // notify children of visibility change if root, or part of visible hierarchy + if (!getParent() || getParent()->isInVisibleChain()) + { + // tell all children of this view that the visibility may have changed + dirtyRect(); + onVisibilityChange( visible ); + } + updateBoundingRect(); + } } // virtual void LLView::onVisibilityChange ( BOOL new_visibility ) { - BOOL old_visibility; - BOOL log_visibility_change = LLViewerEventRecorder::instance().getLoggingStatus(); - for (LLView* viewp : mChildList) - { - if (!viewp) - { - continue; - } - - // only views that are themselves visible will have their overall visibility affected by their ancestors - old_visibility=viewp->getVisible(); - - if(log_visibility_change) - { - if (old_visibility!=new_visibility) - { - LLViewerEventRecorder::instance().logVisibilityChange( viewp->getPathname(), viewp->getName(), new_visibility,"widget"); - } - } - - if (old_visibility) - { - viewp->onVisibilityChange ( new_visibility ); - } - - if(log_visibility_change) - { - // Consider changing returns to confirm success and know which widget grabbed it - // For now assume success and log at highest xui possible - // NOTE we log actual state - which may differ if it somehow failed to set visibility - LL_DEBUGS() << "LLView::handleVisibilityChange - now: " << getVisible() << " xui: " << viewp->getPathname() << " name: " << viewp->getName() << LL_ENDL; - - } - } + BOOL old_visibility; + BOOL log_visibility_change = LLViewerEventRecorder::instance().getLoggingStatus(); + for (LLView* viewp : mChildList) + { + if (!viewp) + { + continue; + } + + // only views that are themselves visible will have their overall visibility affected by their ancestors + old_visibility=viewp->getVisible(); + + if(log_visibility_change) + { + if (old_visibility!=new_visibility) + { + LLViewerEventRecorder::instance().logVisibilityChange( viewp->getPathname(), viewp->getName(), new_visibility,"widget"); + } + } + + if (old_visibility) + { + viewp->onVisibilityChange ( new_visibility ); + } + + if(log_visibility_change) + { + // Consider changing returns to confirm success and know which widget grabbed it + // For now assume success and log at highest xui possible + // NOTE we log actual state - which may differ if it somehow failed to set visibility + LL_DEBUGS() << "LLView::handleVisibilityChange - now: " << getVisible() << " xui: " << viewp->getPathname() << " name: " << viewp->getName() << LL_ENDL; + + } + } } // virtual @@ -669,14 +669,14 @@ void LLView::onUpdateScrollToChild(const LLUICtrl * cntrl) // virtual void LLView::translate(S32 x, S32 y) { - mRect.translate(x, y); - updateBoundingRect(); + mRect.translate(x, y); + updateBoundingRect(); } // virtual BOOL LLView::canSnapTo(const LLView* other_view) { - return other_view != this && other_view->getVisible(); + return other_view != this && other_view->getVisible(); } // virtual @@ -686,58 +686,58 @@ void LLView::setSnappedTo(const LLView* snap_view) BOOL LLView::handleHover(S32 x, S32 y, MASK mask) { - return childrenHandleHover( x, y, mask ) != NULL; + return childrenHandleHover( x, y, mask ) != NULL; } void LLView::onMouseEnter(S32 x, S32 y, MASK mask) { - //LL_INFOS() << "Mouse entered " << getName() << LL_ENDL; + //LL_INFOS() << "Mouse entered " << getName() << LL_ENDL; } void LLView::onMouseLeave(S32 x, S32 y, MASK mask) { - //LL_INFOS() << "Mouse left " << getName() << LL_ENDL; + //LL_INFOS() << "Mouse left " << getName() << LL_ENDL; } bool LLView::visibleAndContains(S32 local_x, S32 local_y) { - return sDrilldown(this, local_x, local_y) - && getVisible(); + return sDrilldown(this, local_x, local_y) + && getVisible(); } bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y) { - return visibleAndContains(local_x, local_y) - && getEnabled(); + return visibleAndContains(local_x, local_y) + && getEnabled(); } // This is NOT event recording related void LLView::logMouseEvent() { - if (sDebugMouseHandling) - { - sMouseHandlerMessage = std::string("/") + mName + sMouseHandlerMessage; - } + if (sDebugMouseHandling) + { + sMouseHandlerMessage = std::string("/") + mName + sMouseHandlerMessage; + } } template <typename METHOD, typename CHARTYPE> LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& method, - CHARTYPE c, MASK mask) -{ - if ( getVisible() && getEnabled() ) - { - for (LLView* viewp : mChildList) - { - if ((viewp->*method)(c, mask, TRUE)) - { - if (LLView::sDebugKeys) - { - LL_INFOS() << desc << " handled by " << viewp->getName() << LL_ENDL; - } - return viewp; - } - } - } + CHARTYPE c, MASK mask) +{ + if ( getVisible() && getEnabled() ) + { + for (LLView* viewp : mChildList) + { + if ((viewp->*method)(c, mask, TRUE)) + { + if (LLView::sDebugKeys) + { + LL_INFOS() << desc << " handled by " << viewp->getName() << LL_ENDL; + } + return viewp; + } + } + } return NULL; } @@ -745,146 +745,146 @@ LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& m template <typename METHOD, typename XDATA> LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block) { - for (LLView* viewp : mChildList) - { - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; + for (LLView* viewp : mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; - if (!viewp->visibleEnabledAndContains(local_x, local_y)) - { - continue; - } + if (!viewp->visibleEnabledAndContains(local_x, local_y)) + { + continue; + } - if ((viewp->*method)( local_x, local_y, extra ) - || (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y ))) - { - LL_DEBUGS() << "LLView::childrenHandleMouseEvent calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << LL_ENDL; - LL_DEBUGS() << "LLView::childrenHandleMouseEvent getPathname for viewp result: " << viewp->getPathname() << "for this view: " << getPathname() << LL_ENDL; + if ((viewp->*method)( local_x, local_y, extra ) + || (allow_mouse_block && viewp->blockMouseEvent( local_x, local_y ))) + { + LL_DEBUGS() << "LLView::childrenHandleMouseEvent calling updatemouseeventinfo - local_x|global x "<< local_x << " " << x << "local/global y " << local_y << " " << y << LL_ENDL; + LL_DEBUGS() << "LLView::childrenHandleMouseEvent getPathname for viewp result: " << viewp->getPathname() << "for this view: " << getPathname() << LL_ENDL; - LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); - // This is NOT event recording related - viewp->logMouseEvent(); + // This is NOT event recording related + viewp->logMouseEvent(); - return viewp; - } - } - return NULL; + return viewp; + } + } + return NULL; } LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask) { - for (LLView* viewp : mChildList) - { - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - // Differs from childrenHandleMouseEvent() in that we want to offer - // tooltips even for disabled widgets. - if(!viewp->visibleAndContains(local_x, local_y)) - { - continue; - } - - if (viewp->handleToolTip(local_x, local_y, mask) - || viewp->blockMouseEvent(local_x, local_y)) - { - // This is NOT event recording related - viewp->logMouseEvent(); - return viewp; - } - } - return NULL; + for (LLView* viewp : mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + // Differs from childrenHandleMouseEvent() in that we want to offer + // tooltips even for disabled widgets. + if(!viewp->visibleAndContains(local_x, local_y)) + { + continue; + } + + if (viewp->handleToolTip(local_x, local_y, mask) + || viewp->blockMouseEvent(local_x, local_y)) + { + // This is NOT event recording related + viewp->logMouseEvent(); + return viewp; + } + } + return NULL; } LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - // default to not accepting drag and drop, will be overridden by handler - *accept = ACCEPT_NO; - - for (LLView* viewp : mChildList) - { - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if( !viewp->visibleEnabledAndContains(local_x, local_y)) - { - continue; - } - - // Differs from childrenHandleMouseEvent() simply in that this virtual - // method call diverges pretty radically from the usual (x, y, int). - if (viewp->handleDragAndDrop(local_x, local_y, mask, drop, - cargo_type, - cargo_data, - accept, - tooltip_msg) - || viewp->blockMouseEvent(local_x, local_y)) - { - return viewp; - } - } - return NULL; + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // default to not accepting drag and drop, will be overridden by handler + *accept = ACCEPT_NO; + + for (LLView* viewp : mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if( !viewp->visibleEnabledAndContains(local_x, local_y)) + { + continue; + } + + // Differs from childrenHandleMouseEvent() simply in that this virtual + // method call diverges pretty radically from the usual (x, y, int). + if (viewp->handleDragAndDrop(local_x, local_y, mask, drop, + cargo_type, + cargo_data, + accept, + tooltip_msg) + || viewp->blockMouseEvent(local_x, local_y)) + { + return viewp; + } + } + return NULL; } LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) { - for (LLView* viewp : mChildList) - { - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if(!viewp->visibleEnabledAndContains(local_x, local_y)) - { - continue; - } - - // This call differentiates this method from childrenHandleMouseEvent(). - LLUI::getInstance()->mWindow->setCursor(viewp->getHoverCursor()); - - if (viewp->handleHover(local_x, local_y, mask) - || viewp->blockMouseEvent(local_x, local_y)) - { - // This is NOT event recording related - viewp->logMouseEvent(); - return viewp; - } - } - return NULL; -} - -LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) -{ - if (!getVisible()) - return NULL; - - for (LLView* viewp : mChildList) - { - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if (!viewp->visibleAndContains(local_x, local_y)) - { - continue; - } - // Here we've found the first (frontmost) visible child at this level - // containing the specified point. Is the caller asking us to drill - // down and return the innermost leaf child at this point, or just the - // top-level child? - if (recur) - { - LLView* leaf(viewp->childFromPoint(local_x, local_y, recur)); - // Maybe viewp is already a leaf LLView, or maybe it has children - // but this particular (x, y) point falls between them. If the - // recursive call returns non-NULL, great, use that; else just use - // viewp. - return leaf? leaf : viewp; - } - return viewp; - - } - return 0; + for (LLView* viewp : mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if(!viewp->visibleEnabledAndContains(local_x, local_y)) + { + continue; + } + + // This call differentiates this method from childrenHandleMouseEvent(). + LLUI::getInstance()->mWindow->setCursor(viewp->getHoverCursor()); + + if (viewp->handleHover(local_x, local_y, mask) + || viewp->blockMouseEvent(local_x, local_y)) + { + // This is NOT event recording related + viewp->logMouseEvent(); + return viewp; + } + } + return NULL; +} + +LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) +{ + if (!getVisible()) + return NULL; + + for (LLView* viewp : mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (!viewp->visibleAndContains(local_x, local_y)) + { + continue; + } + // Here we've found the first (frontmost) visible child at this level + // containing the specified point. Is the caller asking us to drill + // down and return the innermost leaf child at this point, or just the + // top-level child? + if (recur) + { + LLView* leaf(viewp->childFromPoint(local_x, local_y, recur)); + // Maybe viewp is already a leaf LLView, or maybe it has children + // but this particular (x, y) point falls between them. If the + // recursive call returns non-NULL, great, use that; else just use + // viewp. + return leaf? leaf : viewp; + } + return viewp; + + } + return 0; } F32 LLView::getTooltipTimeout() @@ -898,165 +898,193 @@ F32 LLView::getTooltipTimeout() : tooltip_delay); } +// virtual +const std::string LLView::getToolTip() const +{ + if (sDebugUnicode) + { + std::string text = getText(); + if (!text.empty()) + { + const std::string& name = getName(); + std::string tooltip = llformat("Name: \"%s\"", name.c_str()); + + if (const LLFontGL* font = getFont()) + { + tooltip += llformat("\nFont: %s (%s)", + font->getFontDesc().getName().c_str(), + font->getFontDesc().getSize().c_str() + ); + } + + tooltip += "\n\n" + utf8str_showBytesUTF8(text); + + return tooltip; + } + } + + return mToolTipMsg.getString(); +} + BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = FALSE; - // parents provide tooltips first, which are optionally - // overridden by children, in case child is mouse_opaque - std::string tooltip = getToolTip(); - if (!tooltip.empty()) - { + // parents provide tooltips first, which are optionally + // overridden by children, in case child is mouse_opaque + std::string tooltip = getToolTip(); + if (!tooltip.empty()) + { static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true); - // Even if we don't show tooltips, consume the event, nothing below should show tooltip - if (allow_ui_tooltips) - { - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip) - .sticky_rect(calcScreenRect()) - .delay_time(getTooltipTimeout())); - } - handled = TRUE; - } + // Even if we don't show tooltips, consume the event, nothing below should show tooltip + if (allow_ui_tooltips) + { + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(tooltip) + .sticky_rect(calcScreenRect()) + .delay_time(getTooltipTimeout())); + } + handled = TRUE; + } - // child tooltips will override our own - LLView* child_handler = childrenHandleToolTip(x, y, mask); - if (child_handler) - { - handled = TRUE; - } + // child tooltips will override our own + LLView* child_handler = childrenHandleToolTip(x, y, mask); + if (child_handler) + { + handled = TRUE; + } - return handled; + return handled; } BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - BOOL handled = FALSE; - - if (getVisible() && getEnabled()) - { - if( called_from_parent ) - { - // Downward traversal - handled = childrenHandleKey( key, mask ) != NULL; - } - - if (!handled) - { - // For event logging we don't care which widget handles it - // So we capture the key at the end of this function once we know if it was handled - handled = handleKeyHere( key, mask ); - if (handled) - { - LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL; - } - } - } - - if( !handled && !called_from_parent && mParentView) - { - // Upward traversal - handled = mParentView->handleKey( key, mask, FALSE ); - } - return handled; + BOOL handled = FALSE; + + if (getVisible() && getEnabled()) + { + if( called_from_parent ) + { + // Downward traversal + handled = childrenHandleKey( key, mask ) != NULL; + } + + if (!handled) + { + // For event logging we don't care which widget handles it + // So we capture the key at the end of this function once we know if it was handled + handled = handleKeyHere( key, mask ); + if (handled) + { + LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL; + } + } + } + + if( !handled && !called_from_parent && mParentView) + { + // Upward traversal + handled = mParentView->handleKey( key, mask, FALSE ); + } + return handled; } BOOL LLView::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) { - BOOL handled = FALSE; - - if (getVisible() && getEnabled()) - { - if (called_from_parent) - { - // Downward traversal - handled = childrenHandleKeyUp(key, mask) != NULL; - } - - if (!handled) - { - // For event logging we don't care which widget handles it - // So we capture the key at the end of this function once we know if it was handled - handled = handleKeyUpHere(key, mask); - if (handled) - { - LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL; - } - } - } - - if (!handled && !called_from_parent && mParentView) - { - // Upward traversal - handled = mParentView->handleKeyUp(key, mask, FALSE); - } - return handled; + BOOL handled = FALSE; + + if (getVisible() && getEnabled()) + { + if (called_from_parent) + { + // Downward traversal + handled = childrenHandleKeyUp(key, mask) != NULL; + } + + if (!handled) + { + // For event logging we don't care which widget handles it + // So we capture the key at the end of this function once we know if it was handled + handled = handleKeyUpHere(key, mask); + if (handled) + { + LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL; + } + } + } + + if (!handled && !called_from_parent && mParentView) + { + // Upward traversal + handled = mParentView->handleKeyUp(key, mask, FALSE); + } + return handled; } // Called from handleKey() // Handles key in this object. Checking parents and children happens in handleKey() BOOL LLView::handleKeyHere(KEY key, MASK mask) { - return FALSE; + return FALSE; } // Called from handleKey() // Handles key in this object. Checking parents and children happens in handleKey() BOOL LLView::handleKeyUpHere(KEY key, MASK mask) { - return FALSE; + return FALSE; } BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { - BOOL handled = FALSE; - - if (getVisible() && getEnabled()) - { - if( called_from_parent ) - { - // Downward traversal - handled = childrenHandleUnicodeChar( uni_char ) != NULL; - } - - if (!handled) - { - handled = handleUnicodeCharHere(uni_char); - if (handled && LLView::sDebugKeys) - { - LL_INFOS() << "Unicode key " << wchar_utf8_preview(uni_char) << " is handled by " << getName() << LL_ENDL; - } - } - } - - if (!handled && !called_from_parent && mParentView) - { - // Upward traversal - handled = mParentView->handleUnicodeChar(uni_char, FALSE); - } - - if (handled) - { - LLViewerEventRecorder::instance().logKeyUnicodeEvent(uni_char); - } - - return handled; + BOOL handled = FALSE; + + if (getVisible() && getEnabled()) + { + if( called_from_parent ) + { + // Downward traversal + handled = childrenHandleUnicodeChar( uni_char ) != NULL; + } + + if (!handled) + { + handled = handleUnicodeCharHere(uni_char); + if (handled && LLView::sDebugKeys) + { + LL_INFOS() << "Unicode key " << wchar_utf8_preview(uni_char) << " is handled by " << getName() << LL_ENDL; + } + } + } + + if (!handled && !called_from_parent && mParentView) + { + // Upward traversal + handled = mParentView->handleUnicodeChar(uni_char, FALSE); + } + + if (handled) + { + LLViewerEventRecorder::instance().logKeyUnicodeEvent(uni_char); + } + + return handled; } BOOL LLView::handleUnicodeCharHere(llwchar uni_char ) { - return FALSE; + return FALSE; } BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL; + return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL; } void LLView::onMouseCaptureLost() @@ -1064,189 +1092,189 @@ void LLView::onMouseCaptureLost() } BOOL LLView::hasMouseCapture() -{ - return gFocusMgr.getMouseCapture() == this; +{ + return gFocusMgr.getMouseCapture() == this; } BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask) { - LLView* r = childrenHandleMouseUp( x, y, mask ); + LLView* r = childrenHandleMouseUp( x, y, mask ); - return (r!=NULL); + return (r!=NULL); } BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask) { - LLView* r= childrenHandleMouseDown(x, y, mask ); + LLView* r= childrenHandleMouseDown(x, y, mask ); - return (r!=NULL); + return (r!=NULL); } BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask) { - return childrenHandleDoubleClick( x, y, mask ) != NULL; + return childrenHandleDoubleClick( x, y, mask ) != NULL; } BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks) { - return childrenHandleScrollWheel( x, y, clicks ) != NULL; + return childrenHandleScrollWheel( x, y, clicks ) != NULL; } BOOL LLView::handleScrollHWheel(S32 x, S32 y, S32 clicks) { - return childrenHandleScrollHWheel( x, y, clicks ) != NULL; + return childrenHandleScrollHWheel( x, y, clicks ) != NULL; } BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask) { - return childrenHandleRightMouseDown( x, y, mask ) != NULL; + return childrenHandleRightMouseDown( x, y, mask ) != NULL; } BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask) { - return childrenHandleRightMouseUp( x, y, mask ) != NULL; + return childrenHandleRightMouseUp( x, y, mask ) != NULL; } - + BOOL LLView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - return childrenHandleMiddleMouseDown( x, y, mask ) != NULL; + return childrenHandleMiddleMouseDown( x, y, mask ) != NULL; } BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { - return childrenHandleMiddleMouseUp( x, y, mask ) != NULL; + return childrenHandleMiddleMouseUp( x, y, mask ) != NULL; } LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks) { - return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false); + return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks, false); } LLView* LLView::childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks) { - return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false); + return childrenHandleMouseEvent(&LLView::handleScrollHWheel, x, y, clicks, false); } // Called during downward traversal LLView* LLView::childrenHandleKey(KEY key, MASK mask) { - return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask); + return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask); } // Called during downward traversal LLView* LLView::childrenHandleKeyUp(KEY key, MASK mask) { - return childrenHandleCharEvent("Key Up", &LLView::handleKeyUp, key, mask); + return childrenHandleCharEvent("Key Up", &LLView::handleKeyUp, key, mask); } // Called during downward traversal LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char) { - return childrenHandleCharEvent("Unicode character", &LLView::handleUnicodeCharWithDummyMask, - uni_char, MASK_NONE); + return childrenHandleCharEvent("Unicode character", &LLView::handleUnicodeCharWithDummyMask, + uni_char, MASK_NONE); } LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleMouseDown, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleMouseDown, x, y, mask); } LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleRightMouseDown, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleRightMouseDown, x, y, mask); } LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleMiddleMouseDown, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleMiddleMouseDown, x, y, mask); } LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleDoubleClick, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleDoubleClick, x, y, mask); } LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask); } LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleRightMouseUp, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleRightMouseUp, x, y, mask); } LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask) { - return childrenHandleMouseEvent(&LLView::handleMiddleMouseUp, x, y, mask); + return childrenHandleMouseEvent(&LLView::handleMiddleMouseUp, x, y, mask); } void LLView::draw() { - drawChildren(); + drawChildren(); } void LLView::drawChildren() { - if (!mChildList.empty()) - { - LLView* rootp = LLUI::getInstance()->getRootView(); - ++sDepth; - - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) - { - child_list_reverse_iter_t child = child_iter++; - LLView *viewp = *child; - - if (viewp == NULL) - { - continue; - } - - if (viewp->getVisible() && viewp->getRect().isValid()) - { - LLRect screen_rect = viewp->calcScreenRect(); - if ( rootp->getLocalRect().overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) - { - LLUI::pushMatrix(); - { - LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom); - // flag the fact we are in draw here, in case overridden draw() method attempts to remove this widget - viewp->mInDraw = true; - viewp->draw(); - viewp->mInDraw = false; - - if (sDebugRects) - { - viewp->drawDebugRect(); - - // Check for bogus rectangle - if (!getRect().isValid()) - { - LL_WARNS() << "Bogus rectangle for " << getName() << " with " << mRect << LL_ENDL; - } - } - } - LLUI::popMatrix(); - } - } - - } - --sDepth; - } + if (!mChildList.empty()) + { + LLView* rootp = LLUI::getInstance()->getRootView(); + ++sDepth; + + for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) + { + child_list_reverse_iter_t child = child_iter++; + LLView *viewp = *child; + + if (viewp == NULL) + { + continue; + } + + if (viewp->getVisible() && viewp->getRect().isValid()) + { + LLRect screen_rect = viewp->calcScreenRect(); + if ( rootp->getLocalRect().overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) + { + LLUI::pushMatrix(); + { + LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom); + // flag the fact we are in draw here, in case overridden draw() method attempts to remove this widget + viewp->mInDraw = true; + viewp->draw(); + viewp->mInDraw = false; + + if (sDebugRects) + { + viewp->drawDebugRect(); + + // Check for bogus rectangle + if (!getRect().isValid()) + { + LL_WARNS() << "Bogus rectangle for " << getName() << " with " << mRect << LL_ENDL; + } + } + } + LLUI::popMatrix(); + } + } + + } + --sDepth; + } } void LLView::dirtyRect() { - LLView* child = getParent(); - LLView* parent = child ? child->getParent() : NULL; - LLView* cur = this; - while (child && parent && parent->getParent()) - { //find third to top-most view - cur = child; - child = parent; - parent = parent->getParent(); - } + LLView* child = getParent(); + LLView* parent = child ? child->getParent() : NULL; + LLView* cur = this; + while (child && parent && parent->getParent()) + { //find third to top-most view + cur = child; + child = parent; + parent = parent->getParent(); + } if (!sIsRectDirty) { @@ -1262,343 +1290,343 @@ void LLView::dirtyRect() //Draw a box for debugging. void LLView::drawDebugRect() { - std::set<LLView*>::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element - - LLUI::pushMatrix(); - { - // drawing solids requires texturing be disabled - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (getUseBoundingRect()) - { - LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom); - } - - LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; - - // draw red rectangle for the border - LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f); - if(preview_iter != sPreviewHighlightedElements.end()) - { - if(LLView::sPreviewClickedElement && this == sPreviewClickedElement) - { - border_color = LLColor4::red; - } - else - { - static LLUIColor scroll_highlighted_color = LLUIColorTable::instance().getColor("ScrollHighlightedColor"); - border_color = scroll_highlighted_color; - } - } - else - { - border_color.mV[sDepth%3] = 1.f; - } - - gGL.color4fv( border_color.mV ); - - gGL.begin(LLRender::LINES); - gGL.vertex2i(0, debug_rect.getHeight() - 1); - gGL.vertex2i(0, 0); - - gGL.vertex2i(0, 0); - gGL.vertex2i(debug_rect.getWidth() - 1, 0); - - gGL.vertex2i(debug_rect.getWidth() - 1, 0); - gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1); - - gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1); - gGL.vertex2i(0, debug_rect.getHeight() - 1); - gGL.end(); - - // Draw the name if it's not a leaf node or not in editing or preview mode - if (mChildList.size() - && preview_iter == sPreviewHighlightedElements.end() - && sDebugRectsShowNames) - { - S32 x, y; - gGL.color4fv( border_color.mV ); - - x = debug_rect.getWidth() / 2; - - S32 rect_height = debug_rect.getHeight(); - S32 lines = rect_height / LINE_HEIGHT + 1; - - S32 depth = 0; - LLView * viewp = this; - while (NULL != viewp) - { - viewp = viewp->getParent(); - depth++; - } - - y = rect_height - LINE_HEIGHT * (depth % lines + 1); - - std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), - debug_rect.getWidth(), debug_rect.getHeight()); - LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, - LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); - } - } - LLUI::popMatrix(); + std::set<LLView*>::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element + + LLUI::pushMatrix(); + { + // drawing solids requires texturing be disabled + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + if (getUseBoundingRect()) + { + LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom); + } + + LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; + + // draw red rectangle for the border + LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f); + if(preview_iter != sPreviewHighlightedElements.end()) + { + if(LLView::sPreviewClickedElement && this == sPreviewClickedElement) + { + border_color = LLColor4::red; + } + else + { + static LLUIColor scroll_highlighted_color = LLUIColorTable::instance().getColor("ScrollHighlightedColor"); + border_color = scroll_highlighted_color; + } + } + else + { + border_color.mV[sDepth%3] = 1.f; + } + + gGL.color4fv( border_color.mV ); + + gGL.begin(LLRender::LINES); + gGL.vertex2i(0, debug_rect.getHeight() - 1); + gGL.vertex2i(0, 0); + + gGL.vertex2i(0, 0); + gGL.vertex2i(debug_rect.getWidth() - 1, 0); + + gGL.vertex2i(debug_rect.getWidth() - 1, 0); + gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1); + + gGL.vertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1); + gGL.vertex2i(0, debug_rect.getHeight() - 1); + gGL.end(); + + // Draw the name if it's not a leaf node or not in editing or preview mode + if (mChildList.size() + && preview_iter == sPreviewHighlightedElements.end() + && sDebugRectsShowNames) + { + S32 x, y; + gGL.color4fv( border_color.mV ); + + x = debug_rect.getWidth() / 2; + + S32 rect_height = debug_rect.getHeight(); + S32 lines = rect_height / LINE_HEIGHT + 1; + + S32 depth = 0; + LLView * viewp = this; + while (NULL != viewp) + { + viewp = viewp->getParent(); + depth++; + } + + y = rect_height - LINE_HEIGHT * (depth % lines + 1); + + std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), + debug_rect.getWidth(), debug_rect.getHeight()); + LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, + LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); + } + } + LLUI::popMatrix(); } void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw) { - if (childp && childp->getParent() == this) - { - ++sDepth; - - if ((childp->getVisible() && childp->getRect().isValid()) - || force_draw) - { - gGL.matrixMode(LLRender::MM_MODELVIEW); - LLUI::pushMatrix(); - { - LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset); - childp->draw(); - } - LLUI::popMatrix(); - } - - --sDepth; - } + if (childp && childp->getParent() == this) + { + ++sDepth; + + if ((childp->getVisible() && childp->getRect().isValid()) + || force_draw) + { + gGL.matrixMode(LLRender::MM_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset); + childp->draw(); + } + LLUI::popMatrix(); + } + + --sDepth; + } } void LLView::reshape(S32 width, S32 height, BOOL called_from_parent) { - // compute how much things changed and apply reshape logic to children - S32 delta_width = width - getRect().getWidth(); - S32 delta_height = height - getRect().getHeight(); - - if (delta_width || delta_height || sForceReshape) - { - // adjust our rectangle - mRect.mRight = getRect().mLeft + width; - mRect.mTop = getRect().mBottom + height; - - // move child views according to reshape flags - for (LLView* viewp : mChildList) - { - if (viewp != NULL) - { - LLRect child_rect( viewp->mRect ); - - if (viewp->followsRight() && viewp->followsLeft()) - { - child_rect.mRight += delta_width; - } - else if (viewp->followsRight()) - { - child_rect.mLeft += delta_width; - child_rect.mRight += delta_width; - } - else if (viewp->followsLeft()) - { - // left is 0, don't need to adjust coords - } - else - { - // BUG what to do when we don't follow anyone? - // for now, same as followsLeft - } - - if (viewp->followsTop() && viewp->followsBottom()) - { - child_rect.mTop += delta_height; - } - else if (viewp->followsTop()) - { - child_rect.mTop += delta_height; - child_rect.mBottom += delta_height; - } - else if (viewp->followsBottom()) - { - // bottom is 0, so don't need to adjust coords - } - else - { - // BUG what to do when we don't follow? - // for now, same as bottom - } - - S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft; - S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom; - viewp->translate( delta_x, delta_y ); - if (child_rect.getWidth() != viewp->getRect().getWidth() + // compute how much things changed and apply reshape logic to children + S32 delta_width = width - getRect().getWidth(); + S32 delta_height = height - getRect().getHeight(); + + if (delta_width || delta_height || sForceReshape) + { + // adjust our rectangle + mRect.mRight = getRect().mLeft + width; + mRect.mTop = getRect().mBottom + height; + + // move child views according to reshape flags + for (LLView* viewp : mChildList) + { + if (viewp != NULL) + { + LLRect child_rect( viewp->mRect ); + + if (viewp->followsRight() && viewp->followsLeft()) + { + child_rect.mRight += delta_width; + } + else if (viewp->followsRight()) + { + child_rect.mLeft += delta_width; + child_rect.mRight += delta_width; + } + else if (viewp->followsLeft()) + { + // left is 0, don't need to adjust coords + } + else + { + // BUG what to do when we don't follow anyone? + // for now, same as followsLeft + } + + if (viewp->followsTop() && viewp->followsBottom()) + { + child_rect.mTop += delta_height; + } + else if (viewp->followsTop()) + { + child_rect.mTop += delta_height; + child_rect.mBottom += delta_height; + } + else if (viewp->followsBottom()) + { + // bottom is 0, so don't need to adjust coords + } + else + { + // BUG what to do when we don't follow? + // for now, same as bottom + } + + S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft; + S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom; + viewp->translate( delta_x, delta_y ); + if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight() || sForceReshape) - { - viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); - } - } - } - } + { + viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); + } + } + } + } - if (!called_from_parent) - { - if (mParentView) - { - mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE); - } - } + if (!called_from_parent) + { + if (mParentView) + { + mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE); + } + } - updateBoundingRect(); + updateBoundingRect(); } LLRect LLView::calcBoundingRect() { - LLRect local_bounding_rect = LLRect::null; - - for (LLView* childp : mChildList) - { - // ignore invisible and "top" children when calculating bounding rect - // such as combobox popups - if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) - { - continue; - } - - LLRect child_bounding_rect = childp->getBoundingRect(); + LLRect local_bounding_rect = LLRect::null; - if (local_bounding_rect.isEmpty()) - { - // start out with bounding rect equal to first visible child's bounding rect - local_bounding_rect = child_bounding_rect; - } - else - { - // accumulate non-null children rectangles - if (!child_bounding_rect.isEmpty()) - { - local_bounding_rect.unionWith(child_bounding_rect); - } - } - } + for (LLView* childp : mChildList) + { + // ignore invisible and "top" children when calculating bounding rect + // such as combobox popups + if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) + { + continue; + } + + LLRect child_bounding_rect = childp->getBoundingRect(); + + if (local_bounding_rect.isEmpty()) + { + // start out with bounding rect equal to first visible child's bounding rect + local_bounding_rect = child_bounding_rect; + } + else + { + // accumulate non-null children rectangles + if (!child_bounding_rect.isEmpty()) + { + local_bounding_rect.unionWith(child_bounding_rect); + } + } + } - // convert to parent-relative coordinates - local_bounding_rect.translate(mRect.mLeft, mRect.mBottom); - return local_bounding_rect; + // convert to parent-relative coordinates + local_bounding_rect.translate(mRect.mLeft, mRect.mBottom); + return local_bounding_rect; } void LLView::updateBoundingRect() { - if (isDead()) return; + if (isDead()) return; - LLRect cur_rect = mBoundingRect; + LLRect cur_rect = mBoundingRect; - if (getUseBoundingRect()) - { - mBoundingRect = calcBoundingRect(); - } - else - { - mBoundingRect = mRect; - } + if (getUseBoundingRect()) + { + mBoundingRect = calcBoundingRect(); + } + else + { + mBoundingRect = mRect; + } - // give parent view a chance to resize, in case we just moved, for example - if (getParent() && getParent()->getUseBoundingRect()) - { - getParent()->updateBoundingRect(); - } + // give parent view a chance to resize, in case we just moved, for example + if (getParent() && getParent()->getUseBoundingRect()) + { + getParent()->updateBoundingRect(); + } - if (mBoundingRect != cur_rect) - { - dirtyRect(); - } + if (mBoundingRect != cur_rect) + { + dirtyRect(); + } } LLRect LLView::calcScreenRect() const { - LLRect screen_rect; - localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom); - localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop); - return screen_rect; + LLRect screen_rect; + localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom); + localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop); + return screen_rect; } LLRect LLView::calcScreenBoundingRect() const { - LLRect screen_rect; - // get bounding rect, if used - LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect; + LLRect screen_rect; + // get bounding rect, if used + LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect; - // convert to local coordinates, as defined by mRect - bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); + // convert to local coordinates, as defined by mRect + bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); - localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom); - localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop); - return screen_rect; + localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom); + localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop); + return screen_rect; } LLRect LLView::getLocalBoundingRect() const { - LLRect local_bounding_rect = getBoundingRect(); - local_bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); + LLRect local_bounding_rect = getBoundingRect(); + local_bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); - return local_bounding_rect; + return local_bounding_rect; } LLRect LLView::getLocalRect() const { - LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - return local_rect; + LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + return local_rect; } LLRect LLView::getLocalSnapRect() const { - LLRect local_snap_rect = getSnapRect(); - local_snap_rect.translate(-getRect().mLeft, -getRect().mBottom); - return local_snap_rect; + LLRect local_snap_rect = getSnapRect(); + local_snap_rect.translate(-getRect().mLeft, -getRect().mBottom); + return local_snap_rect; } BOOL LLView::hasAncestor(const LLView* parentp) const { - if (!parentp) - { - return FALSE; - } + if (!parentp) + { + return FALSE; + } - LLView* viewp = getParent(); - while(viewp) - { - if (viewp == parentp) - { - return TRUE; - } - viewp = viewp->getParent(); - } + LLView* viewp = getParent(); + while(viewp) + { + if (viewp == parentp) + { + return TRUE; + } + viewp = viewp->getParent(); + } - return FALSE; + return FALSE; } //----------------------------------------------------------------------------- BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const { - LLView *focus = dynamic_cast<LLView *>(gFocusMgr.getKeyboardFocus()); - - while (focus != NULL) - { - if (focus->getName() == childname) - { - return TRUE; - } - - focus = focus->getParent(); - } - - return FALSE; + LLView *focus = dynamic_cast<LLView *>(gFocusMgr.getKeyboardFocus()); + + while (focus != NULL) + { + if (focus->getName() == childname) + { + return TRUE; + } + + focus = focus->getParent(); + } + + return FALSE; } //----------------------------------------------------------------------------- BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const { - return findChildView(childname, recurse) != NULL; + return findChildView(childname, recurse) != NULL; } //----------------------------------------------------------------------------- @@ -1606,176 +1634,176 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const //----------------------------------------------------------------------------- LLView* LLView::getChildView(const std::string& name, BOOL recurse) const { - return getChild<LLView>(name, recurse); + return getChild<LLView>(name, recurse); } LLView* LLView::findChildView(const std::string& name, BOOL recurse) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - + // Look for direct children *first* - for (LLView* childp : mChildList) - { - llassert(childp); - if (childp->getName() == name) - { - return childp; - } - } - if (recurse) - { - // Look inside each child as well. - for (LLView* childp : mChildList) - { - llassert(childp); - LLView* viewp = childp->findChildView(name, recurse); - if ( viewp ) - { - return viewp; - } - } - } - return NULL; -} - -BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const -{ - return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) - ? mBoundingRect.pointInRect( x, y ) - : mRect.pointInRect( x, y ); -} - -BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const -{ - return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) - ? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom ) - : mRect.localPointInRect( x, y ); + for (LLView* childp : mChildList) + { + llassert(childp); + if (childp->getName() == name) + { + return childp; + } + } + if (recurse) + { + // Look inside each child as well. + for (LLView* childp : mChildList) + { + llassert(childp); + LLView* viewp = childp->findChildView(name, recurse); + if ( viewp ) + { + return viewp; + } + } + } + return NULL; +} + +BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const +{ + return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) + ? mBoundingRect.pointInRect( x, y ) + : mRect.pointInRect( x, y ); +} + +BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const +{ + return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) + ? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom ) + : mRect.localPointInRect( x, y ); } BOOL LLView::blockMouseEvent(S32 x, S32 y) const { - return mMouseOpaque && pointInView(x, y, HIT_TEST_IGNORE_BOUNDING_RECT); + return mMouseOpaque && pointInView(x, y, HIT_TEST_IGNORE_BOUNDING_RECT); } // virtual void LLView::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const { - *local_x = screen_x - getRect().mLeft; - *local_y = screen_y - getRect().mBottom; + *local_x = screen_x - getRect().mLeft; + *local_y = screen_y - getRect().mBottom; - const LLView* cur = this; - while( cur->mParentView ) - { - cur = cur->mParentView; - *local_x -= cur->getRect().mLeft; - *local_y -= cur->getRect().mBottom; - } + const LLView* cur = this; + while( cur->mParentView ) + { + cur = cur->mParentView; + *local_x -= cur->getRect().mLeft; + *local_y -= cur->getRect().mBottom; + } } void LLView::localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const { - *screen_x = local_x; - *screen_y = local_y; + *screen_x = local_x; + *screen_y = local_y; - const LLView* cur = this; - do - { - LLRect cur_rect = cur->getRect(); - *screen_x += cur_rect.mLeft; - *screen_y += cur_rect.mBottom; - cur = cur->mParentView; - } - while( cur ); + const LLView* cur = this; + do + { + LLRect cur_rect = cur->getRect(); + *screen_x += cur_rect.mLeft; + *screen_y += cur_rect.mBottom; + cur = cur->mParentView; + } + while( cur ); } void LLView::screenRectToLocal(const LLRect& screen, LLRect* local) const { - *local = screen; - local->translate( -getRect().mLeft, -getRect().mBottom ); + *local = screen; + local->translate( -getRect().mLeft, -getRect().mBottom ); - const LLView* cur = this; - while( cur->mParentView ) - { - cur = cur->mParentView; - local->translate( -cur->getRect().mLeft, -cur->getRect().mBottom ); - } + const LLView* cur = this; + while( cur->mParentView ) + { + cur = cur->mParentView; + local->translate( -cur->getRect().mLeft, -cur->getRect().mBottom ); + } } void LLView::localRectToScreen(const LLRect& local, LLRect* screen) const { - *screen = local; - screen->translate( getRect().mLeft, getRect().mBottom ); + *screen = local; + screen->translate( getRect().mLeft, getRect().mBottom ); - const LLView* cur = this; - while( cur->mParentView ) - { - cur = cur->mParentView; - screen->translate( cur->getRect().mLeft, cur->getRect().mBottom ); - } + const LLView* cur = this; + while( cur->mParentView ) + { + cur = cur->mParentView; + screen->translate( cur->getRect().mLeft, cur->getRect().mBottom ); + } } LLView* LLView::getRootView() { - LLView* view = this; - while( view->mParentView ) - { - view = view->mParentView; - } - return view; + LLView* view = this; + while( view->mParentView ) + { + view = view->mParentView; + } + return view; } LLView* LLView::findPrevSibling(LLView* child) { - child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child); - if (prev_it != mChildList.end() && prev_it != mChildList.begin()) - { - return *(--prev_it); - } - return NULL; + child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child); + if (prev_it != mChildList.end() && prev_it != mChildList.begin()) + { + return *(--prev_it); + } + return NULL; } LLView* LLView::findNextSibling(LLView* child) { - child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child); - if (next_it != mChildList.end()) - { - next_it++; - } + child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child); + if (next_it != mChildList.end()) + { + next_it++; + } - return (next_it != mChildList.end()) ? *next_it : NULL; + return (next_it != mChildList.end()) ? *next_it : NULL; } LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S32 min_overlap_pixels) { - LLCoordGL delta; + LLCoordGL delta; - const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth()); - const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight()); + const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth()); + const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight()); - if (KEEP_ONSCREEN_PIXELS_WIDTH <= constraint.getWidth() && - KEEP_ONSCREEN_PIXELS_HEIGHT <= constraint.getHeight()) - { - if (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft) - { - delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); - } - else if (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight) - { - delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); - } - - if (input.mTop > constraint.mTop) - { - delta.mY = constraint.mTop - input.mTop; - } - else if (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom) - { - delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT); - } - } + if (KEEP_ONSCREEN_PIXELS_WIDTH <= constraint.getWidth() && + KEEP_ONSCREEN_PIXELS_HEIGHT <= constraint.getHeight()) + { + if (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft) + { + delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); + } + else if (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight) + { + delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); + } + + if (input.mTop > constraint.mTop) + { + delta.mY = constraint.mTop - input.mTop; + } + else if (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom) + { + delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT); + } + } - return delta; + return delta; } // Moves the view so that it is entirely inside of constraint. @@ -1788,487 +1816,487 @@ BOOL LLView::translateIntoRect(const LLRect& constraint, S32 min_overlap_pixels) BOOL LLView::translateRectIntoRect(const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels) { - LLCoordGL translation = getNeededTranslation(rect, constraint, min_overlap_pixels); + LLCoordGL translation = getNeededTranslation(rect, constraint, min_overlap_pixels); - if (translation.mX != 0 || translation.mY != 0) - { - translate(translation.mX, translation.mY); - return TRUE; - } + if (translation.mX != 0 || translation.mY != 0) + { + translate(translation.mX, translation.mY); + return TRUE; + } - return FALSE; + return FALSE; } // move this view into "inside" but not onto "exclude" // NOTE: if this view is already contained in "inside", we ignore the "exclude" rect BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels) { - LLCoordGL translation = getNeededTranslation(getRect(), inside, min_overlap_pixels); - - if (translation.mX != 0 || translation.mY != 0) - { - // translate ourselves into constraint rect - translate(translation.mX, translation.mY); - - // do we overlap with exclusion area? - // keep moving in the same direction to the other side of the exclusion rect - if (exclude.overlaps(getRect())) - { - // moving right - if (translation.mX > 0) - { - translate(exclude.mRight - getRect().mLeft, 0); - } - // moving left - else if (translation.mX < 0) - { - translate(exclude.mLeft - getRect().mRight, 0); - } - - // moving up - if (translation.mY > 0) - { - translate(0, exclude.mTop - getRect().mBottom); - } - // moving down - else if (translation.mY < 0) - { - translate(0, exclude.mBottom - getRect().mTop); - } - } - - return TRUE; - } - return FALSE; + LLCoordGL translation = getNeededTranslation(getRect(), inside, min_overlap_pixels); + + if (translation.mX != 0 || translation.mY != 0) + { + // translate ourselves into constraint rect + translate(translation.mX, translation.mY); + + // do we overlap with exclusion area? + // keep moving in the same direction to the other side of the exclusion rect + if (exclude.overlaps(getRect())) + { + // moving right + if (translation.mX > 0) + { + translate(exclude.mRight - getRect().mLeft, 0); + } + // moving left + else if (translation.mX < 0) + { + translate(exclude.mLeft - getRect().mRight, 0); + } + + // moving up + if (translation.mY > 0) + { + translate(0, exclude.mTop - getRect().mBottom); + } + // moving down + else if (translation.mY < 0) + { + translate(0, exclude.mBottom - getRect().mTop); + } + } + + return TRUE; + } + return FALSE; } void LLView::centerWithin(const LLRect& bounds) { - S32 left = bounds.mLeft + (bounds.getWidth() - getRect().getWidth()) / 2; - S32 bottom = bounds.mBottom + (bounds.getHeight() - getRect().getHeight()) / 2; + S32 left = bounds.mLeft + (bounds.getWidth() - getRect().getWidth()) / 2; + S32 bottom = bounds.mBottom + (bounds.getHeight() - getRect().getHeight()) / 2; - translate( left - getRect().mLeft, bottom - getRect().mBottom ); + translate( left - getRect().mLeft, bottom - getRect().mBottom ); } BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const { - const LLView* cur_view = this; - const LLView* root_view = NULL; - - while (cur_view) - { - if (cur_view == other_view) - { - *other_x = x; - *other_y = y; - return TRUE; - } + const LLView* cur_view = this; + const LLView* root_view = NULL; - x += cur_view->getRect().mLeft; - y += cur_view->getRect().mBottom; - - cur_view = cur_view->getParent(); - root_view = cur_view; - } + while (cur_view) + { + if (cur_view == other_view) + { + *other_x = x; + *other_y = y; + return TRUE; + } + + x += cur_view->getRect().mLeft; + y += cur_view->getRect().mBottom; + + cur_view = cur_view->getParent(); + root_view = cur_view; + } - // assuming common root between two views, chase other_view's parents up to root - cur_view = other_view; - while (cur_view) - { - x -= cur_view->getRect().mLeft; - y -= cur_view->getRect().mBottom; + // assuming common root between two views, chase other_view's parents up to root + cur_view = other_view; + while (cur_view) + { + x -= cur_view->getRect().mLeft; + y -= cur_view->getRect().mBottom; - cur_view = cur_view->getParent(); + cur_view = cur_view->getParent(); - if (cur_view == root_view) - { - *other_x = x; - *other_y = y; - return TRUE; - } - } + if (cur_view == root_view) + { + *other_x = x; + *other_y = y; + return TRUE; + } + } - *other_x = x; - *other_y = y; - return FALSE; + *other_x = x; + *other_y = y; + return FALSE; } BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const { - LLRect cur_rect = local; - const LLView* cur_view = this; - const LLView* root_view = NULL; + LLRect cur_rect = local; + const LLView* cur_view = this; + const LLView* root_view = NULL; - while (cur_view) - { - if (cur_view == other_view) - { - *other = cur_rect; - return TRUE; - } + while (cur_view) + { + if (cur_view == other_view) + { + *other = cur_rect; + return TRUE; + } - cur_rect.translate(cur_view->getRect().mLeft, cur_view->getRect().mBottom); + cur_rect.translate(cur_view->getRect().mLeft, cur_view->getRect().mBottom); - cur_view = cur_view->getParent(); - root_view = cur_view; - } + cur_view = cur_view->getParent(); + root_view = cur_view; + } - // assuming common root between two views, chase other_view's parents up to root - cur_view = other_view; - while (cur_view) - { - cur_rect.translate(-cur_view->getRect().mLeft, -cur_view->getRect().mBottom); + // assuming common root between two views, chase other_view's parents up to root + cur_view = other_view; + while (cur_view) + { + cur_rect.translate(-cur_view->getRect().mLeft, -cur_view->getRect().mBottom); - cur_view = cur_view->getParent(); + cur_view = cur_view->getParent(); - if (cur_view == root_view) - { - *other = cur_rect; - return TRUE; - } - } + if (cur_view == root_view) + { + *other = cur_rect; + return TRUE; + } + } - *other = cur_rect; - return FALSE; + *other = cur_rect; + return FALSE; } class CompareByTabOrder { public: - CompareByTabOrder(const LLView::child_tab_order_t& order, S32 default_tab_group = 0) - : mTabOrder(order), - mDefaultTabGroup(default_tab_group) - {} - virtual ~CompareByTabOrder() {} - - // This method compares two LLViews by the tab order specified in the comparator object. The - // code for this is a little convoluted because each argument can have four states: - // 1) not a control, 2) a control but not in the tab order, 3) a control in the tab order, 4) null - bool operator() (const LLView* const a, const LLView* const b) const - { - S32 a_group = 0, b_group = 0; - if(!a) return false; - if(!b) return true; - - LLView::child_tab_order_const_iter_t a_found = mTabOrder.find(a), b_found = mTabOrder.find(b); - if(a_found != mTabOrder.end()) - { - a_group = a_found->second; - } - if(b_found != mTabOrder.end()) - { - b_group = b_found->second; - } - - if(a_group < mDefaultTabGroup && b_group >= mDefaultTabGroup) return true; - if(b_group < mDefaultTabGroup && a_group >= mDefaultTabGroup) return false; - return a_group > b_group; // sort correctly if they're both on the same side of the default tab groupreturn a > b; - } + CompareByTabOrder(const LLView::child_tab_order_t& order, S32 default_tab_group = 0) + : mTabOrder(order), + mDefaultTabGroup(default_tab_group) + {} + virtual ~CompareByTabOrder() {} + + // This method compares two LLViews by the tab order specified in the comparator object. The + // code for this is a little convoluted because each argument can have four states: + // 1) not a control, 2) a control but not in the tab order, 3) a control in the tab order, 4) null + bool operator() (const LLView* const a, const LLView* const b) const + { + S32 a_group = 0, b_group = 0; + if(!a) return false; + if(!b) return true; + + LLView::child_tab_order_const_iter_t a_found = mTabOrder.find(a), b_found = mTabOrder.find(b); + if(a_found != mTabOrder.end()) + { + a_group = a_found->second; + } + if(b_found != mTabOrder.end()) + { + b_group = b_found->second; + } + + if(a_group < mDefaultTabGroup && b_group >= mDefaultTabGroup) return true; + if(b_group < mDefaultTabGroup && a_group >= mDefaultTabGroup) return false; + return a_group > b_group; // sort correctly if they're both on the same side of the default tab groupreturn a > b; + } private: - // ok to store a reference, as this should only be allocated on stack during view query operations - const LLView::child_tab_order_t& mTabOrder; - const S32 mDefaultTabGroup; + // ok to store a reference, as this should only be allocated on stack during view query operations + const LLView::child_tab_order_t& mTabOrder; + const S32 mDefaultTabGroup; }; class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder> { - LLSINGLETON_EMPTY_CTOR(SortByTabOrder); - /*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const override - { - children.sort(CompareByTabOrder(parent->getTabOrder(), parent->getDefaultTabGroup())); - } + LLSINGLETON_EMPTY_CTOR(SortByTabOrder); + /*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const override + { + children.sort(CompareByTabOrder(parent->getTabOrder(), parent->getDefaultTabGroup())); + } }; // static const LLViewQuery & LLView::getTabOrderQuery() { - static LLViewQuery query; - if(query.getPreFilters().size() == 0) { - query.addPreFilter(LLVisibleFilter::getInstance()); - query.addPreFilter(LLEnabledFilter::getInstance()); - query.addPreFilter(LLTabStopFilter::getInstance()); - query.addPostFilter(LLLeavesFilter::getInstance()); - query.setSorter(SortByTabOrder::getInstance()); - } - return query; + static LLViewQuery query; + if(query.getPreFilters().size() == 0) { + query.addPreFilter(LLVisibleFilter::getInstance()); + query.addPreFilter(LLEnabledFilter::getInstance()); + query.addPreFilter(LLTabStopFilter::getInstance()); + query.addPostFilter(LLLeavesFilter::getInstance()); + query.setSorter(SortByTabOrder::getInstance()); + } + return query; } -// This class is only used internally by getFocusRootsQuery below. +// This class is only used internally by getFocusRootsQuery below. class LLFocusRootsFilter : public LLQueryFilter, public LLSingleton<LLFocusRootsFilter> { - LLSINGLETON_EMPTY_CTOR(LLFocusRootsFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override - { - return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot()); - } + LLSINGLETON_EMPTY_CTOR(LLFocusRootsFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override + { + return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot()); + } }; // static const LLViewQuery & LLView::getFocusRootsQuery() { - static LLViewQuery query; - if(query.getPreFilters().size() == 0) { - query.addPreFilter(LLVisibleFilter::getInstance()); - query.addPreFilter(LLEnabledFilter::getInstance()); - query.addPreFilter(LLFocusRootsFilter::getInstance()); - query.addPostFilter(LLRootsFilter::getInstance()); - } - return query; + static LLViewQuery query; + if(query.getPreFilters().size() == 0) { + query.addPreFilter(LLVisibleFilter::getInstance()); + query.addPreFilter(LLEnabledFilter::getInstance()); + query.addPreFilter(LLFocusRootsFilter::getInstance()); + query.addPostFilter(LLRootsFilter::getInstance()); + } + return query; } -void LLView::setShape(const LLRect& new_rect, bool by_user) +void LLView::setShape(const LLRect& new_rect, bool by_user) { - if (new_rect != getRect()) - { - handleReshape(new_rect, by_user); - } + if (new_rect != getRect()) + { + handleReshape(new_rect, by_user); + } } void LLView::handleReshape(const LLRect& new_rect, bool by_user) { - reshape(new_rect.getWidth(), new_rect.getHeight()); - translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom); + reshape(new_rect.getWidth(), new_rect.getHeight()); + translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom); } LLView* LLView::findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, - LLView::ESnapType snap_type, S32 threshold, S32 padding) -{ - new_rect = mRect; - LLView* snap_view = NULL; - - if (!mParentView) - { - return NULL; - } - - S32 delta_x = 0; - S32 delta_y = 0; - if (mouse_dir.mX >= 0) - { - S32 new_right = mRect.mRight; - LLView* view = findSnapEdge(new_right, mouse_dir, SNAP_RIGHT, snap_type, threshold, padding); - delta_x = new_right - mRect.mRight; - snap_view = view ? view : snap_view; - } - - if (mouse_dir.mX <= 0) - { - S32 new_left = mRect.mLeft; - LLView* view = findSnapEdge(new_left, mouse_dir, SNAP_LEFT, snap_type, threshold, padding); - delta_x = new_left - mRect.mLeft; - snap_view = view ? view : snap_view; - } - - if (mouse_dir.mY >= 0) - { - S32 new_top = mRect.mTop; - LLView* view = findSnapEdge(new_top, mouse_dir, SNAP_TOP, snap_type, threshold, padding); - delta_y = new_top - mRect.mTop; - snap_view = view ? view : snap_view; - } - - if (mouse_dir.mY <= 0) - { - S32 new_bottom = mRect.mBottom; - LLView* view = findSnapEdge(new_bottom, mouse_dir, SNAP_BOTTOM, snap_type, threshold, padding); - delta_y = new_bottom - mRect.mBottom; - snap_view = view ? view : snap_view; - } - - new_rect.translate(delta_x, delta_y); - return snap_view; -} - -LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding) -{ - LLRect snap_rect = getSnapRect(); - S32 snap_pos = 0; - switch(snap_edge) - { - case SNAP_LEFT: - snap_pos = snap_rect.mLeft; - break; - case SNAP_RIGHT: - snap_pos = snap_rect.mRight; - break; - case SNAP_TOP: - snap_pos = snap_rect.mTop; - break; - case SNAP_BOTTOM: - snap_pos = snap_rect.mBottom; - break; - } - - if (!mParentView) - { - new_edge_val = snap_pos; - return NULL; - } - - LLView* snap_view = NULL; - - // If the view is near the edge of its parent, snap it to - // the edge. - LLRect test_rect = snap_rect; - test_rect.stretch(padding); - - S32 x_threshold = threshold; - S32 y_threshold = threshold; - - LLRect parent_local_snap_rect = mParentView->getLocalSnapRect(); - - if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS) - { - switch(snap_edge) - { - case SNAP_RIGHT: - if (llabs(parent_local_snap_rect.mRight - test_rect.mRight) <= x_threshold - && (parent_local_snap_rect.mRight - test_rect.mRight) * mouse_dir.mX >= 0) - { - snap_pos = parent_local_snap_rect.mRight - padding; - snap_view = mParentView; - x_threshold = llabs(parent_local_snap_rect.mRight - test_rect.mRight); - } - break; - case SNAP_LEFT: - if (llabs(test_rect.mLeft - parent_local_snap_rect.mLeft) <= x_threshold - && test_rect.mLeft * mouse_dir.mX <= 0) - { - snap_pos = parent_local_snap_rect.mLeft + padding; - snap_view = mParentView; - x_threshold = llabs(test_rect.mLeft - parent_local_snap_rect.mLeft); - } - break; - case SNAP_BOTTOM: - if (llabs(test_rect.mBottom - parent_local_snap_rect.mBottom) <= y_threshold - && test_rect.mBottom * mouse_dir.mY <= 0) - { - snap_pos = parent_local_snap_rect.mBottom + padding; - snap_view = mParentView; - y_threshold = llabs(test_rect.mBottom - parent_local_snap_rect.mBottom); - } - break; - case SNAP_TOP: - if (llabs(parent_local_snap_rect.mTop - test_rect.mTop) <= y_threshold && (parent_local_snap_rect.mTop - test_rect.mTop) * mouse_dir.mY >= 0) - { - snap_pos = parent_local_snap_rect.mTop - padding; - snap_view = mParentView; - y_threshold = llabs(parent_local_snap_rect.mTop - test_rect.mTop); - } - break; - default: - LL_ERRS() << "Invalid snap edge" << LL_ENDL; - } - } - - if (snap_type == SNAP_SIBLINGS || snap_type == SNAP_PARENT_AND_SIBLINGS) - { - for ( child_list_const_iter_t child_it = mParentView->getChildList()->begin(); - child_it != mParentView->getChildList()->end(); ++child_it) - { - LLView* siblingp = *child_it; - - if (!canSnapTo(siblingp)) continue; - - LLRect sibling_rect = siblingp->getSnapRect(); - - switch(snap_edge) - { - case SNAP_RIGHT: - if (llabs(test_rect.mRight - sibling_rect.mLeft) <= x_threshold - && (test_rect.mRight - sibling_rect.mLeft) * mouse_dir.mX <= 0) - { - snap_pos = sibling_rect.mLeft - padding; - snap_view = siblingp; - x_threshold = llabs(test_rect.mRight - sibling_rect.mLeft); - } - // if snapped with sibling along other axis, check for shared edge - else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold - || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= x_threshold) - { - if (llabs(test_rect.mRight - sibling_rect.mRight) <= x_threshold - && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0) - { - snap_pos = sibling_rect.mRight; - snap_view = siblingp; - x_threshold = llabs(test_rect.mRight - sibling_rect.mRight); - } - } - break; - case SNAP_LEFT: - if (llabs(test_rect.mLeft - sibling_rect.mRight) <= x_threshold - && (test_rect.mLeft - sibling_rect.mRight) * mouse_dir.mX <= 0) - { - snap_pos = sibling_rect.mRight + padding; - snap_view = siblingp; - x_threshold = llabs(test_rect.mLeft - sibling_rect.mRight); - } - // if snapped with sibling along other axis, check for shared edge - else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold - || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= y_threshold) - { - if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= x_threshold - && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0) - { - snap_pos = sibling_rect.mLeft; - snap_view = siblingp; - x_threshold = llabs(test_rect.mLeft - sibling_rect.mLeft); - } - } - break; - case SNAP_BOTTOM: - if (llabs(test_rect.mBottom - sibling_rect.mTop) <= y_threshold - && (test_rect.mBottom - sibling_rect.mTop) * mouse_dir.mY <= 0) - { - snap_pos = sibling_rect.mTop + padding; - snap_view = siblingp; - y_threshold = llabs(test_rect.mBottom - sibling_rect.mTop); - } - // if snapped with sibling along other axis, check for shared edge - else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold - || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold) - { - if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= y_threshold - && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0) - { - snap_pos = sibling_rect.mBottom; - snap_view = siblingp; - y_threshold = llabs(test_rect.mBottom - sibling_rect.mBottom); - } - } - break; - case SNAP_TOP: - if (llabs(test_rect.mTop - sibling_rect.mBottom) <= y_threshold - && (test_rect.mTop - sibling_rect.mBottom) * mouse_dir.mY <= 0) - { - snap_pos = sibling_rect.mBottom - padding; - snap_view = siblingp; - y_threshold = llabs(test_rect.mTop - sibling_rect.mBottom); - } - // if snapped with sibling along other axis, check for shared edge - else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold - || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold) - { - if (llabs(test_rect.mTop - sibling_rect.mTop) <= y_threshold - && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0) - { - snap_pos = sibling_rect.mTop; - snap_view = siblingp; - y_threshold = llabs(test_rect.mTop - sibling_rect.mTop); - } - } - break; - default: - LL_ERRS() << "Invalid snap edge" << LL_ENDL; - } - } - } - - new_edge_val = snap_pos; - return snap_view; + LLView::ESnapType snap_type, S32 threshold, S32 padding) +{ + new_rect = mRect; + LLView* snap_view = NULL; + + if (!mParentView) + { + return NULL; + } + + S32 delta_x = 0; + S32 delta_y = 0; + if (mouse_dir.mX >= 0) + { + S32 new_right = mRect.mRight; + LLView* view = findSnapEdge(new_right, mouse_dir, SNAP_RIGHT, snap_type, threshold, padding); + delta_x = new_right - mRect.mRight; + snap_view = view ? view : snap_view; + } + + if (mouse_dir.mX <= 0) + { + S32 new_left = mRect.mLeft; + LLView* view = findSnapEdge(new_left, mouse_dir, SNAP_LEFT, snap_type, threshold, padding); + delta_x = new_left - mRect.mLeft; + snap_view = view ? view : snap_view; + } + + if (mouse_dir.mY >= 0) + { + S32 new_top = mRect.mTop; + LLView* view = findSnapEdge(new_top, mouse_dir, SNAP_TOP, snap_type, threshold, padding); + delta_y = new_top - mRect.mTop; + snap_view = view ? view : snap_view; + } + + if (mouse_dir.mY <= 0) + { + S32 new_bottom = mRect.mBottom; + LLView* view = findSnapEdge(new_bottom, mouse_dir, SNAP_BOTTOM, snap_type, threshold, padding); + delta_y = new_bottom - mRect.mBottom; + snap_view = view ? view : snap_view; + } + + new_rect.translate(delta_x, delta_y); + return snap_view; +} + +LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding) +{ + LLRect snap_rect = getSnapRect(); + S32 snap_pos = 0; + switch(snap_edge) + { + case SNAP_LEFT: + snap_pos = snap_rect.mLeft; + break; + case SNAP_RIGHT: + snap_pos = snap_rect.mRight; + break; + case SNAP_TOP: + snap_pos = snap_rect.mTop; + break; + case SNAP_BOTTOM: + snap_pos = snap_rect.mBottom; + break; + } + + if (!mParentView) + { + new_edge_val = snap_pos; + return NULL; + } + + LLView* snap_view = NULL; + + // If the view is near the edge of its parent, snap it to + // the edge. + LLRect test_rect = snap_rect; + test_rect.stretch(padding); + + S32 x_threshold = threshold; + S32 y_threshold = threshold; + + LLRect parent_local_snap_rect = mParentView->getLocalSnapRect(); + + if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS) + { + switch(snap_edge) + { + case SNAP_RIGHT: + if (llabs(parent_local_snap_rect.mRight - test_rect.mRight) <= x_threshold + && (parent_local_snap_rect.mRight - test_rect.mRight) * mouse_dir.mX >= 0) + { + snap_pos = parent_local_snap_rect.mRight - padding; + snap_view = mParentView; + x_threshold = llabs(parent_local_snap_rect.mRight - test_rect.mRight); + } + break; + case SNAP_LEFT: + if (llabs(test_rect.mLeft - parent_local_snap_rect.mLeft) <= x_threshold + && test_rect.mLeft * mouse_dir.mX <= 0) + { + snap_pos = parent_local_snap_rect.mLeft + padding; + snap_view = mParentView; + x_threshold = llabs(test_rect.mLeft - parent_local_snap_rect.mLeft); + } + break; + case SNAP_BOTTOM: + if (llabs(test_rect.mBottom - parent_local_snap_rect.mBottom) <= y_threshold + && test_rect.mBottom * mouse_dir.mY <= 0) + { + snap_pos = parent_local_snap_rect.mBottom + padding; + snap_view = mParentView; + y_threshold = llabs(test_rect.mBottom - parent_local_snap_rect.mBottom); + } + break; + case SNAP_TOP: + if (llabs(parent_local_snap_rect.mTop - test_rect.mTop) <= y_threshold && (parent_local_snap_rect.mTop - test_rect.mTop) * mouse_dir.mY >= 0) + { + snap_pos = parent_local_snap_rect.mTop - padding; + snap_view = mParentView; + y_threshold = llabs(parent_local_snap_rect.mTop - test_rect.mTop); + } + break; + default: + LL_ERRS() << "Invalid snap edge" << LL_ENDL; + } + } + + if (snap_type == SNAP_SIBLINGS || snap_type == SNAP_PARENT_AND_SIBLINGS) + { + for ( child_list_const_iter_t child_it = mParentView->getChildList()->begin(); + child_it != mParentView->getChildList()->end(); ++child_it) + { + LLView* siblingp = *child_it; + + if (!canSnapTo(siblingp)) continue; + + LLRect sibling_rect = siblingp->getSnapRect(); + + switch(snap_edge) + { + case SNAP_RIGHT: + if (llabs(test_rect.mRight - sibling_rect.mLeft) <= x_threshold + && (test_rect.mRight - sibling_rect.mLeft) * mouse_dir.mX <= 0) + { + snap_pos = sibling_rect.mLeft - padding; + snap_view = siblingp; + x_threshold = llabs(test_rect.mRight - sibling_rect.mLeft); + } + // if snapped with sibling along other axis, check for shared edge + else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold + || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= x_threshold) + { + if (llabs(test_rect.mRight - sibling_rect.mRight) <= x_threshold + && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0) + { + snap_pos = sibling_rect.mRight; + snap_view = siblingp; + x_threshold = llabs(test_rect.mRight - sibling_rect.mRight); + } + } + break; + case SNAP_LEFT: + if (llabs(test_rect.mLeft - sibling_rect.mRight) <= x_threshold + && (test_rect.mLeft - sibling_rect.mRight) * mouse_dir.mX <= 0) + { + snap_pos = sibling_rect.mRight + padding; + snap_view = siblingp; + x_threshold = llabs(test_rect.mLeft - sibling_rect.mRight); + } + // if snapped with sibling along other axis, check for shared edge + else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= y_threshold + || llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= y_threshold) + { + if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= x_threshold + && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0) + { + snap_pos = sibling_rect.mLeft; + snap_view = siblingp; + x_threshold = llabs(test_rect.mLeft - sibling_rect.mLeft); + } + } + break; + case SNAP_BOTTOM: + if (llabs(test_rect.mBottom - sibling_rect.mTop) <= y_threshold + && (test_rect.mBottom - sibling_rect.mTop) * mouse_dir.mY <= 0) + { + snap_pos = sibling_rect.mTop + padding; + snap_view = siblingp; + y_threshold = llabs(test_rect.mBottom - sibling_rect.mTop); + } + // if snapped with sibling along other axis, check for shared edge + else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold + || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold) + { + if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= y_threshold + && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0) + { + snap_pos = sibling_rect.mBottom; + snap_view = siblingp; + y_threshold = llabs(test_rect.mBottom - sibling_rect.mBottom); + } + } + break; + case SNAP_TOP: + if (llabs(test_rect.mTop - sibling_rect.mBottom) <= y_threshold + && (test_rect.mTop - sibling_rect.mBottom) * mouse_dir.mY <= 0) + { + snap_pos = sibling_rect.mBottom - padding; + snap_view = siblingp; + y_threshold = llabs(test_rect.mTop - sibling_rect.mBottom); + } + // if snapped with sibling along other axis, check for shared edge + else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= x_threshold + || llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= x_threshold) + { + if (llabs(test_rect.mTop - sibling_rect.mTop) <= y_threshold + && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0) + { + snap_pos = sibling_rect.mTop; + snap_view = siblingp; + y_threshold = llabs(test_rect.mTop - sibling_rect.mTop); + } + } + break; + default: + LL_ERRS() << "Invalid snap edge" << LL_ENDL; + } + } + } + + new_edge_val = snap_pos; + return snap_view; } //----------------------------------------------------------------------------- @@ -2278,114 +2306,114 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna LLControlVariable *LLView::findControl(const std::string& name) { - // parse the name to locate which group it belongs to - std::size_t key_pos= name.find("."); - if(key_pos!= std::string::npos ) - { - std::string control_group_key = name.substr(0, key_pos); - LLControlVariable* control; - // check if it's in the control group that name indicated - if(LLUI::getInstance()->mSettingGroups[control_group_key]) - { - control = LLUI::getInstance()->mSettingGroups[control_group_key]->getControl(name); - if (control) - { - return control; - } - } - } - - LLControlGroup& control_group = LLUI::getInstance()->getControlControlGroup(name); - return control_group.getControl(name); + // parse the name to locate which group it belongs to + std::size_t key_pos= name.find("."); + if(key_pos!= std::string::npos ) + { + std::string control_group_key = name.substr(0, key_pos); + LLControlVariable* control; + // check if it's in the control group that name indicated + if(LLUI::getInstance()->mSettingGroups[control_group_key]) + { + control = LLUI::getInstance()->mSettingGroups[control_group_key]->getControl(name); + if (control) + { + return control; + } + } + } + + LLControlGroup& control_group = LLUI::getInstance()->getControlControlGroup(name); + return control_group.getControl(name); } void LLView::initFromParams(const LLView::Params& params) { - LLRect required_rect = getRequiredRect(); + LLRect required_rect = getRequiredRect(); - S32 width = llmax(getRect().getWidth(), required_rect.getWidth()); - S32 height = llmax(getRect().getHeight(), required_rect.getHeight()); + S32 width = llmax(getRect().getWidth(), required_rect.getWidth()); + S32 height = llmax(getRect().getHeight(), required_rect.getHeight()); - reshape(width, height); + reshape(width, height); - // call virtual methods with most recent data - // use getters because these values might not come through parameter block - setEnabled(getEnabled()); - setVisible(getVisible()); + // call virtual methods with most recent data + // use getters because these values might not come through parameter block + setEnabled(getEnabled()); + setVisible(getVisible()); - if (!params.name().empty()) - { - setName(params.name()); - } + if (!params.name().empty()) + { + setName(params.name()); + } - mLayout = params.layout(); + mLayout = params.layout(); } void LLView::parseFollowsFlags(const LLView::Params& params) { - // preserve follows flags set by code if user did not override - if (!params.follows.isProvided()) - { - return; - } - - // interpret either string or bitfield version of follows - if (params.follows.string.isChosen()) - { - setFollows(FOLLOWS_NONE); - - std::string follows = params.follows.string; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("|"); - tokenizer tokens(follows, sep); - tokenizer::iterator token_iter = tokens.begin(); - - while(token_iter != tokens.end()) - { - const std::string& token_str = *token_iter; - if (token_str == "left") - { - setFollowsLeft(); - } - else if (token_str == "right") - { - setFollowsRight(); - } - else if (token_str == "top") - { - setFollowsTop(); - } - else if (token_str == "bottom") - { - setFollowsBottom(); - } - else if (token_str == "all") - { - setFollowsAll(); - } - ++token_iter; - } - } - else if (params.follows.flags.isChosen()) - { - setFollows(params.follows.flags); - } + // preserve follows flags set by code if user did not override + if (!params.follows.isProvided()) + { + return; + } + + // interpret either string or bitfield version of follows + if (params.follows.string.isChosen()) + { + setFollows(FOLLOWS_NONE); + + std::string follows = params.follows.string; + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("|"); + tokenizer tokens(follows, sep); + tokenizer::iterator token_iter = tokens.begin(); + + while(token_iter != tokens.end()) + { + const std::string& token_str = *token_iter; + if (token_str == "left") + { + setFollowsLeft(); + } + else if (token_str == "right") + { + setFollowsRight(); + } + else if (token_str == "top") + { + setFollowsTop(); + } + else if (token_str == "bottom") + { + setFollowsBottom(); + } + else if (token_str == "all") + { + setFollowsAll(); + } + ++token_iter; + } + } + else if (params.follows.flags.isChosen()) + { + setFollows(params.follows.flags); + } } // static //LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) //{ -// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; +// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; // -// if (node->hasAttribute("halign")) -// { -// std::string horizontal_align_name; -// node->getAttributeString("halign", horizontal_align_name); -// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); -// } -// return gl_hfont_align; +// if (node->hasAttribute("halign")) +// { +// std::string horizontal_align_name; +// node->getAttributeString("halign", horizontal_align_name); +// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name); +// } +// return gl_hfont_align; //} // Return the rectangle of the last-constructed child, @@ -2393,395 +2421,395 @@ void LLView::parseFollowsFlags(const LLView::Params& params) // Returns true if found static bool get_last_child_rect(LLView* parent, LLRect *rect) { - if (!parent) return false; + if (!parent) return false; - LLView::child_list_t::const_iterator itor = - parent->getChildList()->begin(); - for (;itor != parent->getChildList()->end(); ++itor) - { - LLView *last_view = (*itor); - if (last_view->getFromXUI()) - { - *rect = last_view->getRect(); - return true; - } - } - return false; + LLView::child_list_t::const_iterator itor = + parent->getChildList()->begin(); + for (;itor != parent->getChildList()->end(); ++itor) + { + LLView *last_view = (*itor); + if (last_view->getFromXUI()) + { + *rect = last_view->getRect(); + return true; + } + } + return false; } //static void LLView::applyXUILayout(LLView::Params& p, LLView* parent, LLRect layout_rect) { - if (!parent) return; - - const S32 VPAD = 4; - const S32 MIN_WIDGET_HEIGHT = 10; - - // *NOTE: This will confuse export of floater/panel coordinates unless - // the default is also "topleft". JC - if (p.layout().empty()) - { - p.layout = parent->getLayout(); - } - - if (layout_rect.isEmpty()) - { - layout_rect = parent->getLocalRect(); - } - - // overwrite uninitialized rect params, using context - LLRect default_rect = parent->getLocalRect(); - - bool layout_topleft = (p.layout() == "topleft"); - - // convert negative or centered coordinates to parent relative values - // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() - if (p.rect.left.isProvided()) - { - p.rect.left = p.rect.left + ((p.rect.left >= 0) ? layout_rect.mLeft : layout_rect.mRight); - } - if (p.rect.right.isProvided()) - { - p.rect.right = p.rect.right + ((p.rect.right >= 0) ? layout_rect.mLeft : layout_rect.mRight); - } - if (p.rect.bottom.isProvided()) - { - p.rect.bottom = p.rect.bottom + ((p.rect.bottom >= 0) ? layout_rect.mBottom : layout_rect.mTop); - if (layout_topleft) - { - //invert top to bottom - p.rect.bottom = layout_rect.mBottom + layout_rect.mTop - p.rect.bottom; - } - } - if (p.rect.top.isProvided()) - { - p.rect.top = p.rect.top + ((p.rect.top >= 0) ? layout_rect.mBottom : layout_rect.mTop); - if (layout_topleft) - { - //invert top to bottom - p.rect.top = layout_rect.mBottom + layout_rect.mTop - p.rect.top; - } - } - - // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels - if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) - { - p.rect.height = MIN_WIDGET_HEIGHT; - } - - default_rect.translate(0, default_rect.getHeight()); - - // If there was a recently constructed child, use its rectangle - get_last_child_rect(parent, &default_rect); - - if (layout_topleft) - { - // Invert the sense of bottom_delta for topleft layout - if (p.bottom_delta.isProvided()) - { - p.bottom_delta = -p.bottom_delta; - } - else if (p.top_pad.isProvided()) - { - p.bottom_delta = -(p.rect.height + p.top_pad); - } - else if (p.top_delta.isProvided()) - { - p.bottom_delta = - -(p.top_delta + p.rect.height - default_rect.getHeight()); - } - else if (!p.left_delta.isProvided() - && !p.left_pad.isProvided()) - { - // set default position is just below last rect - p.bottom_delta.set(-(p.rect.height + VPAD), false); - } - else - { - p.bottom_delta.set(0, false); - } - - // default to same left edge - if (!p.left_delta.isProvided()) - { - p.left_delta.set(0, false); - } - if (p.left_pad.isProvided()) - { - // left_pad is based on prior widget's right edge - p.left_delta.set(p.left_pad + default_rect.getWidth(), false); - } - - default_rect.translate(p.left_delta, p.bottom_delta); - } - else - { - // set default position is just below last rect - if (!p.bottom_delta.isProvided()) - { - p.bottom_delta.set(-(p.rect.height + VPAD), false); - } - if (!p.left_delta.isProvided()) - { - p.left_delta.set(0, false); - } - default_rect.translate(p.left_delta, p.bottom_delta); - } - - // this handles case where *both* x and x_delta are provided - // ignore x in favor of default x + x_delta - if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); - if (p.left_delta.isProvided()) p.rect.left.set(0, false); - - // selectively apply rectangle defaults, making sure that - // params are not flagged as having been "provided" - // as rect params are overconstrained and rely on provided flags - if (!p.rect.left.isProvided()) - { - p.rect.left.set(default_rect.mLeft, false); - //HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value - p.rect.paramChanged(p.rect.left, true); - } - if (!p.rect.bottom.isProvided()) - { - p.rect.bottom.set(default_rect.mBottom, false); - p.rect.paramChanged(p.rect.bottom, true); - } - if (!p.rect.top.isProvided()) - { - p.rect.top.set(default_rect.mTop, false); - p.rect.paramChanged(p.rect.top, true); - } - if (!p.rect.right.isProvided()) - { - p.rect.right.set(default_rect.mRight, false); - p.rect.paramChanged(p.rect.right, true); - - } - if (!p.rect.width.isProvided()) - { - p.rect.width.set(default_rect.getWidth(), false); - p.rect.paramChanged(p.rect.width, true); - } - if (!p.rect.height.isProvided()) - { - p.rect.height.set(default_rect.getHeight(), false); - p.rect.paramChanged(p.rect.height, true); - } + if (!parent) return; + + const S32 VPAD = 4; + const S32 MIN_WIDGET_HEIGHT = 10; + + // *NOTE: This will confuse export of floater/panel coordinates unless + // the default is also "topleft". JC + if (p.layout().empty()) + { + p.layout = parent->getLayout(); + } + + if (layout_rect.isEmpty()) + { + layout_rect = parent->getLocalRect(); + } + + // overwrite uninitialized rect params, using context + LLRect default_rect = parent->getLocalRect(); + + bool layout_topleft = (p.layout() == "topleft"); + + // convert negative or centered coordinates to parent relative values + // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock() + if (p.rect.left.isProvided()) + { + p.rect.left = p.rect.left + ((p.rect.left >= 0) ? layout_rect.mLeft : layout_rect.mRight); + } + if (p.rect.right.isProvided()) + { + p.rect.right = p.rect.right + ((p.rect.right >= 0) ? layout_rect.mLeft : layout_rect.mRight); + } + if (p.rect.bottom.isProvided()) + { + p.rect.bottom = p.rect.bottom + ((p.rect.bottom >= 0) ? layout_rect.mBottom : layout_rect.mTop); + if (layout_topleft) + { + //invert top to bottom + p.rect.bottom = layout_rect.mBottom + layout_rect.mTop - p.rect.bottom; + } + } + if (p.rect.top.isProvided()) + { + p.rect.top = p.rect.top + ((p.rect.top >= 0) ? layout_rect.mBottom : layout_rect.mTop); + if (layout_topleft) + { + //invert top to bottom + p.rect.top = layout_rect.mBottom + layout_rect.mTop - p.rect.top; + } + } + + // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels + if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0) + { + p.rect.height = MIN_WIDGET_HEIGHT; + } + + default_rect.translate(0, default_rect.getHeight()); + + // If there was a recently constructed child, use its rectangle + get_last_child_rect(parent, &default_rect); + + if (layout_topleft) + { + // Invert the sense of bottom_delta for topleft layout + if (p.bottom_delta.isProvided()) + { + p.bottom_delta = -p.bottom_delta; + } + else if (p.top_pad.isProvided()) + { + p.bottom_delta = -(p.rect.height + p.top_pad); + } + else if (p.top_delta.isProvided()) + { + p.bottom_delta = + -(p.top_delta + p.rect.height - default_rect.getHeight()); + } + else if (!p.left_delta.isProvided() + && !p.left_pad.isProvided()) + { + // set default position is just below last rect + p.bottom_delta.set(-(p.rect.height + VPAD), false); + } + else + { + p.bottom_delta.set(0, false); + } + + // default to same left edge + if (!p.left_delta.isProvided()) + { + p.left_delta.set(0, false); + } + if (p.left_pad.isProvided()) + { + // left_pad is based on prior widget's right edge + p.left_delta.set(p.left_pad + default_rect.getWidth(), false); + } + + default_rect.translate(p.left_delta, p.bottom_delta); + } + else + { + // set default position is just below last rect + if (!p.bottom_delta.isProvided()) + { + p.bottom_delta.set(-(p.rect.height + VPAD), false); + } + if (!p.left_delta.isProvided()) + { + p.left_delta.set(0, false); + } + default_rect.translate(p.left_delta, p.bottom_delta); + } + + // this handles case where *both* x and x_delta are provided + // ignore x in favor of default x + x_delta + if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); + if (p.left_delta.isProvided()) p.rect.left.set(0, false); + + // selectively apply rectangle defaults, making sure that + // params are not flagged as having been "provided" + // as rect params are overconstrained and rely on provided flags + if (!p.rect.left.isProvided()) + { + p.rect.left.set(default_rect.mLeft, false); + //HACK: get around the fact that setting a rect param component value won't invalidate the existing rect object value + p.rect.paramChanged(p.rect.left, true); + } + if (!p.rect.bottom.isProvided()) + { + p.rect.bottom.set(default_rect.mBottom, false); + p.rect.paramChanged(p.rect.bottom, true); + } + if (!p.rect.top.isProvided()) + { + p.rect.top.set(default_rect.mTop, false); + p.rect.paramChanged(p.rect.top, true); + } + if (!p.rect.right.isProvided()) + { + p.rect.right.set(default_rect.mRight, false); + p.rect.paramChanged(p.rect.right, true); + + } + if (!p.rect.width.isProvided()) + { + p.rect.width.set(default_rect.getWidth(), false); + p.rect.paramChanged(p.rect.width, true); + } + if (!p.rect.height.isProvided()) + { + p.rect.height.set(default_rect.getHeight(), false); + p.rect.paramChanged(p.rect.height, true); + } } static S32 invert_vertical(S32 y, LLView* parent) { - if (y < 0) - { - // already based on top-left, just invert - return -y; - } - else if (parent) - { - // use parent to flip coordinate - S32 parent_height = parent->getRect().getHeight(); - return parent_height - y; - } - else - { - LL_WARNS() << "Attempting to convert layout to top-left with no parent" << LL_ENDL; - return y; - } + if (y < 0) + { + // already based on top-left, just invert + return -y; + } + else if (parent) + { + // use parent to flip coordinate + S32 parent_height = parent->getRect().getHeight(); + return parent_height - y; + } + else + { + LL_WARNS() << "Attempting to convert layout to top-left with no parent" << LL_ENDL; + return y; + } } // Assumes that input is in bottom-left coordinates, hence must call // _before_ convert_coords_to_top_left(). static void convert_to_relative_layout(LLView::Params& p, LLView* parent) { - // Use setupParams to get the final widget rectangle - // according to our wacky layout rules. - LLView::Params final = p; - LLView::applyXUILayout(final, parent); - // Must actually extract the rectangle to get consistent - // right = left+width, top = bottom+height - LLRect final_rect = final.rect; - - // We prefer to write out top edge instead of bottom, regardless - // of whether we use relative positioning - bool converted_top = false; - - // Look for a last rectangle - LLRect last_rect; - if (get_last_child_rect(parent, &last_rect)) - { - // ...we have a previous widget to compare to - const S32 EDGE_THRESHOLD_PIXELS = 4; - S32 left_pad = final_rect.mLeft - last_rect.mRight; - S32 left_delta = final_rect.mLeft - last_rect.mLeft; - S32 top_pad = final_rect.mTop - last_rect.mBottom; - S32 top_delta = final_rect.mTop - last_rect.mTop; - // If my left edge is almost the same, or my top edge is - // almost the same... - if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS - || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS) - { - // ...use relative positioning - // prefer top_pad if widgets are stacking vertically - // (coordinate system is still bottom-left here) - if (top_pad < 0) - { - p.top_pad = top_pad; - p.top_delta.setProvided(false); - } - else - { - p.top_pad.setProvided(false); - p.top_delta = top_delta; - } - // null out other vertical specifiers - p.rect.top.setProvided(false); - p.rect.bottom.setProvided(false); - p.bottom_delta.setProvided(false); - converted_top = true; - - // prefer left_pad if widgets are stacking horizontally - if (left_pad > 0) - { - p.left_pad = left_pad; - p.left_delta.setProvided(false); - } - else - { - p.left_pad.setProvided(false); - p.left_delta = left_delta; - } - p.rect.left.setProvided(false); - p.rect.right.setProvided(false); - } - } - - if (!converted_top) - { - // ...this is the first widget, or one that wasn't aligned - // prefer top/left specification - p.rect.top = final_rect.mTop; - p.rect.bottom.setProvided(false); - p.bottom_delta.setProvided(false); - p.top_pad.setProvided(false); - p.top_delta.setProvided(false); - } + // Use setupParams to get the final widget rectangle + // according to our wacky layout rules. + LLView::Params final = p; + LLView::applyXUILayout(final, parent); + // Must actually extract the rectangle to get consistent + // right = left+width, top = bottom+height + LLRect final_rect = final.rect; + + // We prefer to write out top edge instead of bottom, regardless + // of whether we use relative positioning + bool converted_top = false; + + // Look for a last rectangle + LLRect last_rect; + if (get_last_child_rect(parent, &last_rect)) + { + // ...we have a previous widget to compare to + const S32 EDGE_THRESHOLD_PIXELS = 4; + S32 left_pad = final_rect.mLeft - last_rect.mRight; + S32 left_delta = final_rect.mLeft - last_rect.mLeft; + S32 top_pad = final_rect.mTop - last_rect.mBottom; + S32 top_delta = final_rect.mTop - last_rect.mTop; + // If my left edge is almost the same, or my top edge is + // almost the same... + if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS + || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS) + { + // ...use relative positioning + // prefer top_pad if widgets are stacking vertically + // (coordinate system is still bottom-left here) + if (top_pad < 0) + { + p.top_pad = top_pad; + p.top_delta.setProvided(false); + } + else + { + p.top_pad.setProvided(false); + p.top_delta = top_delta; + } + // null out other vertical specifiers + p.rect.top.setProvided(false); + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + converted_top = true; + + // prefer left_pad if widgets are stacking horizontally + if (left_pad > 0) + { + p.left_pad = left_pad; + p.left_delta.setProvided(false); + } + else + { + p.left_pad.setProvided(false); + p.left_delta = left_delta; + } + p.rect.left.setProvided(false); + p.rect.right.setProvided(false); + } + } + + if (!converted_top) + { + // ...this is the first widget, or one that wasn't aligned + // prefer top/left specification + p.rect.top = final_rect.mTop; + p.rect.bottom.setProvided(false); + p.bottom_delta.setProvided(false); + p.top_pad.setProvided(false); + p.top_delta.setProvided(false); + } } static void convert_coords_to_top_left(LLView::Params& p, LLView* parent) { - // Convert the coordinate system to be top-left based. - if (p.rect.top.isProvided()) - { - p.rect.top = invert_vertical(p.rect.top, parent); - } - if (p.rect.bottom.isProvided()) - { - p.rect.bottom = invert_vertical(p.rect.bottom, parent); - } - if (p.top_pad.isProvided()) - { - p.top_pad = -p.top_pad; - } - if (p.top_delta.isProvided()) - { - p.top_delta = -p.top_delta; - } - if (p.bottom_delta.isProvided()) - { - p.bottom_delta = -p.bottom_delta; - } - p.layout = "topleft"; + // Convert the coordinate system to be top-left based. + if (p.rect.top.isProvided()) + { + p.rect.top = invert_vertical(p.rect.top, parent); + } + if (p.rect.bottom.isProvided()) + { + p.rect.bottom = invert_vertical(p.rect.bottom, parent); + } + if (p.top_pad.isProvided()) + { + p.top_pad = -p.top_pad; + } + if (p.top_delta.isProvided()) + { + p.top_delta = -p.top_delta; + } + if (p.bottom_delta.isProvided()) + { + p.bottom_delta = -p.bottom_delta; + } + p.layout = "topleft"; } //static void LLView::setupParamsForExport(Params& p, LLView* parent) { - // Don't convert if already top-left based - if (p.layout() == "topleft") - { - return; - } - - // heuristic: Many of our floaters and panels were bulk-exported. - // These specify exactly bottom/left and height/width. - // Others were done by hand using bottom_delta and/or left_delta. - // Some rely on not specifying left to mean align with left edge. - // Try to convert both to use relative layout, but using top-left - // coordinates. - // Avoid rectangles where top/bottom/left/right was specified. - if (p.rect.height.isProvided() && p.rect.width.isProvided()) - { - if (p.rect.bottom.isProvided() && p.rect.left.isProvided()) - { - // standard bulk export, convert it - convert_to_relative_layout(p, parent); - } - else if (p.rect.bottom.isProvided() && p.left_delta.isProvided()) - { - // hand layout with left_delta - convert_to_relative_layout(p, parent); - } - else if (p.bottom_delta.isProvided()) - { - // hand layout with bottom_delta - // don't check for p.rect.left or p.left_delta because sometimes - // this layout doesn't set it for widgets that are left-aligned - convert_to_relative_layout(p, parent); - } - } - - convert_coords_to_top_left(p, parent); -} - -LLView::tree_iterator_t LLView::beginTreeDFS() -{ - return tree_iterator_t(this, - boost::bind(boost::mem_fn(&LLView::beginChild), _1), - boost::bind(boost::mem_fn(&LLView::endChild), _1)); -} - -LLView::tree_iterator_t LLView::endTreeDFS() -{ - // an empty iterator is an "end" iterator - return tree_iterator_t(); -} - -LLView::tree_post_iterator_t LLView::beginTreeDFSPost() -{ - return tree_post_iterator_t(this, - boost::bind(boost::mem_fn(&LLView::beginChild), _1), - boost::bind(boost::mem_fn(&LLView::endChild), _1)); -} - -LLView::tree_post_iterator_t LLView::endTreeDFSPost() -{ - // an empty iterator is an "end" iterator - return tree_post_iterator_t(); -} - -LLView::bfs_tree_iterator_t LLView::beginTreeBFS() -{ - return bfs_tree_iterator_t(this, - boost::bind(boost::mem_fn(&LLView::beginChild), _1), - boost::bind(boost::mem_fn(&LLView::endChild), _1)); -} - -LLView::bfs_tree_iterator_t LLView::endTreeBFS() -{ - // an empty iterator is an "end" iterator - return bfs_tree_iterator_t(); + // Don't convert if already top-left based + if (p.layout() == "topleft") + { + return; + } + + // heuristic: Many of our floaters and panels were bulk-exported. + // These specify exactly bottom/left and height/width. + // Others were done by hand using bottom_delta and/or left_delta. + // Some rely on not specifying left to mean align with left edge. + // Try to convert both to use relative layout, but using top-left + // coordinates. + // Avoid rectangles where top/bottom/left/right was specified. + if (p.rect.height.isProvided() && p.rect.width.isProvided()) + { + if (p.rect.bottom.isProvided() && p.rect.left.isProvided()) + { + // standard bulk export, convert it + convert_to_relative_layout(p, parent); + } + else if (p.rect.bottom.isProvided() && p.left_delta.isProvided()) + { + // hand layout with left_delta + convert_to_relative_layout(p, parent); + } + else if (p.bottom_delta.isProvided()) + { + // hand layout with bottom_delta + // don't check for p.rect.left or p.left_delta because sometimes + // this layout doesn't set it for widgets that are left-aligned + convert_to_relative_layout(p, parent); + } + } + + convert_coords_to_top_left(p, parent); +} + +LLView::tree_iterator_t LLView::beginTreeDFS() +{ + return tree_iterator_t(this, + boost::bind(boost::mem_fn(&LLView::beginChild), _1), + boost::bind(boost::mem_fn(&LLView::endChild), _1)); +} + +LLView::tree_iterator_t LLView::endTreeDFS() +{ + // an empty iterator is an "end" iterator + return tree_iterator_t(); +} + +LLView::tree_post_iterator_t LLView::beginTreeDFSPost() +{ + return tree_post_iterator_t(this, + boost::bind(boost::mem_fn(&LLView::beginChild), _1), + boost::bind(boost::mem_fn(&LLView::endChild), _1)); +} + +LLView::tree_post_iterator_t LLView::endTreeDFSPost() +{ + // an empty iterator is an "end" iterator + return tree_post_iterator_t(); +} + +LLView::bfs_tree_iterator_t LLView::beginTreeBFS() +{ + return bfs_tree_iterator_t(this, + boost::bind(boost::mem_fn(&LLView::beginChild), _1), + boost::bind(boost::mem_fn(&LLView::endChild), _1)); +} + +LLView::bfs_tree_iterator_t LLView::endTreeBFS() +{ + // an empty iterator is an "end" iterator + return bfs_tree_iterator_t(); } LLView::root_to_view_iterator_t LLView::beginRootToView() { - return root_to_view_iterator_t(this, boost::bind(&LLView::getParent, _1)); + return root_to_view_iterator_t(this, boost::bind(&LLView::getParent, _1)); } LLView::root_to_view_iterator_t LLView::endRootToView() { - return root_to_view_iterator_t(); + return root_to_view_iterator_t(); } @@ -2789,66 +2817,66 @@ LLView::root_to_view_iterator_t LLView::endRootToView() // when a view is constructed/deconstructed LLView& LLView::getDefaultWidgetContainer() const { - if (!mDefaultWidgets) - { - LLView::Params p; - p.name = "default widget container"; - p.visible = false; // ensures default widgets can't steal focus, etc. - mDefaultWidgets = new LLView(p); - } - return *mDefaultWidgets; + if (!mDefaultWidgets) + { + LLView::Params p; + p.name = "default widget container"; + p.visible = false; // ensures default widgets can't steal focus, etc. + mDefaultWidgets = new LLView(p); + } + return *mDefaultWidgets; } -S32 LLView::notifyParent(const LLSD& info) +S32 LLView::notifyParent(const LLSD& info) { - LLView* parent = getParent(); - if(parent) - return parent->notifyParent(info); - return 0; + LLView* parent = getParent(); + if(parent) + return parent->notifyParent(info); + return 0; } -bool LLView::notifyChildren(const LLSD& info) +bool LLView::notifyChildren(const LLSD& info) { - bool ret = false; - for (LLView* childp : mChildList) - { - ret = ret || childp->notifyChildren(info); - } - return ret; + bool ret = false; + for (LLView* childp : mChildList) + { + ret = ret || childp->notifyChildren(info); + } + return ret; } // convenient accessor for draw context const LLViewDrawContext& LLView::getDrawContext() { - return LLViewDrawContext::getCurrentContext(); + return LLViewDrawContext::getCurrentContext(); } const LLViewDrawContext& LLViewDrawContext::getCurrentContext() { - static LLViewDrawContext default_context; + static LLViewDrawContext default_context; + + if (sDrawContextStack.empty()) + return default_context; - if (sDrawContextStack.empty()) - return default_context; - - return *sDrawContextStack.back(); + return *sDrawContextStack.back(); } LLSD LLView::getInfo(void) { - LLSD info; - addInfo(info); - return info; + LLSD info; + addInfo(info); + return info; } void LLView::addInfo(LLSD & info) { - info["path"] = getPathname(); - info["class"] = typeid(*this).name(); - info["visible"] = getVisible(); - info["visible_chain"] = isInVisibleChain(); - info["enabled"] = getEnabled(); - info["enabled_chain"] = isInEnabledChain(); - info["available"] = isAvailable(); - LLRect rect(calcScreenRect()); - info["rect"] = LLSDMap("left", rect.mLeft)("top", rect.mTop) - ("right", rect.mRight)("bottom", rect.mBottom); + info["path"] = getPathname(); + info["class"] = typeid(*this).name(); + info["visible"] = getVisible(); + info["visible_chain"] = isInVisibleChain(); + info["enabled"] = getEnabled(); + info["enabled_chain"] = isInEnabledChain(); + info["available"] = isAvailable(); + LLRect rect(calcScreenRect()); + info["rect"] = LLSDMap("left", rect.mLeft)("top", rect.mTop) + ("right", rect.mRight)("bottom", rect.mBottom); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index c14a8bdce3..fefdd83bd4 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -1,25 +1,25 @@ -/** +/** * @file llview.h * @brief Container for other views, anything that draws. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -54,15 +54,15 @@ class LLSD; -const U32 FOLLOWS_NONE = 0x00; -const U32 FOLLOWS_LEFT = 0x01; -const U32 FOLLOWS_RIGHT = 0x02; -const U32 FOLLOWS_TOP = 0x10; -const U32 FOLLOWS_BOTTOM = 0x20; -const U32 FOLLOWS_ALL = 0x33; +const U32 FOLLOWS_NONE = 0x00; +const U32 FOLLOWS_LEFT = 0x01; +const U32 FOLLOWS_RIGHT = 0x02; +const U32 FOLLOWS_TOP = 0x10; +const U32 FOLLOWS_BOTTOM = 0x20; +const U32 FOLLOWS_ALL = 0x33; -const BOOL MOUSE_OPAQUE = TRUE; -const BOOL NOT_MOUSE_OPAQUE = FALSE; +const BOOL MOUSE_OPAQUE = TRUE; +const BOOL NOT_MOUSE_OPAQUE = FALSE; const U32 GL_NAME_UI_RESERVED = 2; @@ -71,618 +71,620 @@ const U32 GL_NAME_UI_RESERVED = 2; class LLViewDrawContext { public: - F32 mAlpha; - - LLViewDrawContext(F32 alpha = 1.f) - : mAlpha(alpha) - { - if (!sDrawContextStack.empty()) - { - LLViewDrawContext* context_top = sDrawContextStack.back(); - // merge with top of stack - mAlpha *= context_top->mAlpha; - } - sDrawContextStack.push_back(this); - } - - ~LLViewDrawContext() - { - sDrawContextStack.pop_back(); - } - - static const LLViewDrawContext& getCurrentContext(); + F32 mAlpha; + + LLViewDrawContext(F32 alpha = 1.f) + : mAlpha(alpha) + { + if (!sDrawContextStack.empty()) + { + LLViewDrawContext* context_top = sDrawContextStack.back(); + // merge with top of stack + mAlpha *= context_top->mAlpha; + } + sDrawContextStack.push_back(this); + } + + ~LLViewDrawContext() + { + sDrawContextStack.pop_back(); + } + + static const LLViewDrawContext& getCurrentContext(); private: - static std::vector<LLViewDrawContext*> sDrawContextStack; + static std::vector<LLViewDrawContext*> sDrawContextStack; }; -class LLView -: public LLMouseHandler, // handles mouse events - public LLFocusableElement, // handles keyboard events - public LLMortician, // lazy deletion - public LLHandleProvider<LLView> // passes out weak references to self +class LLView +: public LLMouseHandler, // handles mouse events + public LLFocusableElement, // handles keyboard events + public LLMortician, // lazy deletion + public LLHandleProvider<LLView> // passes out weak references to self { public: - enum EOrientation { HORIZONTAL, VERTICAL, ORIENTATION_COUNT }; + enum EOrientation { HORIZONTAL, VERTICAL, ORIENTATION_COUNT }; - struct Follows : public LLInitParam::ChoiceBlock<Follows> - { - Alternative<std::string> string; - Alternative<U32> flags; + struct Follows : public LLInitParam::ChoiceBlock<Follows> + { + Alternative<std::string> string; + Alternative<U32> flags; - Follows(); - }; + Follows(); + }; - struct Params : public LLInitParam::Block<Params> - { - Mandatory<std::string> name; + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; - Optional<bool> enabled, - visible, - mouse_opaque, - use_bounding_rect, - from_xui, - focus_root; + Optional<bool> enabled, + visible, + mouse_opaque, + use_bounding_rect, + from_xui, + focus_root; - Optional<S32> tab_group, - default_tab_group; - Optional<std::string> tool_tip; + Optional<S32> tab_group, + default_tab_group; + Optional<std::string> tool_tip; - Optional<S32> sound_flags; - Optional<Follows> follows; - Optional<std::string> hover_cursor; + Optional<S32> sound_flags; + Optional<Follows> follows; + Optional<std::string> hover_cursor; - Optional<std::string> layout; - Optional<LLRect> rect; + Optional<std::string> layout; + Optional<LLRect> rect; - // Historical bottom-left layout used bottom_delta and left_delta - // for relative positioning. New layout "topleft" prefers specifying - // based on top edge. - Optional<S32> bottom_delta, // from last bottom to my bottom - top_pad, // from last bottom to my top - top_delta, // from last top to my top - left_pad, // from last right to my left - left_delta; // from last left to my left + // Historical bottom-left layout used bottom_delta and left_delta + // for relative positioning. New layout "topleft" prefers specifying + // based on top edge. + Optional<S32> bottom_delta, // from last bottom to my bottom + top_pad, // from last bottom to my top + top_delta, // from last top to my top + left_pad, // from last right to my left + left_delta; // from last left to my left - //FIXME: get parent context involved in parsing traversal - Ignored needs_translate, // cue for translation tools - xmlns, // xml namespace - xmlns_xsi, // xml namespace - xsi_schemaLocation, // xml schema - xsi_type; // xml schema type + //FIXME: get parent context involved in parsing traversal + Ignored needs_translate, // cue for translation tools + xmlns, // xml namespace + xmlns_xsi, // xml namespace + xsi_schemaLocation, // xml schema + xsi_type; // xml schema type - Params(); - }; + Params(); + }; - // most widgets are valid children of LLView - typedef LLDefaultChildRegistry child_registry_t; + // most widgets are valid children of LLView + typedef LLDefaultChildRegistry child_registry_t; - void initFromParams(const LLView::Params&); + void initFromParams(const LLView::Params&); protected: - LLView(const LLView::Params&); - friend class LLUICtrlFactory; + LLView(const LLView::Params&); + friend class LLUICtrlFactory; private: - // widgets in general are not copyable - LLView(const LLView& other); + // widgets in general are not copyable + LLView(const LLView& other); public: //#if LL_DEBUG - static BOOL sIsDrawing; + static BOOL sIsDrawing; //#endif - enum ESoundFlags - { - SILENT = 0, - MOUSE_DOWN = 1, - MOUSE_UP = 2 - }; - - enum ESnapType - { - SNAP_PARENT, - SNAP_SIBLINGS, - SNAP_PARENT_AND_SIBLINGS - }; - - enum ESnapEdge - { - SNAP_LEFT, - SNAP_TOP, - SNAP_RIGHT, - SNAP_BOTTOM - }; - - typedef std::list<LLView*> child_list_t; - typedef child_list_t::iterator child_list_iter_t; - typedef child_list_t::const_iterator child_list_const_iter_t; - typedef child_list_t::reverse_iterator child_list_reverse_iter_t; - typedef child_list_t::const_reverse_iterator child_list_const_reverse_iter_t; - - typedef std::pair<LLView *, S32> tab_order_pair_t; - // this structure primarily sorts by the tab group, secondarily by the insertion ordinal (lastly by the value of the pointer) - typedef std::map<const LLView*, S32> child_tab_order_t; - typedef child_tab_order_t::iterator child_tab_order_iter_t; - typedef child_tab_order_t::const_iterator child_tab_order_const_iter_t; - typedef child_tab_order_t::reverse_iterator child_tab_order_reverse_iter_t; - typedef child_tab_order_t::const_reverse_iterator child_tab_order_const_reverse_iter_t; - - virtual ~LLView(); - - // Some UI widgets need to be added as controls. Others need to - // be added as regular view children. isCtrl should return TRUE - // if a widget needs to be added as a ctrl - virtual BOOL isCtrl() const; - - virtual BOOL isPanel() const; - - // - // MANIPULATORS - // - void setMouseOpaque( BOOL b ) { mMouseOpaque = b; } - BOOL getMouseOpaque() const { return mMouseOpaque; } - void setToolTip( const LLStringExplicit& msg ); - BOOL setToolTipArg( const LLStringExplicit& key, const LLStringExplicit& text ); - void setToolTipArgs( const LLStringUtil::format_map_t& args ); - - virtual void setRect(const LLRect &rect); - void setFollows(U32 flags) { mReshapeFlags = flags; } - - // deprecated, use setFollows() with FOLLOWS_LEFT | FOLLOWS_TOP, etc. - void setFollowsNone() { mReshapeFlags = FOLLOWS_NONE; } - void setFollowsLeft() { mReshapeFlags |= FOLLOWS_LEFT; } - void setFollowsTop() { mReshapeFlags |= FOLLOWS_TOP; } - void setFollowsRight() { mReshapeFlags |= FOLLOWS_RIGHT; } - void setFollowsBottom() { mReshapeFlags |= FOLLOWS_BOTTOM; } - void setFollowsAll() { mReshapeFlags |= FOLLOWS_ALL; } - - void setSoundFlags(U8 flags) { mSoundFlags = flags; } - void setName(std::string name) { mName = name; } - void setUseBoundingRect( BOOL use_bounding_rect ); - BOOL getUseBoundingRect() const; - - ECursorType getHoverCursor() { return mHoverCursor; } + enum ESoundFlags + { + SILENT = 0, + MOUSE_DOWN = 1, + MOUSE_UP = 2 + }; + + enum ESnapType + { + SNAP_PARENT, + SNAP_SIBLINGS, + SNAP_PARENT_AND_SIBLINGS + }; + + enum ESnapEdge + { + SNAP_LEFT, + SNAP_TOP, + SNAP_RIGHT, + SNAP_BOTTOM + }; + + typedef std::list<LLView*> child_list_t; + typedef child_list_t::iterator child_list_iter_t; + typedef child_list_t::const_iterator child_list_const_iter_t; + typedef child_list_t::reverse_iterator child_list_reverse_iter_t; + typedef child_list_t::const_reverse_iterator child_list_const_reverse_iter_t; + + typedef std::pair<LLView *, S32> tab_order_pair_t; + // this structure primarily sorts by the tab group, secondarily by the insertion ordinal (lastly by the value of the pointer) + typedef std::map<const LLView*, S32> child_tab_order_t; + typedef child_tab_order_t::iterator child_tab_order_iter_t; + typedef child_tab_order_t::const_iterator child_tab_order_const_iter_t; + typedef child_tab_order_t::reverse_iterator child_tab_order_reverse_iter_t; + typedef child_tab_order_t::const_reverse_iterator child_tab_order_const_reverse_iter_t; + + virtual ~LLView(); + + // Some UI widgets need to be added as controls. Others need to + // be added as regular view children. isCtrl should return TRUE + // if a widget needs to be added as a ctrl + virtual BOOL isCtrl() const; + + virtual BOOL isPanel() const; + + // + // MANIPULATORS + // + void setMouseOpaque( BOOL b ) { mMouseOpaque = b; } + BOOL getMouseOpaque() const { return mMouseOpaque; } + void setToolTip( const LLStringExplicit& msg ); + BOOL setToolTipArg( const LLStringExplicit& key, const LLStringExplicit& text ); + void setToolTipArgs( const LLStringUtil::format_map_t& args ); + + virtual void setRect(const LLRect &rect); + void setFollows(U32 flags) { mReshapeFlags = flags; } + + // deprecated, use setFollows() with FOLLOWS_LEFT | FOLLOWS_TOP, etc. + void setFollowsNone() { mReshapeFlags = FOLLOWS_NONE; } + void setFollowsLeft() { mReshapeFlags |= FOLLOWS_LEFT; } + void setFollowsTop() { mReshapeFlags |= FOLLOWS_TOP; } + void setFollowsRight() { mReshapeFlags |= FOLLOWS_RIGHT; } + void setFollowsBottom() { mReshapeFlags |= FOLLOWS_BOTTOM; } + void setFollowsAll() { mReshapeFlags |= FOLLOWS_ALL; } + + void setSoundFlags(U8 flags) { mSoundFlags = flags; } + void setName(std::string name) { mName = name; } + void setUseBoundingRect( BOOL use_bounding_rect ); + BOOL getUseBoundingRect() const; + + ECursorType getHoverCursor() { return mHoverCursor; } static F32 getTooltipTimeout(); - virtual const std::string getToolTip() const { return mToolTipMsg.getString(); } - - void sendChildToFront(LLView* child); - void sendChildToBack(LLView* child); - - virtual bool addChild(LLView* view, S32 tab_group = 0); - - // implemented in terms of addChild() - bool addChildInBack(LLView* view, S32 tab_group = 0); - - // remove the specified child from the view, and set it's parent to NULL. - virtual void removeChild(LLView* view); - - virtual BOOL postBuild() { return TRUE; } - - const child_tab_order_t& getTabOrder() const { return mTabOrder; } - - void setDefaultTabGroup(S32 d) { mDefaultTabGroup = d; } - S32 getDefaultTabGroup() const { return mDefaultTabGroup; } - S32 getLastTabGroup() { return mLastTabGroup; } - - BOOL isInVisibleChain() const; - BOOL isInEnabledChain() const; - - void setFocusRoot(BOOL b) { mIsFocusRoot = b; } - BOOL isFocusRoot() const { return mIsFocusRoot; } - virtual BOOL canFocusChildren() const; - - BOOL focusNextRoot(); - BOOL focusPrevRoot(); - - // Normally we want the app menus to get priority on accelerated keys - // However, sometimes we want to give specific views a first chance - // iat handling them. (eg. the script editor) - virtual bool hasAccelerators() const { return false; }; - - // delete all children. Override this function if you need to - // perform any extra clean up such as cached pointers to selected - // children, etc. - virtual void deleteAllChildren(); - - void setAllChildrenEnabled(BOOL b); - - virtual void setVisible(BOOL visible); - void setVisibleDirect(BOOL visible) { mVisible = visible; } - const BOOL& getVisible() const { return mVisible; } - virtual void setEnabled(BOOL enabled); - BOOL getEnabled() const { return mEnabled; } - /// 'available' in this context means 'visible and enabled': in other - /// words, can a user actually interact with this? - virtual bool isAvailable() const; - /// The static isAvailable() tests an LLView* that could be NULL. - static bool isAvailable(const LLView* view); - U8 getSoundFlags() const { return mSoundFlags; } - - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - - virtual void onVisibilityChange ( BOOL new_visibility ); - virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); - - void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } - void popVisible() { setVisible(mLastVisible); } - BOOL getLastVisible() const { return mLastVisible; } - - U32 getFollows() const { return mReshapeFlags; } - BOOL followsLeft() const { return mReshapeFlags & FOLLOWS_LEFT; } - BOOL followsRight() const { return mReshapeFlags & FOLLOWS_RIGHT; } - BOOL followsTop() const { return mReshapeFlags & FOLLOWS_TOP; } - BOOL followsBottom() const { return mReshapeFlags & FOLLOWS_BOTTOM; } - BOOL followsAll() const { return mReshapeFlags & FOLLOWS_ALL; } - - const LLRect& getRect() const { return mRect; } - const LLRect& getBoundingRect() const { return mBoundingRect; } - LLRect getLocalBoundingRect() const; - LLRect calcScreenRect() const; - LLRect calcScreenBoundingRect() const; - LLRect getLocalRect() const; - virtual LLRect getSnapRect() const; - LLRect getLocalSnapRect() const; - - std::string getLayout() { return mLayout; } - - // Override and return required size for this object. 0 for width/height means don't care. - virtual LLRect getRequiredRect(); - LLRect calcBoundingRect(); - void updateBoundingRect(); - - LLView* getRootView(); - LLView* getParent() const { return mParentView; } - LLView* getFirstChild() const { return (mChildList.empty()) ? NULL : *(mChildList.begin()); } - LLView* findPrevSibling(LLView* child); - LLView* findNextSibling(LLView* child); - S32 getChildCount() const { return (S32)mChildList.size(); } - template<class _Pr3> void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); } - BOOL hasAncestor(const LLView* parentp) const; - BOOL hasChild(const std::string& childname, BOOL recurse = FALSE) const; - BOOL childHasKeyboardFocus( const std::string& childname ) const; - - // these iterators are used for collapsing various tree traversals into for loops - typedef LLTreeDFSIter<LLView, child_list_const_iter_t> tree_iterator_t; - tree_iterator_t beginTreeDFS(); - tree_iterator_t endTreeDFS(); - - typedef LLTreeDFSPostIter<LLView, child_list_const_iter_t> tree_post_iterator_t; - tree_post_iterator_t beginTreeDFSPost(); - tree_post_iterator_t endTreeDFSPost(); - - typedef LLTreeBFSIter<LLView, child_list_const_iter_t> bfs_tree_iterator_t; - bfs_tree_iterator_t beginTreeBFS(); - bfs_tree_iterator_t endTreeBFS(); - - - typedef LLTreeDownIter<LLView> root_to_view_iterator_t; - root_to_view_iterator_t beginRootToView(); - root_to_view_iterator_t endRootToView(); - - // - // UTILITIES - // - - // Default behavior is to use reshape flags to resize child views - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual void translate( S32 x, S32 y ); - void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } - BOOL translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); - BOOL translateRectIntoRect( const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); - BOOL translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX); - void centerWithin(const LLRect& bounds); - - void setShape(const LLRect& new_rect, bool by_user = false); - virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); - virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); - virtual BOOL canSnapTo(const LLView* other_view); - virtual void setSnappedTo(const LLView* snap_view); - - // inherited from LLFocusableElement - /* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - /* virtual */ BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); - /* virtual */ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); - - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - virtual void draw(); - - void parseFollowsFlags(const LLView::Params& params); - - // Some widgets, like close box buttons, don't need to be saved - BOOL getFromXUI() const { return mFromXUI; } - void setFromXUI(BOOL b) { mFromXUI = b; } - - typedef enum e_hit_test_type - { - HIT_TEST_USE_BOUNDING_RECT, - HIT_TEST_IGNORE_BOUNDING_RECT - }EHitTestType; - - BOOL parentPointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const; - BOOL pointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const; - BOOL blockMouseEvent(S32 x, S32 y) const; - - // See LLMouseHandler virtuals for screenPointToLocal and localPointToScreen - BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const; - BOOL localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const; - void screenRectToLocal( const LLRect& screen, LLRect* local ) const; - void localRectToScreen( const LLRect& local, LLRect* screen ) const; - - LLControlVariable *findControl(const std::string& name); - - const child_list_t* getChildList() const { return &mChildList; } - child_list_const_iter_t beginChild() const { return mChildList.begin(); } - child_list_const_iter_t endChild() const { return mChildList.end(); } - - // LLMouseHandler functions - // Default behavior is to pass events to children - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); - - /*virtual*/ const std::string& getName() const; - /*virtual*/ void onMouseCaptureLost(); - /*virtual*/ BOOL hasMouseCapture(); - /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; - /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; - - virtual LLView* childFromPoint(S32 x, S32 y, bool recur=false); - - // view-specific handlers - virtual void onMouseEnter(S32 x, S32 y, MASK mask); - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - - std::string getPathname() const; - // static method handles NULL pointer too - static std::string getPathname(const LLView*); - - template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const - { - LLView* child = findChildView(name, recurse); - T* result = dynamic_cast<T*>(child); - return result; - } - - template <class T> T* getChild(const std::string& name, BOOL recurse = TRUE) const; - - template <class T> T& getChildRef(const std::string& name, BOOL recurse = TRUE) const - { - return *getChild<T>(name, recurse); - } - - virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; - virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; - - template <class T> T* getDefaultWidget(const std::string& name) const - { - LLView* widgetp = getDefaultWidgetContainer().findChildView(name); - return dynamic_cast<T*>(widgetp); - } - - template <class T> T* getParentByType() const - { - LLView* parent = getParent(); - while(parent) - { - if (dynamic_cast<T*>(parent)) - { - return static_cast<T*>(parent); - } - parent = parent->getParent(); - } - return NULL; - } - - ////////////////////////////////////////////// - // statics - ////////////////////////////////////////////// - //static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node); - - // focuses the item in the list after the currently-focused item, wrapping if necessary - static BOOL focusNext(LLView::child_list_t & result); - // focuses the item in the list before the currently-focused item, wrapping if necessary - static BOOL focusPrev(LLView::child_list_t & result); - - // returns query for iterating over controls in tab order - static const LLViewQuery & getTabOrderQuery(); - // return query for iterating over focus roots in tab order - static const LLViewQuery & getFocusRootsQuery(); - - static LLWindow* getWindow(void) { return LLUI::getInstance()->mWindow; } - - // Set up params after XML load before calling new(), - // usually to adjust layout. - static void applyXUILayout(Params& p, LLView* parent, LLRect layout_rect = LLRect()); - - // For re-export of floaters and panels, convert the coordinate system - // to be top-left based. - static void setupParamsForExport(Params& p, LLView* parent); - - //virtual BOOL addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; } - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleKeyUpHere(KEY key, MASK mask); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - - virtual void handleReshape(const LLRect& rect, bool by_user); - virtual void dirtyRect(); - - //send custom notification to LLView parent - virtual S32 notifyParent(const LLSD& info); - - //send custom notification to all view childrend - // return true if _any_ children return true. otherwise false. - virtual bool notifyChildren(const LLSD& info); - - //send custom notification to current view - virtual S32 notify(const LLSD& info) { return 0;}; - - static const LLViewDrawContext& getDrawContext(); - - // Returns useful information about this ui widget. - LLSD getInfo(void); + virtual const std::string getToolTip() const; + virtual const std::string& getText() const { return LLStringUtil::null; } + virtual const LLFontGL* getFont() const { return nullptr; } + + void sendChildToFront(LLView* child); + void sendChildToBack(LLView* child); + + virtual bool addChild(LLView* view, S32 tab_group = 0); + + // implemented in terms of addChild() + bool addChildInBack(LLView* view, S32 tab_group = 0); + + // remove the specified child from the view, and set it's parent to NULL. + virtual void removeChild(LLView* view); + + virtual BOOL postBuild() { return TRUE; } + + const child_tab_order_t& getTabOrder() const { return mTabOrder; } + + void setDefaultTabGroup(S32 d) { mDefaultTabGroup = d; } + S32 getDefaultTabGroup() const { return mDefaultTabGroup; } + S32 getLastTabGroup() { return mLastTabGroup; } + + BOOL isInVisibleChain() const; + BOOL isInEnabledChain() const; + + void setFocusRoot(BOOL b) { mIsFocusRoot = b; } + BOOL isFocusRoot() const { return mIsFocusRoot; } + virtual BOOL canFocusChildren() const; + + BOOL focusNextRoot(); + BOOL focusPrevRoot(); + + // Normally we want the app menus to get priority on accelerated keys + // However, sometimes we want to give specific views a first chance + // iat handling them. (eg. the script editor) + virtual bool hasAccelerators() const { return false; }; + + // delete all children. Override this function if you need to + // perform any extra clean up such as cached pointers to selected + // children, etc. + virtual void deleteAllChildren(); + + void setAllChildrenEnabled(BOOL b); + + virtual void setVisible(BOOL visible); + void setVisibleDirect(BOOL visible) { mVisible = visible; } + const BOOL& getVisible() const { return mVisible; } + virtual void setEnabled(BOOL enabled); + BOOL getEnabled() const { return mEnabled; } + /// 'available' in this context means 'visible and enabled': in other + /// words, can a user actually interact with this? + virtual bool isAvailable() const; + /// The static isAvailable() tests an LLView* that could be NULL. + static bool isAvailable(const LLView* view); + U8 getSoundFlags() const { return mSoundFlags; } + + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + + virtual void onVisibilityChange ( BOOL new_visibility ); + virtual void onUpdateScrollToChild(const LLUICtrl * cntrl); + + void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } + void popVisible() { setVisible(mLastVisible); } + BOOL getLastVisible() const { return mLastVisible; } + + U32 getFollows() const { return mReshapeFlags; } + BOOL followsLeft() const { return mReshapeFlags & FOLLOWS_LEFT; } + BOOL followsRight() const { return mReshapeFlags & FOLLOWS_RIGHT; } + BOOL followsTop() const { return mReshapeFlags & FOLLOWS_TOP; } + BOOL followsBottom() const { return mReshapeFlags & FOLLOWS_BOTTOM; } + BOOL followsAll() const { return mReshapeFlags & FOLLOWS_ALL; } + + const LLRect& getRect() const { return mRect; } + const LLRect& getBoundingRect() const { return mBoundingRect; } + LLRect getLocalBoundingRect() const; + LLRect calcScreenRect() const; + LLRect calcScreenBoundingRect() const; + LLRect getLocalRect() const; + virtual LLRect getSnapRect() const; + LLRect getLocalSnapRect() const; + + std::string getLayout() { return mLayout; } + + // Override and return required size for this object. 0 for width/height means don't care. + virtual LLRect getRequiredRect(); + LLRect calcBoundingRect(); + void updateBoundingRect(); + + LLView* getRootView(); + LLView* getParent() const { return mParentView; } + LLView* getFirstChild() const { return (mChildList.empty()) ? NULL : *(mChildList.begin()); } + LLView* findPrevSibling(LLView* child); + LLView* findNextSibling(LLView* child); + S32 getChildCount() const { return (S32)mChildList.size(); } + template<class _Pr3> void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); } + BOOL hasAncestor(const LLView* parentp) const; + BOOL hasChild(const std::string& childname, BOOL recurse = FALSE) const; + BOOL childHasKeyboardFocus( const std::string& childname ) const; + + // these iterators are used for collapsing various tree traversals into for loops + typedef LLTreeDFSIter<LLView, child_list_const_iter_t> tree_iterator_t; + tree_iterator_t beginTreeDFS(); + tree_iterator_t endTreeDFS(); + + typedef LLTreeDFSPostIter<LLView, child_list_const_iter_t> tree_post_iterator_t; + tree_post_iterator_t beginTreeDFSPost(); + tree_post_iterator_t endTreeDFSPost(); + + typedef LLTreeBFSIter<LLView, child_list_const_iter_t> bfs_tree_iterator_t; + bfs_tree_iterator_t beginTreeBFS(); + bfs_tree_iterator_t endTreeBFS(); + + + typedef LLTreeDownIter<LLView> root_to_view_iterator_t; + root_to_view_iterator_t beginRootToView(); + root_to_view_iterator_t endRootToView(); + + // + // UTILITIES + // + + // Default behavior is to use reshape flags to resize child views + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void translate( S32 x, S32 y ); + void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } + BOOL translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); + BOOL translateRectIntoRect( const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); + BOOL translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX); + void centerWithin(const LLRect& bounds); + + void setShape(const LLRect& new_rect, bool by_user = false); + virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); + virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); + virtual BOOL canSnapTo(const LLView* other_view); + virtual void setSnappedTo(const LLView* snap_view); + + // inherited from LLFocusableElement + /* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /* virtual */ BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); + /* virtual */ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + virtual void draw(); + + void parseFollowsFlags(const LLView::Params& params); + + // Some widgets, like close box buttons, don't need to be saved + BOOL getFromXUI() const { return mFromXUI; } + void setFromXUI(BOOL b) { mFromXUI = b; } + + typedef enum e_hit_test_type + { + HIT_TEST_USE_BOUNDING_RECT, + HIT_TEST_IGNORE_BOUNDING_RECT + }EHitTestType; + + BOOL parentPointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const; + BOOL pointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const; + BOOL blockMouseEvent(S32 x, S32 y) const; + + // See LLMouseHandler virtuals for screenPointToLocal and localPointToScreen + BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, const LLView* other_view) const; + BOOL localRectToOtherView( const LLRect& local, LLRect* other, const LLView* other_view ) const; + void screenRectToLocal( const LLRect& screen, LLRect* local ) const; + void localRectToScreen( const LLRect& local, LLRect* screen ) const; + + LLControlVariable *findControl(const std::string& name); + + const child_list_t* getChildList() const { return &mChildList; } + child_list_const_iter_t beginChild() const { return mChildList.begin(); } + child_list_const_iter_t endChild() const { return mChildList.end(); } + + // LLMouseHandler functions + // Default behavior is to pass events to children + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + + /*virtual*/ const std::string& getName() const; + /*virtual*/ void onMouseCaptureLost(); + /*virtual*/ BOOL hasMouseCapture(); + /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; + /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; + + virtual LLView* childFromPoint(S32 x, S32 y, bool recur=false); + + // view-specific handlers + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + std::string getPathname() const; + // static method handles NULL pointer too + static std::string getPathname(const LLView*); + + template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const + { + LLView* child = findChildView(name, recurse); + T* result = dynamic_cast<T*>(child); + return result; + } + + template <class T> T* getChild(const std::string& name, BOOL recurse = TRUE) const; + + template <class T> T& getChildRef(const std::string& name, BOOL recurse = TRUE) const + { + return *getChild<T>(name, recurse); + } + + virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE) const; + virtual LLView* findChildView(const std::string& name, BOOL recurse = TRUE) const; + + template <class T> T* getDefaultWidget(const std::string& name) const + { + LLView* widgetp = getDefaultWidgetContainer().findChildView(name); + return dynamic_cast<T*>(widgetp); + } + + template <class T> T* getParentByType() const + { + LLView* parent = getParent(); + while(parent) + { + if (dynamic_cast<T*>(parent)) + { + return static_cast<T*>(parent); + } + parent = parent->getParent(); + } + return NULL; + } + + ////////////////////////////////////////////// + // statics + ////////////////////////////////////////////// + //static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node); + + // focuses the item in the list after the currently-focused item, wrapping if necessary + static BOOL focusNext(LLView::child_list_t & result); + // focuses the item in the list before the currently-focused item, wrapping if necessary + static BOOL focusPrev(LLView::child_list_t & result); + + // returns query for iterating over controls in tab order + static const LLViewQuery & getTabOrderQuery(); + // return query for iterating over focus roots in tab order + static const LLViewQuery & getFocusRootsQuery(); + + static LLWindow* getWindow(void) { return LLUI::getInstance()->mWindow; } + + // Set up params after XML load before calling new(), + // usually to adjust layout. + static void applyXUILayout(Params& p, LLView* parent, LLRect layout_rect = LLRect()); + + // For re-export of floaters and panels, convert the coordinate system + // to be top-left based. + static void setupParamsForExport(Params& p, LLView* parent); + + //virtual BOOL addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; } + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleKeyUpHere(KEY key, MASK mask); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); + + virtual void handleReshape(const LLRect& rect, bool by_user); + virtual void dirtyRect(); + + //send custom notification to LLView parent + virtual S32 notifyParent(const LLSD& info); + + //send custom notification to all view childrend + // return true if _any_ children return true. otherwise false. + virtual bool notifyChildren(const LLSD& info); + + //send custom notification to current view + virtual S32 notify(const LLSD& info) { return 0;}; + + static const LLViewDrawContext& getDrawContext(); + + // Returns useful information about this ui widget. + LLSD getInfo(void); protected: - void drawDebugRect(); - void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); - void drawChildren(); - bool visibleAndContains(S32 local_x, S32 local_Y); - bool visibleEnabledAndContains(S32 local_x, S32 local_y); - void logMouseEvent(); - - LLView* childrenHandleKey(KEY key, MASK mask); - LLView* childrenHandleKeyUp(KEY key, MASK mask); - LLView* childrenHandleUnicodeChar(llwchar uni_char); - LLView* childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType type, - void* data, - EAcceptance* accept, - std::string& tooltip_msg); - - LLView* childrenHandleHover(S32 x, S32 y, MASK mask); - LLView* childrenHandleMouseUp(S32 x, S32 y, MASK mask); - LLView* childrenHandleMouseDown(S32 x, S32 y, MASK mask); - LLView* childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask); - LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); - LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); - LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); - LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks); - LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); - LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); - LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask); - - ECursorType mHoverCursor; - - virtual void addInfo(LLSD & info); + void drawDebugRect(); + void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); + void drawChildren(); + bool visibleAndContains(S32 local_x, S32 local_Y); + bool visibleEnabledAndContains(S32 local_x, S32 local_y); + void logMouseEvent(); + + LLView* childrenHandleKey(KEY key, MASK mask); + LLView* childrenHandleKeyUp(KEY key, MASK mask); + LLView* childrenHandleUnicodeChar(llwchar uni_char); + LLView* childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType type, + void* data, + EAcceptance* accept, + std::string& tooltip_msg); + + LLView* childrenHandleHover(S32 x, S32 y, MASK mask); + LLView* childrenHandleMouseUp(S32 x, S32 y, MASK mask); + LLView* childrenHandleMouseDown(S32 x, S32 y, MASK mask); + LLView* childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask); + LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); + LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); + LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); + LLView* childrenHandleScrollHWheel(S32 x, S32 y, S32 clicks); + LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); + LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); + LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask); + + ECursorType mHoverCursor; + + virtual void addInfo(LLSD & info); private: - template <typename METHOD, typename XDATA> - LLView* childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block = true); + template <typename METHOD, typename XDATA> + LLView* childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block = true); + + template <typename METHOD, typename CHARTYPE> + LLView* childrenHandleCharEvent(const std::string& desc, const METHOD& method, + CHARTYPE c, MASK mask); + + // adapter to blur distinction between handleKey() and handleUnicodeChar() + // for childrenHandleCharEvent() + BOOL handleUnicodeCharWithDummyMask(llwchar uni_char, MASK /* dummy */, BOOL from_parent) + { + return handleUnicodeChar(uni_char, from_parent); + } - template <typename METHOD, typename CHARTYPE> - LLView* childrenHandleCharEvent(const std::string& desc, const METHOD& method, - CHARTYPE c, MASK mask); + LLView* mParentView; + child_list_t mChildList; - // adapter to blur distinction between handleKey() and handleUnicodeChar() - // for childrenHandleCharEvent() - BOOL handleUnicodeCharWithDummyMask(llwchar uni_char, MASK /* dummy */, BOOL from_parent) - { - return handleUnicodeChar(uni_char, from_parent); - } + // location in pixels, relative to surrounding structure, bottom,left=0,0 + BOOL mVisible; + LLRect mRect; + LLRect mBoundingRect; - LLView* mParentView; - child_list_t mChildList; + std::string mLayout; + std::string mName; - // location in pixels, relative to surrounding structure, bottom,left=0,0 - BOOL mVisible; - LLRect mRect; - LLRect mBoundingRect; - - std::string mLayout; - std::string mName; - - U32 mReshapeFlags; + U32 mReshapeFlags; - child_tab_order_t mTabOrder; - S32 mDefaultTabGroup; - S32 mLastTabGroup; + child_tab_order_t mTabOrder; + S32 mDefaultTabGroup; + S32 mLastTabGroup; - BOOL mEnabled; // Enabled means "accepts input that has an effect on the state of the application." - // A disabled view, for example, may still have a scrollbar that responds to mouse events. - BOOL mMouseOpaque; // Opaque views handle all mouse events that are over their rect. - LLUIString mToolTipMsg; // isNull() is true if none. + BOOL mEnabled; // Enabled means "accepts input that has an effect on the state of the application." + // A disabled view, for example, may still have a scrollbar that responds to mouse events. + BOOL mMouseOpaque; // Opaque views handle all mouse events that are over their rect. + LLUIString mToolTipMsg; // isNull() is true if none. - U8 mSoundFlags; - BOOL mFromXUI; + U8 mSoundFlags; + BOOL mFromXUI; - BOOL mIsFocusRoot; - BOOL mUseBoundingRect; // hit test against bounding rectangle that includes all child elements + BOOL mIsFocusRoot; + BOOL mUseBoundingRect; // hit test against bounding rectangle that includes all child elements - BOOL mLastVisible; + BOOL mLastVisible; - bool mInDraw; + bool mInDraw; - static LLWindow* sWindow; // All root views must know about their window. + static LLWindow* sWindow; // All root views must know about their window. - typedef std::map<std::string, LLView*> default_widget_map_t; - // allocate this map no demand, as it is rarely needed - mutable LLView* mDefaultWidgets; + typedef std::map<std::string, LLView*> default_widget_map_t; + // allocate this map no demand, as it is rarely needed + mutable LLView* mDefaultWidgets; - LLView& getDefaultWidgetContainer() const; + LLView& getDefaultWidgetContainer() const; - // This allows special mouse-event targeting logic for testing. - typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc; - static DrilldownFunc sDrilldown; + // This allows special mouse-event targeting logic for testing. + typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc; + static DrilldownFunc sDrilldown; public: - // This is the only public accessor to alter sDrilldown. This is not - // an accident. The intended usage pattern is like: - // { - // LLView::TemporaryDrilldownFunc scoped_func(myfunctor); - // // ... test with myfunctor ... - // } // exiting block restores original LLView::sDrilldown - class TemporaryDrilldownFunc: public boost::noncopyable - { - public: - TemporaryDrilldownFunc(const DrilldownFunc& func): - mOldDrilldown(sDrilldown) - { - sDrilldown = func; - } - - ~TemporaryDrilldownFunc() - { - sDrilldown = mOldDrilldown; - } - - private: - DrilldownFunc mOldDrilldown; - }; - - // Depth in view hierarchy during rendering - static S32 sDepth; - - // Draw debug rectangles around widgets to help with alignment and spacing - static bool sDebugRects; - - // Show hexadecimal byte values of unicode symbols in a tooltip - static bool sDebugUnicode; - - // Show camera position and direction in Camera Controls floater - static bool sDebugCamera; - - static bool sIsRectDirty; - static LLRect sDirtyRect; - - // Draw widget names and sizes when drawing debug rectangles, turning this - // off is useful to make the rectangles themselves easier to see. - static bool sDebugRectsShowNames; - - static bool sDebugKeys; - static bool sDebugMouseHandling; - static std::string sMouseHandlerMessage; - static S32 sSelectID; - static std::set<LLView*> sPreviewHighlightedElements; // DEV-16869 - static BOOL sHighlightingDiffs; // DEV-16869 - static LLView* sPreviewClickedElement; // DEV-16869 - static BOOL sDrawPreviewHighlights; - static S32 sLastLeftXML; - static S32 sLastBottomXML; - static BOOL sForceReshape; + // This is the only public accessor to alter sDrilldown. This is not + // an accident. The intended usage pattern is like: + // { + // LLView::TemporaryDrilldownFunc scoped_func(myfunctor); + // // ... test with myfunctor ... + // } // exiting block restores original LLView::sDrilldown + class TemporaryDrilldownFunc: public boost::noncopyable + { + public: + TemporaryDrilldownFunc(const DrilldownFunc& func): + mOldDrilldown(sDrilldown) + { + sDrilldown = func; + } + + ~TemporaryDrilldownFunc() + { + sDrilldown = mOldDrilldown; + } + + private: + DrilldownFunc mOldDrilldown; + }; + + // Depth in view hierarchy during rendering + static S32 sDepth; + + // Draw debug rectangles around widgets to help with alignment and spacing + static bool sDebugRects; + + // Show hexadecimal byte values of unicode symbols in a tooltip + static bool sDebugUnicode; + + // Show camera position and direction in Camera Controls floater + static bool sDebugCamera; + + static bool sIsRectDirty; + static LLRect sDirtyRect; + + // Draw widget names and sizes when drawing debug rectangles, turning this + // off is useful to make the rectangles themselves easier to see. + static bool sDebugRectsShowNames; + + static bool sDebugKeys; + static bool sDebugMouseHandling; + static std::string sMouseHandlerMessage; + static S32 sSelectID; + static std::set<LLView*> sPreviewHighlightedElements; // DEV-16869 + static BOOL sHighlightingDiffs; // DEV-16869 + static LLView* sPreviewClickedElement; // DEV-16869 + static BOOL sDrawPreviewHighlights; + static S32 sLastLeftXML; + static S32 sLastBottomXML; + static BOOL sForceReshape; }; namespace LLInitParam @@ -690,46 +692,46 @@ namespace LLInitParam template<> struct TypeValues<LLView::EOrientation> : public LLInitParam::TypeValuesHelper<LLView::EOrientation> { - static void declareValues(); + static void declareValues(); }; } template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) const { - LLView* child = findChildView(name, recurse); - T* result = dynamic_cast<T*>(child); - if (!result) - { - // did we find *something* with that name? - if (child) - { - LL_WARNS() << "Found child named \"" << name << "\" but of wrong type " << typeid(*child).name() << ", expecting " << typeid(T*).name() << LL_ENDL; - } - result = getDefaultWidget<T>(name); - if (!result) - { - result = LLUICtrlFactory::getDefaultWidget<T>(name); - if (!result) - { - LL_ERRS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL; - } - - // *NOTE: You cannot call mFoo = getChild<LLFoo>("bar") - // in a floater or panel constructor. The widgets will not - // be ready. Instead, put it in postBuild(). - LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; - - getDefaultWidgetContainer().addChild(result); - } - } - return result; + LLView* child = findChildView(name, recurse); + T* result = dynamic_cast<T*>(child); + if (!result) + { + // did we find *something* with that name? + if (child) + { + LL_WARNS() << "Found child named \"" << name << "\" but of wrong type " << typeid(*child).name() << ", expecting " << typeid(T*).name() << LL_ENDL; + } + result = getDefaultWidget<T>(name); + if (!result) + { + result = LLUICtrlFactory::getDefaultWidget<T>(name); + if (!result) + { + LL_ERRS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL; + } + + // *NOTE: You cannot call mFoo = getChild<LLFoo>("bar") + // in a floater or panel constructor. The widgets will not + // be ready. Instead, put it in postBuild(). + LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; + + getDefaultWidgetContainer().addChild(result); + } + } + return result; } // Compiler optimization - don't generate these specializations inline, // require explicit specialization. See llbutton.cpp for an example. #ifndef LLVIEW_CPP extern template class LLView* LLView::getChild<class LLView>( - const std::string& name, BOOL recurse) const; + const std::string& name, BOOL recurse) const; #endif #endif //LL_LLVIEW_H diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp index 919267dcc6..47cc57e42f 100644 --- a/indra/llui/llviewborder.cpp +++ b/indra/llui/llviewborder.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llviewborder.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,237 +34,237 @@ static LLDefaultChildRegistry::Register<LLViewBorder> r("view_border"); void LLViewBorder::BevelValues::declareValues() { - declare("in", LLViewBorder::BEVEL_IN); - declare("out", LLViewBorder::BEVEL_OUT); - declare("bright", LLViewBorder::BEVEL_BRIGHT); - declare("none", LLViewBorder::BEVEL_NONE); + declare("in", LLViewBorder::BEVEL_IN); + declare("out", LLViewBorder::BEVEL_OUT); + declare("bright", LLViewBorder::BEVEL_BRIGHT); + declare("none", LLViewBorder::BEVEL_NONE); } void LLViewBorder::StyleValues::declareValues() { - declare("line", LLViewBorder::STYLE_LINE); - declare("texture", LLViewBorder::STYLE_TEXTURE); + declare("line", LLViewBorder::STYLE_LINE); + declare("texture", LLViewBorder::STYLE_TEXTURE); } LLViewBorder::Params::Params() -: bevel_style("bevel_style", BEVEL_OUT), - render_style("border_style", STYLE_LINE), - border_thickness("border_thickness"), - highlight_light_color("highlight_light_color"), - highlight_dark_color("highlight_dark_color"), - shadow_light_color("shadow_light_color"), - shadow_dark_color("shadow_dark_color") +: bevel_style("bevel_style", BEVEL_OUT), + render_style("border_style", STYLE_LINE), + border_thickness("border_thickness"), + highlight_light_color("highlight_light_color"), + highlight_dark_color("highlight_dark_color"), + shadow_light_color("shadow_light_color"), + shadow_dark_color("shadow_dark_color") { - addSynonym(border_thickness, "thickness"); - addSynonym(render_style, "style"); + addSynonym(border_thickness, "thickness"); + addSynonym(render_style, "style"); } LLViewBorder::LLViewBorder(const LLViewBorder::Params& p) -: LLView(p), - mTexture( NULL ), - mHasKeyboardFocus( FALSE ), - mBorderWidth(p.border_thickness), - mHighlightLight(p.highlight_light_color()), - mHighlightDark(p.highlight_dark_color()), - mShadowLight(p.shadow_light_color()), - mShadowDark(p.shadow_dark_color()), - mBevel(p.bevel_style), - mStyle(p.render_style) +: LLView(p), + mTexture( NULL ), + mHasKeyboardFocus( FALSE ), + mBorderWidth(p.border_thickness), + mHighlightLight(p.highlight_light_color()), + mHighlightDark(p.highlight_dark_color()), + mShadowLight(p.shadow_light_color()), + mShadowDark(p.shadow_dark_color()), + mBevel(p.bevel_style), + mStyle(p.render_style) {} void LLViewBorder::setColors( const LLColor4& shadow_dark, const LLColor4& highlight_light ) { - mShadowDark = shadow_dark; - mHighlightLight = highlight_light; + mShadowDark = shadow_dark; + mHighlightLight = highlight_light; } void LLViewBorder::setColorsExtended( const LLColor4& shadow_light, const LLColor4& shadow_dark, - const LLColor4& highlight_light, const LLColor4& highlight_dark ) + const LLColor4& highlight_light, const LLColor4& highlight_dark ) { - mShadowDark = shadow_dark; - mShadowLight = shadow_light; - mHighlightLight = highlight_light; - mHighlightDark = highlight_dark; + mShadowDark = shadow_dark; + mShadowLight = shadow_light; + mHighlightLight = highlight_light; + mHighlightDark = highlight_dark; } void LLViewBorder::setTexture( const LLUUID &image_id ) { - mTexture = LLUI::getUIImageByID(image_id); + mTexture = LLUI::getUIImageByID(image_id); } void LLViewBorder::draw() { - if( STYLE_LINE == mStyle ) - { - if( 0 == mBorderWidth ) - { - // no visible border - } - else - if( 1 == mBorderWidth ) - { - drawOnePixelLines(); - } - else - if( 2 == mBorderWidth ) - { - drawTwoPixelLines(); - } - else - { - llassert( FALSE ); // not implemented - } - } - - LLView::draw(); + if( STYLE_LINE == mStyle ) + { + if( 0 == mBorderWidth ) + { + // no visible border + } + else + if( 1 == mBorderWidth ) + { + drawOnePixelLines(); + } + else + if( 2 == mBorderWidth ) + { + drawTwoPixelLines(); + } + else + { + llassert( FALSE ); // not implemented + } + } + + LLView::draw(); } void LLViewBorder::drawOnePixelLines() { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLColor4 top_color = mHighlightLight.get(); - LLColor4 bottom_color = mHighlightLight.get(); - switch( mBevel ) - { - case BEVEL_OUT: - top_color = mHighlightLight.get(); - bottom_color = mShadowDark.get(); - break; - case BEVEL_IN: - top_color = mShadowDark.get(); - bottom_color = mHighlightLight.get(); - break; - case BEVEL_NONE: - // use defaults - break; - default: - llassert(0); - } - - if( mHasKeyboardFocus ) - { - top_color = gFocusMgr.getFocusColor(); - bottom_color = top_color; - - LLUI::setLineWidth(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())); - } - - S32 left = 0; - S32 top = getRect().getHeight(); - S32 right = getRect().getWidth(); - S32 bottom = 0; - - gGL.color4fv( top_color.mV ); - gl_line_2d(left, bottom, left, top); - gl_line_2d(left, top, right, top); - - gGL.color4fv( bottom_color.mV ); - gl_line_2d(right, top, right, bottom); - gl_line_2d(left, bottom, right, bottom); - - LLUI::setLineWidth(1.f); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLColor4 top_color = mHighlightLight.get(); + LLColor4 bottom_color = mHighlightLight.get(); + switch( mBevel ) + { + case BEVEL_OUT: + top_color = mHighlightLight.get(); + bottom_color = mShadowDark.get(); + break; + case BEVEL_IN: + top_color = mShadowDark.get(); + bottom_color = mHighlightLight.get(); + break; + case BEVEL_NONE: + // use defaults + break; + default: + llassert(0); + } + + if( mHasKeyboardFocus ) + { + top_color = gFocusMgr.getFocusColor(); + bottom_color = top_color; + + LLUI::setLineWidth(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())); + } + + S32 left = 0; + S32 top = getRect().getHeight(); + S32 right = getRect().getWidth(); + S32 bottom = 0; + + gGL.color4fv( top_color.mV ); + gl_line_2d(left, bottom, left, top); + gl_line_2d(left, top, right, top); + + gGL.color4fv( bottom_color.mV ); + gl_line_2d(right, top, right, bottom); + gl_line_2d(left, bottom, right, bottom); + + LLUI::setLineWidth(1.f); } void LLViewBorder::drawTwoPixelLines() { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLColor4 focus_color = gFocusMgr.getFocusColor(); - - LLColor4 top_in_color; - LLColor4 top_out_color; - LLColor4 bottom_in_color; - LLColor4 bottom_out_color; - - switch( mBevel ) - { - case BEVEL_OUT: - top_in_color = mHighlightLight.get(); - top_out_color = mHighlightDark.get(); - bottom_in_color = mShadowLight.get(); - bottom_out_color = mShadowDark.get(); - break; - case BEVEL_IN: - top_in_color = mShadowDark.get(); - top_out_color = mShadowLight.get(); - bottom_in_color = mHighlightDark.get(); - bottom_out_color = mHighlightLight.get(); - break; - case BEVEL_BRIGHT: - top_in_color = mHighlightLight.get(); - top_out_color = mHighlightLight.get(); - bottom_in_color = mHighlightLight.get(); - bottom_out_color = mHighlightLight.get(); - break; - case BEVEL_NONE: - top_in_color = mShadowDark.get(); - top_out_color = mShadowDark.get(); - bottom_in_color = mShadowDark.get(); - bottom_out_color = mShadowDark.get(); - // use defaults - break; - default: - llassert(0); - } - - if( mHasKeyboardFocus ) - { - top_out_color = focus_color; - bottom_out_color = focus_color; - } - - S32 left = 0; - S32 top = getRect().getHeight(); - S32 right = getRect().getWidth(); - S32 bottom = 0; - - // draw borders - gGL.color3fv( top_out_color.mV ); - gl_line_2d(left, bottom, left, top-1); - gl_line_2d(left, top-1, right, top-1); - - gGL.color3fv( top_in_color.mV ); - gl_line_2d(left+1, bottom+1, left+1, top-2); - gl_line_2d(left+1, top-2, right-1, top-2); - - gGL.color3fv( bottom_out_color.mV ); - gl_line_2d(right-1, top-1, right-1, bottom); - gl_line_2d(left, bottom, right, bottom); - - gGL.color3fv( bottom_in_color.mV ); - gl_line_2d(right-2, top-2, right-2, bottom+1); - gl_line_2d(left+1, bottom+1, right-1, bottom+1); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLColor4 focus_color = gFocusMgr.getFocusColor(); + + LLColor4 top_in_color; + LLColor4 top_out_color; + LLColor4 bottom_in_color; + LLColor4 bottom_out_color; + + switch( mBevel ) + { + case BEVEL_OUT: + top_in_color = mHighlightLight.get(); + top_out_color = mHighlightDark.get(); + bottom_in_color = mShadowLight.get(); + bottom_out_color = mShadowDark.get(); + break; + case BEVEL_IN: + top_in_color = mShadowDark.get(); + top_out_color = mShadowLight.get(); + bottom_in_color = mHighlightDark.get(); + bottom_out_color = mHighlightLight.get(); + break; + case BEVEL_BRIGHT: + top_in_color = mHighlightLight.get(); + top_out_color = mHighlightLight.get(); + bottom_in_color = mHighlightLight.get(); + bottom_out_color = mHighlightLight.get(); + break; + case BEVEL_NONE: + top_in_color = mShadowDark.get(); + top_out_color = mShadowDark.get(); + bottom_in_color = mShadowDark.get(); + bottom_out_color = mShadowDark.get(); + // use defaults + break; + default: + llassert(0); + } + + if( mHasKeyboardFocus ) + { + top_out_color = focus_color; + bottom_out_color = focus_color; + } + + S32 left = 0; + S32 top = getRect().getHeight(); + S32 right = getRect().getWidth(); + S32 bottom = 0; + + // draw borders + gGL.color3fv( top_out_color.mV ); + gl_line_2d(left, bottom, left, top-1); + gl_line_2d(left, top-1, right, top-1); + + gGL.color3fv( top_in_color.mV ); + gl_line_2d(left+1, bottom+1, left+1, top-2); + gl_line_2d(left+1, top-2, right-1, top-2); + + gGL.color3fv( bottom_out_color.mV ); + gl_line_2d(right-1, top-1, right-1, bottom); + gl_line_2d(left, bottom, right, bottom); + + gGL.color3fv( bottom_in_color.mV ); + gl_line_2d(right-2, top-2, right-2, bottom+1); + gl_line_2d(left+1, bottom+1, right-1, bottom+1); } BOOL LLViewBorder::getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel& bevel_style) { - if (node->hasAttribute("bevel_style")) - { - std::string bevel_string; - node->getAttributeString("bevel_style", bevel_string); - LLStringUtil::toLower(bevel_string); - - if (bevel_string == "none") - { - bevel_style = LLViewBorder::BEVEL_NONE; - } - else if (bevel_string == "in") - { - bevel_style = LLViewBorder::BEVEL_IN; - } - else if (bevel_string == "out") - { - bevel_style = LLViewBorder::BEVEL_OUT; - } - else if (bevel_string == "bright") - { - bevel_style = LLViewBorder::BEVEL_BRIGHT; - } - return TRUE; - } - return FALSE; + if (node->hasAttribute("bevel_style")) + { + std::string bevel_string; + node->getAttributeString("bevel_style", bevel_string); + LLStringUtil::toLower(bevel_string); + + if (bevel_string == "none") + { + bevel_style = LLViewBorder::BEVEL_NONE; + } + else if (bevel_string == "in") + { + bevel_style = LLViewBorder::BEVEL_IN; + } + else if (bevel_string == "out") + { + bevel_style = LLViewBorder::BEVEL_OUT; + } + else if (bevel_string == "bright") + { + bevel_style = LLViewBorder::BEVEL_BRIGHT; + } + return TRUE; + } + return FALSE; } diff --git a/indra/llui/llviewborder.h b/indra/llui/llviewborder.h index 413ce39744..2ee25fff1a 100644 --- a/indra/llui/llviewborder.h +++ b/indra/llui/llviewborder.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewborder.h * @brief A customizable decorative border. Does not interact with mouse events. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,78 +32,78 @@ class LLViewBorder : public LLView { public: - typedef enum e_bevel { BEVEL_IN, BEVEL_OUT, BEVEL_BRIGHT, BEVEL_NONE } EBevel ; - typedef enum e_style { STYLE_LINE, STYLE_TEXTURE } EStyle; - - struct BevelValues - : public LLInitParam::TypeValuesHelper<LLViewBorder::EBevel, BevelValues> - { - static void declareValues(); - }; - - struct StyleValues - : public LLInitParam::TypeValuesHelper<LLViewBorder::EStyle, StyleValues> - { - static void declareValues(); - }; - - struct Params : public LLInitParam::Block<Params, LLView::Params> - { - Optional<EBevel, BevelValues> bevel_style; - Optional<EStyle, StyleValues> render_style; - Optional<S32> border_thickness; - - Optional<LLUIColor> highlight_light_color, - highlight_dark_color, - shadow_light_color, - shadow_dark_color; - - Params(); - }; + typedef enum e_bevel { BEVEL_IN, BEVEL_OUT, BEVEL_BRIGHT, BEVEL_NONE } EBevel ; + typedef enum e_style { STYLE_LINE, STYLE_TEXTURE } EStyle; + + struct BevelValues + : public LLInitParam::TypeValuesHelper<LLViewBorder::EBevel, BevelValues> + { + static void declareValues(); + }; + + struct StyleValues + : public LLInitParam::TypeValuesHelper<LLViewBorder::EStyle, StyleValues> + { + static void declareValues(); + }; + + struct Params : public LLInitParam::Block<Params, LLView::Params> + { + Optional<EBevel, BevelValues> bevel_style; + Optional<EStyle, StyleValues> render_style; + Optional<S32> border_thickness; + + Optional<LLUIColor> highlight_light_color, + highlight_dark_color, + shadow_light_color, + shadow_dark_color; + + Params(); + }; protected: - LLViewBorder(const Params&); - friend class LLUICtrlFactory; + LLViewBorder(const Params&); + friend class LLUICtrlFactory; public: - virtual void setValue(const LLSD& val) { setRect(LLRect(val)); } + virtual void setValue(const LLSD& val) { setRect(LLRect(val)); } + + virtual BOOL isCtrl() const { return FALSE; } - virtual BOOL isCtrl() const { return FALSE; } + // llview functionality + virtual void draw(); - // llview functionality - virtual void draw(); - - static BOOL getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel& bevel_style); + static BOOL getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel& bevel_style); - void setBorderWidth(S32 width) { mBorderWidth = width; } - S32 getBorderWidth() const { return mBorderWidth; } - void setBevel(EBevel bevel) { mBevel = bevel; } - EBevel getBevel() const { return mBevel; } - void setColors( const LLColor4& shadow_dark, const LLColor4& highlight_light ); - void setColorsExtended( const LLColor4& shadow_light, const LLColor4& shadow_dark, - const LLColor4& highlight_light, const LLColor4& highlight_dark ); - void setTexture( const class LLUUID &image_id ); + void setBorderWidth(S32 width) { mBorderWidth = width; } + S32 getBorderWidth() const { return mBorderWidth; } + void setBevel(EBevel bevel) { mBevel = bevel; } + EBevel getBevel() const { return mBevel; } + void setColors( const LLColor4& shadow_dark, const LLColor4& highlight_light ); + void setColorsExtended( const LLColor4& shadow_light, const LLColor4& shadow_dark, + const LLColor4& highlight_light, const LLColor4& highlight_dark ); + void setTexture( const class LLUUID &image_id ); - LLColor4 getHighlightLight() {return mHighlightLight.get();} - LLColor4 getShadowDark() {return mHighlightDark.get();} + LLColor4 getHighlightLight() {return mHighlightLight.get();} + LLColor4 getShadowDark() {return mHighlightDark.get();} - EStyle getStyle() const { return mStyle; } + EStyle getStyle() const { return mStyle; } - void setKeyboardFocusHighlight( BOOL b ) { mHasKeyboardFocus = b; } + void setKeyboardFocusHighlight( BOOL b ) { mHasKeyboardFocus = b; } private: - void drawOnePixelLines(); - void drawTwoPixelLines(); - void drawTextures(); - - EBevel mBevel; - EStyle mStyle; - LLUIColor mHighlightLight; - LLUIColor mHighlightDark; - LLUIColor mShadowLight; - LLUIColor mShadowDark; - LLUIColor mBackgroundColor; - S32 mBorderWidth; - LLPointer<LLUIImage> mTexture; - BOOL mHasKeyboardFocus; + void drawOnePixelLines(); + void drawTwoPixelLines(); + void drawTextures(); + + EBevel mBevel; + EStyle mStyle; + LLUIColor mHighlightLight; + LLUIColor mHighlightDark; + LLUIColor mShadowLight; + LLUIColor mShadowDark; + LLUIColor mBackgroundColor; + S32 mBorderWidth; + LLPointer<LLUIImage> mTexture; + BOOL mHasKeyboardFocus; }; #endif // LL_LLVIEWBORDER_H diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index cb000aef74..8154a98b85 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -3,22 +3,22 @@ * @brief Viewer event recording and playback support for mouse and keyboard events * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * + * * Copyright (c) 2013, Linden Research, Inc. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ LLViewerEventRecorder::LLViewerEventRecorder() { // Remove any previous event log file std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old"); LLFile::remove(old_log_ui_events_to_llsd_file, ENOENT); - + mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd"); LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file, ENOENT); @@ -52,7 +52,7 @@ void LLViewerEventRecorder::setEventLoggingOn() { if (! mLog.is_open()) { mLog.open(mLogFilename.c_str(), std::ios_base::out); } - logEvents=true; + logEvents=true; LL_DEBUGS() << "LLViewerEventRecorder::setEventLoggingOn event logging turned on" << LL_ENDL; } @@ -83,7 +83,7 @@ void LLViewerEventRecorder::clear(S32 r) { global_x=r; global_y=r; - + } @@ -115,9 +115,9 @@ void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 g this->global_y=global_y; // ONLY record deepest xui path for hierarchy searches - or first/only xui for floaters/panels reached via mouse captor - and llmousehandler - if (mName!="" && mName!="/" && xui=="") { - // xui=std::string("/")+mName+xui; - //xui=mName+xui; + if (mName!="" && mName!="/" && xui=="") { + // xui=std::string("/")+mName+xui; + //xui=mName+xui; xui = mName; // TODO review confirm we never call with partial path - also cAN REMOVE CHECK FOR "" - ON OTHER HAND IT'S PRETTY HARMLESS } @@ -148,7 +148,7 @@ void LLViewerEventRecorder::logVisibilityChange(std::string xui, std::string nam event.insert("path",LLSD(xui)); } - event.insert("timestamp",LLSD(LLDate::now().asString())); + event.insert("timestamp",LLSD(LLDate::now().asString())); recordEvent(event); } @@ -181,7 +181,7 @@ void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) { // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might // break the test script and it would be useful to have more context to make these sorts of edits safer - + // TODO replace this with a call which extracts to an array of names of masks (just like vita expects during playback) // This is looking more and more like an object is a good idea, for this part a handy method call to setMask(mask) would be nice :-) // call the func - llkeyboard::llsdStringarrayFromMask @@ -193,11 +193,11 @@ void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) { if (mask & MASK_SHIFT) { key_mask.append(LLSD("SHIFT")); } if (mask & MASK_MAC_CONTROL) { key_mask.append(LLSD("MAC_CONTROL")); } - event.insert("mask",key_mask); - event.insert("timestamp",LLSD(LLDate::now().asString())); + event.insert("mask",key_mask); + event.insert("timestamp",LLSD(LLDate::now().asString())); - // Although vita has keyDown and keyUp requests it does not have type as a high-level concept - // (maybe it should) - instead it has a convenience method that generates the keydown and keyup events + // Although vita has keyDown and keyUp requests it does not have type as a high-level concept + // (maybe it should) - instead it has a convenience method that generates the keydown and keyup events // Here we will use "type" as our event type LL_DEBUGS() << "LLVIewerEventRecorder::logKeyEvent Serialized LLSD for event " << event.asString() << "\n" << LL_ENDL; @@ -217,17 +217,17 @@ void LLViewerEventRecorder::playbackRecording() { // ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer LeapCommand =LLUI::getInstance()->mSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand"); - + LL_DEBUGS() << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << LL_ENDL; LLLeap::create("", LeapCommand, false); // exception=false - + } void LLViewerEventRecorder::recordEvent(LLSD event) { LL_DEBUGS() << "LLViewerEventRecorder::recordEvent event written to log: " << LLSDXMLStreamer(event) << LL_ENDL; mLog << event << std::endl; - + } void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { if (! logEvents) return; @@ -238,16 +238,16 @@ void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { event.insert("timestamp",LLSD(LLDate::now().asString())); - + // keysym ...or // keycode...or // char LL_DEBUGS() << "Wrapped in conversion to wstring " << wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << LL_ENDL; - + event.insert("char", - LLSD( wstring_to_utf8str(LLWString( 1,uni_char)) ) - ); + LLSD( wstring_to_utf8str(LLWString( 1,uni_char)) ) + ); // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might @@ -255,7 +255,7 @@ void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { // TODO need to consider mask keys too? Doesn't seem possible - at least not easily at this point - event.insert("event",LLSD("keyDown")); + event.insert("event",LLSD("keyDown")); LL_DEBUGS() << "[VITA] unicode key: " << uni_char << LL_ENDL; LL_DEBUGS() << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << LL_ENDL; @@ -267,7 +267,7 @@ void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string button_name) { - if (! logEvents) return; + if (! logEvents) return; LLSD event=LLSD::emptyMap(); @@ -286,11 +286,11 @@ void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string b event.insert("global_x",LLSD(global_x)); event.insert("global_y",LLSD(global_y)); } - event.insert("timestamp",LLSD(LLDate::now().asString())); + event.insert("timestamp",LLSD(LLDate::now().asString())); recordEvent(event); clear(UNDEFINED); - + } diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h index 6170005b2b..8c41d306ca 100644 --- a/indra/llui/llviewereventrecorder.h +++ b/indra/llui/llviewereventrecorder.h @@ -3,22 +3,22 @@ * @brief Viewer event recording and playback support for mouse and keyboard events * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * + * * Copyright (c) 2013, Linden Research, Inc. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,10 +27,10 @@ #define LL_VIEWER_EVENT_RECORDER -#include "linden_common.h" +#include "linden_common.h" -#include "lldir.h" -#include "llsd.h" +#include "lldir.h" +#include "llsd.h" #include "llfile.h" #include "lldate.h" #include "llsdserialize.h" @@ -46,7 +46,7 @@ class LLViewerEventRecorder : public LLSimpleton<LLViewerEventRecorder> public: LLViewerEventRecorder(); ~LLViewerEventRecorder(); - + void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y, std::string mName); void setMouseLocalCoords(S32 x,S32 y); void setMouseGlobalCoords(S32 x,S32 y); @@ -75,12 +75,12 @@ public: bool logEvents; std::string mLogFilename; - llofstream mLog; + llofstream mLog; private: - // Mouse event info + // Mouse event info S32 global_x; S32 global_y; S32 local_x; @@ -92,7 +92,7 @@ public: // Actually write the event out to llsd log file void recordEvent(LLSD event); - void clear(S32 r); + void clear(S32 r); static const S32 UNDEFINED=-1; }; diff --git a/indra/llui/llviewinject.cpp b/indra/llui/llviewinject.cpp index 46c5839f8e..6da00de5d4 100644 --- a/indra/llui/llviewinject.cpp +++ b/indra/llui/llviewinject.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-08-16 * @brief Implementation for llviewinject. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llui/llviewinject.h b/indra/llui/llviewinject.h index 7f18ec6fbe..c4218e28ff 100644 --- a/indra/llui/llviewinject.h +++ b/indra/llui/llviewinject.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-08-16 * @brief Supplemental LLView functionality used for simulating UI events. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp index a400eb70c0..93106b344f 100644 --- a/indra/llui/llviewmodel.cpp +++ b/indra/llui/llviewmodel.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-08-08 * @brief Implementation for llviewmodel. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,13 +37,13 @@ /// LLViewModel::LLViewModel() -: mDirty(false) +: mDirty(false) { } /// Instantiate an LLViewModel with an existing data value LLViewModel::LLViewModel(const LLSD& value) -: mDirty(false) +: mDirty(false) { setValue(value); } @@ -65,23 +65,23 @@ LLSD LLViewModel::getValue() const /// LLTextViewModel::LLTextViewModel() : LLViewModel(false), - mUpdateFromDisplay(false) + mUpdateFromDisplay(false) { } /// Instantiate an LLViewModel with an existing data value LLTextViewModel::LLTextViewModel(const LLSD& value) : LLViewModel(value), - mUpdateFromDisplay(false) + mUpdateFromDisplay(false) { } /// Update the stored value void LLTextViewModel::setValue(const LLSD& value) { - // approximate LLSD storage usage - LLViewModel::setValue(value); - mDisplay = utf8str_to_wstring(value.asString()); + // approximate LLSD storage usage + LLViewModel::setValue(value); + mDisplay = utf8str_to_wstring(mStringValue = value.asString()); // mDisplay and mValue agree mUpdateFromDisplay = false; @@ -93,31 +93,42 @@ void LLTextViewModel::setDisplay(const LLWString& value) // and do the utf8str_to_wstring() to get the corresponding mDisplay // value. But a text editor might want to edit the display string // directly, then convert back to UTF8 on commit. - mDisplay = value; - mDirty = true; + mDisplay = value; + mDirty = true; // Don't immediately convert to UTF8 -- do it lazily -- we expect many // more setDisplay() calls than getValue() calls. Just flag that it needs // doing. mUpdateFromDisplay = true; } -LLSD LLTextViewModel::getValue() const +inline void updateFromDisplayIfNeeded(const LLTextViewModel* model) { - // Has anyone called setDisplay() since the last setValue()? If so, have - // to convert mDisplay back to UTF8. - if (mUpdateFromDisplay) + // Has anyone called setDisplay() since the last setValue()? + // If so, have to convert mDisplay back to UTF8. + if (model->mUpdateFromDisplay) { - // The fact that we're lazily updating fields in this object should be - // transparent to clients, which is why this method is left - // conventionally const. Nor do we particularly want to make these - // members mutable. Just cast away constness in this one place. - LLTextViewModel* nthis = const_cast<LLTextViewModel*>(this); + // The fact that we're lazily updating fields + // in this object should be transparent to clients, + // which is why this method is left conventionally const. + // Nor do we particularly want to make these members mutable. + // Just cast away constness in this one place. + LLTextViewModel* nthis = const_cast<LLTextViewModel*>(model); nthis->mUpdateFromDisplay = false; - nthis->mValue = wstring_to_utf8str(mDisplay); + nthis->mValue = nthis->mStringValue = wstring_to_utf8str(model->mDisplay); } - return LLViewModel::getValue(); } +LLSD LLTextViewModel::getValue() const +{ + updateFromDisplayIfNeeded(this); + return mValue; +} + +const std::string& LLTextViewModel::getStringValue() const +{ + updateFromDisplayIfNeeded(this); + return mStringValue; +} //////////////////////////////////////////////////////////////////////////// diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index e7dceb6c31..6cf2200a81 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -8,25 +8,25 @@ * underlying a specific widget object -- as in our case -- rather * than the business "model" object underlying the overall "view" * presented by the collection of widgets. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -61,8 +61,8 @@ typedef LLPointer<LLListViewModel> LLListViewModelPtr; * LLViewModel data. This way, the LLViewModel is quietly deleted when the * last referencing widget is destroyed. */ -class LLViewModel -: public LLRefCount +class LLViewModel +: public LLRefCount { public: LLViewModel(); @@ -79,7 +79,7 @@ public: /// Once the value has been saved to a file, or otherwise consumed by the /// app, we no longer need to enable the Save button void resetDirty() { mDirty = false; } - // + // void setDirty() { mDirty = true; } protected: @@ -88,7 +88,7 @@ protected: }; /** - * LLTextViewModel stores a value displayed as text. + * LLTextViewModel stores a value displayed as text. */ class LLTextViewModel: public LLViewModel { @@ -96,15 +96,16 @@ public: LLTextViewModel(); /// Instantiate an LLViewModel with an existing data value LLTextViewModel(const LLSD& value); - - // LLViewModel functions + + // LLViewModel functions virtual void setValue(const LLSD& value); virtual LLSD getValue() const; + const std::string& getStringValue() const; - // New functions + // New functions /// Get the stored value in string form const LLWString& getDisplay() const { return mDisplay; } - LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; } + LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; } /** * Set the display string directly (see LLTextEditor). What the user is @@ -112,14 +113,19 @@ public: * UTF-8 value. */ void setDisplay(const LLWString& value); - + private: + std::string mStringValue; + /// To avoid converting every widget's stored value from LLSD to LLWString /// every frame, cache the converted value LLWString mDisplay; + /// As the user edits individual characters (setDisplay()), defer /// LLWString-to-UTF8 conversions until s/he's done. bool mUpdateFromDisplay; + + friend void updateFromDisplayIfNeeded(const LLTextViewModel* model); }; /** @@ -145,73 +151,73 @@ public: //namespace LLViewModel //{ -// class Value -// { -// public: -// Value(const LLSD& value = LLSD()); +// class Value +// { +// public: +// Value(const LLSD& value = LLSD()); // -// LLSD getValue() const { return mValue; } -// void setValue(const LLSD& value) { mValue = value; } +// LLSD getValue() const { return mValue; } +// void setValue(const LLSD& value) { mValue = value; } // -// bool isAvailable() const { return false; } -// bool isReadOnly() const { return false; } +// bool isAvailable() const { return false; } +// bool isReadOnly() const { return false; } // -// bool undo() { return false; } -// bool redo() { return false; } +// bool undo() { return false; } +// bool redo() { return false; } // -// /// Has the value been changed since last time we checked? -// bool isDirty() const { return mDirty; } -// /// Once the value has been saved to a file, or otherwise consumed by the -// /// app, we no longer need to enable the Save button -// void resetDirty() { mDirty = false; } -// // -// void setDirty() { mDirty = true; } +// /// Has the value been changed since last time we checked? +// bool isDirty() const { return mDirty; } +// /// Once the value has been saved to a file, or otherwise consumed by the +// /// app, we no longer need to enable the Save button +// void resetDirty() { mDirty = false; } +// // +// void setDirty() { mDirty = true; } // -// protected: -// LLSD mValue; -// bool mDirty; -// }; +// protected: +// LLSD mValue; +// bool mDirty; +// }; // -// class Numeric : public Value -// { -// public: -// Numeric(S32 value = 0); -// Numeric(F32 value); +// class Numeric : public Value +// { +// public: +// Numeric(S32 value = 0); +// Numeric(F32 value); // -// F32 getPrecision(); -// F32 getMin(); -// F32 getMax(); +// F32 getPrecision(); +// F32 getMin(); +// F32 getMax(); // -// void increment(); -// void decrement(); -// }; +// void increment(); +// void decrement(); +// }; // -// class MultipleValues : public Value -// { -// class Selector -// {}; +// class MultipleValues : public Value +// { +// class Selector +// {}; // -// MultipleValues(); -// virtual S32 numElements(); -// }; +// MultipleValues(); +// virtual S32 numElements(); +// }; // -// class Tuple : public MultipleValues -// { -// Tuple(S32 size); -// LLSD getValue(S32 which) const; -// void setValue(S32 which, const LLSD& value); -// }; +// class Tuple : public MultipleValues +// { +// Tuple(S32 size); +// LLSD getValue(S32 which) const; +// void setValue(S32 which, const LLSD& value); +// }; // -// class List : public MultipleValues -// { -// List(); +// class List : public MultipleValues +// { +// List(); // -// void add(const ValueModel& value); -// bool remove(const Selector& item); +// void add(const ValueModel& value); +// bool remove(const Selector& item); // -// void setSortElement(const Selector& element); -// void sort(); -// }; +// void setSortElement(const Selector& element); +// void sort(); +// }; // //}; #endif /* ! defined(LL_LLVIEWMODEL_H) */ diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp index 66262609ae..8f9d05d57e 100644 --- a/indra/llui/llviewquery.cpp +++ b/indra/llui/llviewquery.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewquery.cpp * @brief Implementation of view query class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,33 +32,33 @@ void LLQuerySorter::sort(LLView * parent, viewList_t &children) const {} -filterResult_t LLLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(children.empty(), TRUE); + return filterResult_t(children.empty(), TRUE); } -filterResult_t LLRootsFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLRootsFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(TRUE, FALSE); + return filterResult_t(TRUE, FALSE); } -filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(view->getVisible(), view->getVisible()); + return filterResult_t(view->getVisible(), view->getVisible()); } -filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLEnabledFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(view->getEnabled(), view->getEnabled()); + return filterResult_t(view->getEnabled(), view->getEnabled()); } -filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLTabStopFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl*>(view)->hasTabStop(), - view->canFocusChildren()); + return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl*>(view)->hasTabStop(), + view->canFocusChildren()); } -filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewList_t & children) const +filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewList_t & children) const { - return filterResult_t(view->isCtrl(),TRUE); + return filterResult_t(view->isCtrl(),TRUE); } // @@ -67,70 +67,70 @@ filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewLis viewList_t LLViewQuery::run(LLView* view) const { - viewList_t result; - - // prefilter gets immediate children of view - filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters); - if(!pre.first && !pre.second) - { - // not including ourselves or the children - // nothing more to do - return result; - } - - viewList_t filtered_children; - filterResult_t post(TRUE, TRUE); - if(pre.second) - { - // run filters on children - filterChildren(view, filtered_children); - // only run post filters if this element passed pre filters - // so if you failed to pass the pre filter, you can't filter out children in post - if (pre.first) - { - post = runFilters(view, filtered_children, mPostFilters); - } - } - - if(pre.first && post.first) - { - result.push_back(view); - } - - if(pre.second && post.second) - { - result.insert(result.end(), filtered_children.begin(), filtered_children.end()); - } - - return result; + viewList_t result; + + // prefilter gets immediate children of view + filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters); + if(!pre.first && !pre.second) + { + // not including ourselves or the children + // nothing more to do + return result; + } + + viewList_t filtered_children; + filterResult_t post(TRUE, TRUE); + if(pre.second) + { + // run filters on children + filterChildren(view, filtered_children); + // only run post filters if this element passed pre filters + // so if you failed to pass the pre filter, you can't filter out children in post + if (pre.first) + { + post = runFilters(view, filtered_children, mPostFilters); + } + } + + if(pre.first && post.first) + { + result.push_back(view); + } + + if(pre.second && post.second) + { + result.insert(result.end(), filtered_children.begin(), filtered_children.end()); + } + + return result; } void LLViewQuery::filterChildren(LLView* parent_view, viewList_t & filtered_children) const { - LLView::child_list_t views(*(parent_view->getChildList())); - if (mSorterp) - { - mSorterp->sort(parent_view, views); // sort the children per the sorter - } - for(LLView::child_list_iter_t iter = views.begin(); - iter != views.end(); - iter++) - { - viewList_t indiv_children = this->run(*iter); - filtered_children.splice(filtered_children.end(), indiv_children); - } + LLView::child_list_t views(*(parent_view->getChildList())); + if (mSorterp) + { + mSorterp->sort(parent_view, views); // sort the children per the sorter + } + for(LLView::child_list_iter_t iter = views.begin(); + iter != views.end(); + iter++) + { + viewList_t indiv_children = this->run(*iter); + filtered_children.splice(filtered_children.end(), indiv_children); + } } filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const { - filterResult_t result = filterResult_t(TRUE, TRUE); - for(filterList_const_iter_t iter = filters.begin(); - iter != filters.end(); - iter++) - { - filterResult_t filtered = (**iter)(view, children); - result.first = result.first && filtered.first; - result.second = result.second && filtered.second; - } - return result; + filterResult_t result = filterResult_t(TRUE, TRUE); + for(filterList_const_iter_t iter = filters.begin(); + iter != filters.end(); + iter++) + { + filterResult_t filtered = (**iter)(view, children); + result.first = result.first && filtered.first; + result.second = result.second && filtered.second; + } + return result; } diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h index 4bc9c4a08e..2fc7fc476a 100644 --- a/indra/llui/llviewquery.h +++ b/indra/llui/llviewquery.h @@ -1,25 +1,25 @@ -/** +/** * @file llviewquery.h * @brief Query algorithm for flattening and filtering the view hierarchy. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,74 +27,74 @@ #ifndef LL_LLVIEWQUERY_H #define LL_LLVIEWQUERY_H -#include <list> +#include <list> #include "llsingleton.h" #include "llui.h" class LLView; -typedef std::list<LLView *> viewList_t; -typedef std::pair<BOOL, BOOL> filterResult_t; +typedef std::list<LLView *> viewList_t; +typedef std::pair<BOOL, BOOL> filterResult_t; // Abstract base class for all query filters. class LLQueryFilter { public: - virtual ~LLQueryFilter() {}; - virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const = 0; + virtual ~LLQueryFilter() {}; + virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const = 0; }; class LLQuerySorter { public: - virtual ~LLQuerySorter() {}; - virtual void sort(LLView * parent, viewList_t &children) const; + virtual ~LLQuerySorter() {}; + virtual void sort(LLView * parent, viewList_t &children) const; }; class LLLeavesFilter : public LLQueryFilter, public LLSingleton<LLLeavesFilter> { - LLSINGLETON_EMPTY_CTOR(LLLeavesFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLLeavesFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLRootsFilter : public LLQueryFilter, public LLSingleton<LLRootsFilter> { - LLSINGLETON_EMPTY_CTOR(LLRootsFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLRootsFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter> { - LLSINGLETON_EMPTY_CTOR(LLVisibleFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLVisibleFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter> { - LLSINGLETON_EMPTY_CTOR(LLEnabledFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLEnabledFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter> { - LLSINGLETON_EMPTY_CTOR(LLTabStopFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLTabStopFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLCtrlFilter : public LLQueryFilter, public LLSingleton<LLCtrlFilter> { - LLSINGLETON_EMPTY_CTOR(LLCtrlFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; + LLSINGLETON_EMPTY_CTOR(LLCtrlFilter); + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; template <class T> class LLWidgetTypeFilter : public LLQueryFilter { - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const - { - return filterResult_t(dynamic_cast<const T*>(view) != NULL, TRUE); - } + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const + { + return filterResult_t(dynamic_cast<const T*>(view) != NULL, TRUE); + } }; @@ -102,35 +102,35 @@ class LLWidgetTypeFilter : public LLQueryFilter class LLViewQuery { public: - typedef std::list<const LLQueryFilter*> filterList_t; - typedef filterList_t::iterator filterList_iter_t; - typedef filterList_t::const_iterator filterList_const_iter_t; + typedef std::list<const LLQueryFilter*> filterList_t; + typedef filterList_t::iterator filterList_iter_t; + typedef filterList_t::const_iterator filterList_const_iter_t; - LLViewQuery() : mPreFilters(), mPostFilters(), mSorterp() {} - virtual ~LLViewQuery() {} + LLViewQuery() : mPreFilters(), mPostFilters(), mSorterp() {} + virtual ~LLViewQuery() {} - void addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); } - void addPostFilter(const LLQueryFilter* postfilter) { mPostFilters.push_back(postfilter); } - const filterList_t & getPreFilters() const { return mPreFilters; } - const filterList_t & getPostFilters() const { return mPostFilters; } + void addPreFilter(const LLQueryFilter* prefilter) { mPreFilters.push_back(prefilter); } + void addPostFilter(const LLQueryFilter* postfilter) { mPostFilters.push_back(postfilter); } + const filterList_t & getPreFilters() const { return mPreFilters; } + const filterList_t & getPostFilters() const { return mPostFilters; } - void setSorter(const LLQuerySorter* sorter) { mSorterp = sorter; } - const LLQuerySorter* getSorter() const { return mSorterp; } + void setSorter(const LLQuerySorter* sorter) { mSorterp = sorter; } + const LLQuerySorter* getSorter() const { return mSorterp; } - viewList_t run(LLView * view) const; - // syntactic sugar - viewList_t operator () (LLView * view) const { return run(view); } + viewList_t run(LLView * view) const; + // syntactic sugar + viewList_t operator () (LLView * view) const { return run(view); } - // override this method to provide iteration over other types of children - virtual void filterChildren(LLView * view, viewList_t& filtered_children) const; + // override this method to provide iteration over other types of children + virtual void filterChildren(LLView * view, viewList_t& filtered_children) const; private: - filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const; + filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const; - filterList_t mPreFilters; - filterList_t mPostFilters; - const LLQuerySorter* mSorterp; + filterList_t mPreFilters; + filterList_t mPostFilters; + const LLQuerySorter* mSorterp; }; diff --git a/indra/llui/llvirtualtrackball.cpp b/indra/llui/llvirtualtrackball.cpp index 6e0aef740d..deb357cd9f 100644 --- a/indra/llui/llvirtualtrackball.cpp +++ b/indra/llui/llvirtualtrackball.cpp @@ -83,7 +83,7 @@ LLVirtualTrackball::LLVirtualTrackball(const LLVirtualTrackball::Params& p) mBorder = LLUICtrlFactory::create<LLViewBorder>(border); addChild(mBorder); - + LLButton::Params btn_rt = p.btn_rotate_top; btn_rt.rect(LLRect(centerX - axis_offset_lt, border_rect.mTop, centerX + axis_offset_rb, border_rect.mTop - btn_size)); btn_rt.click_callback.function(boost::bind(&LLVirtualTrackball::onRotateTopClick, this)); @@ -247,7 +247,7 @@ void LLVirtualTrackball::onRotateTopClick() if (getEnabled()) { LLQuaternion delta; - delta.setAngleAxis(mIncrementBtn, 1, 0, 0); + delta.setAngleAxis(mIncrementBtn, 1, 0, 0); mValue *= delta; setValueAndCommit(mValue); @@ -316,7 +316,7 @@ void LLVirtualTrackball::onRotateRightMouseEnter() void LLVirtualTrackball::setValue(const LLSD& value) { - if (value.isArray() && value.size() == 4) + if (value.isArray() && value.size() == 4) { mValue.setValue(value); } @@ -334,7 +334,7 @@ void LLVirtualTrackball::setValue(F32 x, F32 y, F32 z, F32 w) void LLVirtualTrackball::setValueAndCommit(const LLQuaternion &value) { - mValue = value; + mValue = value; onCommit(); } @@ -345,7 +345,7 @@ LLSD LLVirtualTrackball::getValue() const LLQuaternion LLVirtualTrackball::getRotation() const { - return mValue; + return mValue; } // static diff --git a/indra/llui/llvirtualtrackball.h b/indra/llui/llvirtualtrackball.h index c7a893877b..5eb9b548e5 100644 --- a/indra/llui/llvirtualtrackball.h +++ b/indra/llui/llvirtualtrackball.h @@ -53,7 +53,7 @@ public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<LLViewBorder::Params> border; + Optional<LLViewBorder::Params> border; Optional<LLUIImage*> image_moon_back, image_moon_front, image_sphere, diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp index f5c463c961..e48bc94b0a 100644 --- a/indra/llui/llwindowshade.cpp +++ b/indra/llui/llwindowshade.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,353 +40,353 @@ const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100; static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade"); LLWindowShade::Params::Params() -: bg_image("bg_image"), - modal("modal", false), - text_color("text_color"), - shade_color("shade_color"), - can_close("can_close", true) +: bg_image("bg_image"), + modal("modal", false), + text_color("text_color"), + shade_color("shade_color"), + can_close("can_close", true) { - changeDefault(mouse_opaque, false); + changeDefault(mouse_opaque, false); } LLWindowShade::LLWindowShade(const LLWindowShade::Params& params) -: LLUICtrl(params), - mModal(params.modal), - mFormHeight(0), - mTextColor(params.text_color) +: LLUICtrl(params), + mModal(params.modal), + mFormHeight(0), + mTextColor(params.text_color) { - setFocusRoot(true); + setFocusRoot(true); } void LLWindowShade::initFromParams(const LLWindowShade::Params& params) { - LLUICtrl::initFromParams(params); - - LLLayoutStack::Params layout_p; - layout_p.name = "notification_stack"; - layout_p.rect = params.rect; - layout_p.follows.flags = FOLLOWS_ALL; - layout_p.mouse_opaque = false; - layout_p.orientation = LLLayoutStack::VERTICAL; - layout_p.border_size = 0; - - LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); - addChild(stackp); - - LLLayoutPanel::Params panel_p; - panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0); - panel_p.name = "notification_area"; - panel_p.visible = false; - panel_p.user_resize = false; - panel_p.background_visible = true; - panel_p.bg_alpha_image = params.bg_image; - panel_p.auto_resize = false; - LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(notification_panel); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = true; - panel_p.user_resize = false; - panel_p.rect = params.rect; - panel_p.name = "background_area"; - panel_p.mouse_opaque = false; - panel_p.background_visible = false; - panel_p.bg_alpha_color = params.shade_color; - LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(dummy_panel); - - layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); - layout_p.rect = LLRect(0, 30, 800, 0); - layout_p.follows.flags = FOLLOWS_ALL; - layout_p.orientation = LLLayoutStack::HORIZONTAL; - stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); - notification_panel->addChild(stackp); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.rect.height = 30; - LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(panel); - - LLIconCtrl::Params icon_p; - icon_p.name = "notification_icon"; - icon_p.rect = LLRect(5, 25, 21, 10); - panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); - - LLTextBox::Params text_p; - text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3); - text_p.follows.flags = FOLLOWS_ALL; - text_p.text_color = mTextColor; - text_p.font = LLFontGL::getFontSansSerifSmall(); - text_p.font.style = "BOLD"; - text_p.name = "notification_text"; - text_p.use_ellipses = true; - text_p.wrap = true; - panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = false; - panel_p.user_resize = false; - panel_p.name="form_elements"; - panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0); - LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(form_elements_panel); - - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = false; - panel_p.user_resize = false; - panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0); - panel_p.name = "close_panel"; - LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(close_panel); - - LLButton::Params button_p; - button_p.name = "close_notification"; - button_p.rect = LLRect(5, 23, 21, 7); - button_p.image_color.control="DkGray_66"; - button_p.image_unselected.name="Icon_Close_Foreground"; - button_p.image_selected.name="Icon_Close_Press"; - button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); - - close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); - - close_panel->setVisible(params.can_close); + LLUICtrl::initFromParams(params); + + LLLayoutStack::Params layout_p; + layout_p.name = "notification_stack"; + layout_p.rect = params.rect; + layout_p.follows.flags = FOLLOWS_ALL; + layout_p.mouse_opaque = false; + layout_p.orientation = LLLayoutStack::VERTICAL; + layout_p.border_size = 0; + + LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); + addChild(stackp); + + LLLayoutPanel::Params panel_p; + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0); + panel_p.name = "notification_area"; + panel_p.visible = false; + panel_p.user_resize = false; + panel_p.background_visible = true; + panel_p.bg_alpha_image = params.bg_image; + panel_p.auto_resize = false; + LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(notification_panel); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = true; + panel_p.user_resize = false; + panel_p.rect = params.rect; + panel_p.name = "background_area"; + panel_p.mouse_opaque = false; + panel_p.background_visible = false; + panel_p.bg_alpha_color = params.shade_color; + LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(dummy_panel); + + layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); + layout_p.rect = LLRect(0, 30, 800, 0); + layout_p.follows.flags = FOLLOWS_ALL; + layout_p.orientation = LLLayoutStack::HORIZONTAL; + stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); + notification_panel->addChild(stackp); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.rect.height = 30; + LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(panel); + + LLIconCtrl::Params icon_p; + icon_p.name = "notification_icon"; + icon_p.rect = LLRect(5, 25, 21, 10); + panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); + + LLTextBox::Params text_p; + text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3); + text_p.follows.flags = FOLLOWS_ALL; + text_p.text_color = mTextColor; + text_p.font = LLFontGL::getFontSansSerifSmall(); + text_p.font.style = "BOLD"; + text_p.name = "notification_text"; + text_p.use_ellipses = true; + text_p.wrap = true; + panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = false; + panel_p.user_resize = false; + panel_p.name="form_elements"; + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0); + LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(form_elements_panel); + + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = false; + panel_p.user_resize = false; + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0); + panel_p.name = "close_panel"; + LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(close_panel); + + LLButton::Params button_p; + button_p.name = "close_notification"; + button_p.rect = LLRect(5, 23, 21, 7); + button_p.image_color.control="DkGray_66"; + button_p.image_unselected.name="Icon_Close_Foreground"; + button_p.image_selected.name="Icon_Close_Press"; + button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); + + close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); + + close_panel->setVisible(params.can_close); } void LLWindowShade::draw() { - LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); - - LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); - - notification_area->reshape(notification_area->getRect().getWidth(), - llclamp(message_rect.getHeight() + 15, - llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT), - MAX_NOTIFICATION_AREA_HEIGHT)); - - LLUICtrl::draw(); - - while(!mNotifications.empty() && !mNotifications.back()->isActive()) - { - mNotifications.pop_back(); - // go ahead and hide - hide(); - } - - if (mNotifications.empty()) - { - hide(); - } - else if (notification_area->getVisibleAmount() < 0.01f) - { - displayLatestNotification(); - } - - if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f)) - { - getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); - setMouseOpaque(false); - } + LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); + + LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); + + notification_area->reshape(notification_area->getRect().getWidth(), + llclamp(message_rect.getHeight() + 15, + llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT), + MAX_NOTIFICATION_AREA_HEIGHT)); + + LLUICtrl::draw(); + + while(!mNotifications.empty() && !mNotifications.back()->isActive()) + { + mNotifications.pop_back(); + // go ahead and hide + hide(); + } + + if (mNotifications.empty()) + { + hide(); + } + else if (notification_area->getVisibleAmount() < 0.01f) + { + displayLatestNotification(); + } + + if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f)) + { + getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); + setMouseOpaque(false); + } } void LLWindowShade::hide() { - getChildRef<LLLayoutPanel>("notification_area").setVisible(false); + getChildRef<LLLayoutPanel>("notification_area").setVisible(false); } void LLWindowShade::onCloseNotification() { - if (!mNotifications.empty()) - LLNotifications::instance().cancel(mNotifications.back()); + if (!mNotifications.empty()) + LLNotifications::instance().cancel(mNotifications.back()); } void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) { - LLNotificationPtr notify = getCurrentNotification(); - if (!notify) return; - - bool check = ctrl->getValue().asBoolean(); - if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) - { - // question was "show again" so invert value to get "ignore" - check = !check; - } - notify->setIgnored(check); + LLNotificationPtr notify = getCurrentNotification(); + if (!notify) return; + + bool check = ctrl->getValue().asBoolean(); + if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + notify->setIgnored(check); } void LLWindowShade::onClickNotificationButton(const std::string& name) { - LLNotificationPtr notify = getCurrentNotification(); - if (!notify) return; + LLNotificationPtr notify = getCurrentNotification(); + if (!notify) return; - mNotificationResponse[name] = true; + mNotificationResponse[name] = true; - notify->respond(mNotificationResponse); + notify->respond(mNotificationResponse); } void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) { - mNotificationResponse[name] = ctrl->getValue().asString(); + mNotificationResponse[name] = ctrl->getValue().asString(); } void LLWindowShade::show(LLNotificationPtr notification) { - mNotifications.push_back(notification); + mNotifications.push_back(notification); - displayLatestNotification(); + displayLatestNotification(); } void LLWindowShade::displayLatestNotification() { - if (mNotifications.empty()) return; - - LLNotificationPtr notification = mNotifications.back(); - - LLSD payload = notification->getPayload(); - - LLNotificationFormPtr formp = notification->getForm(); - LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); - notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon()); - notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage()); - notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage()); - - LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); - LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements"); - form_elements.deleteAllChildren(); - form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT); - - const S32 FORM_PADDING_HORIZONTAL = 10; - const S32 FORM_PADDING_VERTICAL = 3; - const S32 WIDGET_HEIGHT = 24; - const S32 LINE_EDITOR_WIDTH = 120; - S32 cur_x = FORM_PADDING_HORIZONTAL; - S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT; - S32 form_width = cur_x; - - if (ignore_type != LLNotificationForm::IGNORE_NO) - { - LLCheckBoxCtrl::Params checkbox_p; - checkbox_p.name = "ignore_check"; - checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); - checkbox_p.label = formp->getIgnoreMessage(); - checkbox_p.label_text.text_color = LLColor4::black; - checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1); - checkbox_p.initial_value = formp->getIgnored(); - - LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); - check->setRect(check->getBoundingRect()); - form_elements.addChild(check); - cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; - form_width = llmax(form_width, cur_x); - } - - for (S32 i = 0; i < formp->getNumElements(); i++) - { - LLSD form_element = formp->getElement(i); - std::string type = form_element["type"].asString(); - if (type == "button") - { - LLButton::Params button_p; - button_p.name = form_element["name"]; - button_p.label = form_element["text"]; - button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); - button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString()); - button_p.auto_resize = true; - - LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); - button->autoResize(); - form_elements.addChild(button); - - if (form_element["default"].asBoolean()) - { - form_elements.setDefaultBtn(button); - } - - cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; - form_width = llmax(form_width, cur_x); - } - else if (type == "text" || type == "password") - { - // if not at beginning of line... - if (cur_x != FORM_PADDING_HORIZONTAL) - { - // start new line - cur_x = FORM_PADDING_HORIZONTAL; - cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; - } - LLTextBox::Params label_p; - label_p.name = form_element["name"].asString() + "_label"; - label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); - label_p.initial_value = form_element["text"]; - label_p.text_color = mTextColor; - label_p.font_valign = LLFontGL::VCENTER; - label_p.v_pad = 5; - LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p); - textbox->reshapeToFitText(); - textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL); - form_elements.addChild(textbox); - cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; - - LLLineEditor::Params line_p; - line_p.name = form_element["name"]; - line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString()); - line_p.is_password = type == "password"; - line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); - - LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p); - form_elements.addChild(line_editor); - form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL); - - // reset to start of next line - cur_x = FORM_PADDING_HORIZONTAL; - cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; - } - } - - mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL); - form_elements.reshape(form_width, mFormHeight); - form_elements.setMinDim(form_width); - - // move all form elements back onto form surface - S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y; - for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end(); - it != end_it; - ++it) - { - (*it)->translate(0, delta_y); - } - - getChildRef<LLLayoutPanel>("notification_area").setVisible(true); - getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal); - - setMouseOpaque(mModal); + if (mNotifications.empty()) return; + + LLNotificationPtr notification = mNotifications.back(); + + LLSD payload = notification->getPayload(); + + LLNotificationFormPtr formp = notification->getForm(); + LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); + notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon()); + notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage()); + notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage()); + + LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); + LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements"); + form_elements.deleteAllChildren(); + form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT); + + const S32 FORM_PADDING_HORIZONTAL = 10; + const S32 FORM_PADDING_VERTICAL = 3; + const S32 WIDGET_HEIGHT = 24; + const S32 LINE_EDITOR_WIDTH = 120; + S32 cur_x = FORM_PADDING_HORIZONTAL; + S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT; + S32 form_width = cur_x; + + if (ignore_type != LLNotificationForm::IGNORE_NO) + { + LLCheckBoxCtrl::Params checkbox_p; + checkbox_p.name = "ignore_check"; + checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); + checkbox_p.label = formp->getIgnoreMessage(); + checkbox_p.label_text.text_color = LLColor4::black; + checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1); + checkbox_p.initial_value = formp->getIgnored(); + + LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); + check->setRect(check->getBoundingRect()); + form_elements.addChild(check); + cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; + form_width = llmax(form_width, cur_x); + } + + for (S32 i = 0; i < formp->getNumElements(); i++) + { + LLSD form_element = formp->getElement(i); + std::string type = form_element["type"].asString(); + if (type == "button") + { + LLButton::Params button_p; + button_p.name = form_element["name"]; + button_p.label = form_element["text"]; + button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT); + button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString()); + button_p.auto_resize = true; + + LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); + button->autoResize(); + form_elements.addChild(button); + + if (form_element["default"].asBoolean()) + { + form_elements.setDefaultBtn(button); + } + + cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; + form_width = llmax(form_width, cur_x); + } + else if (type == "text" || type == "password") + { + // if not at beginning of line... + if (cur_x != FORM_PADDING_HORIZONTAL) + { + // start new line + cur_x = FORM_PADDING_HORIZONTAL; + cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; + } + LLTextBox::Params label_p; + label_p.name = form_element["name"].asString() + "_label"; + label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); + label_p.initial_value = form_element["text"]; + label_p.text_color = mTextColor; + label_p.font_valign = LLFontGL::VCENTER; + label_p.v_pad = 5; + LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p); + textbox->reshapeToFitText(); + textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL); + form_elements.addChild(textbox); + cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; + + LLLineEditor::Params line_p; + line_p.name = form_element["name"]; + line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString()); + line_p.is_password = type == "password"; + line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT); + + LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p); + form_elements.addChild(line_editor); + form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL); + + // reset to start of next line + cur_x = FORM_PADDING_HORIZONTAL; + cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL; + } + } + + mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL); + form_elements.reshape(form_width, mFormHeight); + form_elements.setMinDim(form_width); + + // move all form elements back onto form surface + S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y; + for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end(); + it != end_it; + ++it) + { + (*it)->translate(0, delta_y); + } + + getChildRef<LLLayoutPanel>("notification_area").setVisible(true); + getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal); + + setMouseOpaque(mModal); } void LLWindowShade::setBackgroundImage(LLUIImage* image) { - getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image); + getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image); } void LLWindowShade::setTextColor(LLColor4 color) { - getChild<LLTextBox>("notification_text")->setColor(color); + getChild<LLTextBox>("notification_text")->setColor(color); } bool LLWindowShade::isShown() const { - return getChildRef<LLLayoutPanel>("notification_area").getVisible(); + return getChildRef<LLLayoutPanel>("notification_area").getVisible(); } void LLWindowShade::setCanClose(bool can_close) { - getChildView("close_panel")->setVisible(can_close); + getChildView("close_panel")->setVisible(can_close); } LLNotificationPtr LLWindowShade::getCurrentNotification() { - if (mNotifications.empty()) - { - return LLNotificationPtr(); - } - return mNotifications.back(); + if (mNotifications.empty()) + { + return LLNotificationPtr(); + } + return mNotifications.back(); } diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index 6d753d1161..a401394d78 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,45 +34,45 @@ class LLWindowShade : public LLUICtrl { public: - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> - { - Optional<LLUIImage*> bg_image; - Optional<LLUIColor> text_color, - shade_color; - Optional<bool> modal, - can_close; + struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + { + Optional<LLUIImage*> bg_image; + Optional<LLUIColor> text_color, + shade_color; + Optional<bool> modal, + can_close; + + Params(); + }; - Params(); - }; + void show(LLNotificationPtr); + /*virtual*/ void draw(); + void hide(); - void show(LLNotificationPtr); - /*virtual*/ void draw(); - void hide(); - - bool isShown() const; + bool isShown() const; - void setBackgroundImage(LLUIImage* image); - void setTextColor(LLColor4 color); - void setCanClose(bool can_close); + void setBackgroundImage(LLUIImage* image); + void setTextColor(LLColor4 color); + void setCanClose(bool can_close); private: - void displayLatestNotification(); - LLNotificationPtr getCurrentNotification(); - friend class LLUICtrlFactory; + void displayLatestNotification(); + LLNotificationPtr getCurrentNotification(); + friend class LLUICtrlFactory; - LLWindowShade(const Params& p); - void initFromParams(const Params& params); + LLWindowShade(const Params& p); + void initFromParams(const Params& params); - void onCloseNotification(); - void onClickNotificationButton(const std::string& name); - void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name); - void onClickIgnore(LLUICtrl* ctrl); + void onCloseNotification(); + void onClickNotificationButton(const std::string& name); + void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name); + void onClickIgnore(LLUICtrl* ctrl); - std::vector<LLNotificationPtr> mNotifications; - LLSD mNotificationResponse; - bool mModal; - S32 mFormHeight; - LLUIColor mTextColor; + std::vector<LLNotificationPtr> mNotifications; + LLSD mNotificationResponse; + bool mModal; + S32 mFormHeight; + LLUIColor mTextColor; }; #endif // LL_LLWINDOWSHADE_H diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index 138ba8bf02..0d3819ff5c 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llxuiparser.cpp * @brief Utility functions for handling XUI structures in XML * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,53 +48,53 @@ using namespace BOOST_SPIRIT_CLASSIC_NS; const S32 MAX_STRING_ATTRIBUTE_SIZE = 40; -static LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs; +static LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs; -static LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs; +static LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs; const char* NO_VALUE_MARKER = "no_value"; struct MaxOccursValues : public LLInitParam::TypeValuesHelper<U32, MaxOccursValues> { - static void declareValues() - { - declare("unbounded", U32_MAX); - } + static void declareValues() + { + declare("unbounded", U32_MAX); + } }; struct Occurs : public LLInitParam::Block<Occurs> { - Optional<U32> minOccurs; - Optional<U32, MaxOccursValues> maxOccurs; + Optional<U32> minOccurs; + Optional<U32, MaxOccursValues> maxOccurs; - Occurs() - : minOccurs("minOccurs", 0), - maxOccurs("maxOccurs", U32_MAX) + Occurs() + : minOccurs("minOccurs", 0), + maxOccurs("maxOccurs", U32_MAX) - {} + {} }; typedef enum { - USE_REQUIRED, - USE_OPTIONAL + USE_REQUIRED, + USE_OPTIONAL } EUse; namespace LLInitParam { - template<> - struct TypeValues<EUse> : public TypeValuesHelper<EUse> - { - static void declareValues() - { - declare("required", USE_REQUIRED); - declare("optional", USE_OPTIONAL); - } - }; + template<> + struct TypeValues<EUse> : public TypeValuesHelper<EUse> + { + static void declareValues() + { + declare("required", USE_REQUIRED); + declare("optional", USE_OPTIONAL); + } + }; } struct Element; @@ -103,86 +103,86 @@ struct Sequence; struct All : public LLInitParam::Block<All, Occurs> { - Multiple< Lazy<Element, IS_A_BLOCK> > elements; + Multiple< Lazy<Element, IS_A_BLOCK> > elements; - All() - : elements("element") - { - maxOccurs = 1; - } + All() + : elements("element") + { + maxOccurs = 1; + } }; struct Attribute : public LLInitParam::Block<Attribute> { - Mandatory<std::string> name, - type; - Mandatory<EUse> use; - - Attribute() - : name("name"), - type("type"), - use("use") - {} + Mandatory<std::string> name, + type; + Mandatory<EUse> use; + + Attribute() + : name("name"), + type("type"), + use("use") + {} }; struct Any : public LLInitParam::Block<Any, Occurs> { - Optional<std::string> _namespace; + Optional<std::string> _namespace; - Any() - : _namespace("namespace") - {} + Any() + : _namespace("namespace") + {} }; struct Choice : public LLInitParam::ChoiceBlock<Choice, Occurs> { - Alternative< Lazy<Element, IS_A_BLOCK> > element; - Alternative< Lazy<Group, IS_A_BLOCK> > group; - Alternative< Lazy<Choice, IS_A_BLOCK> > choice; - Alternative< Lazy<Sequence, IS_A_BLOCK> > sequence; - Alternative< Lazy<Any> > any; + Alternative< Lazy<Element, IS_A_BLOCK> > element; + Alternative< Lazy<Group, IS_A_BLOCK> > group; + Alternative< Lazy<Choice, IS_A_BLOCK> > choice; + Alternative< Lazy<Sequence, IS_A_BLOCK> > sequence; + Alternative< Lazy<Any> > any; - Choice() - : element("element"), - group("group"), - choice("choice"), - sequence("sequence"), - any("any") - {} + Choice() + : element("element"), + group("group"), + choice("choice"), + sequence("sequence"), + any("any") + {} }; struct Sequence : public LLInitParam::ChoiceBlock<Sequence, Occurs> { - Alternative< Lazy<Element, IS_A_BLOCK> > element; - Alternative< Lazy<Group, IS_A_BLOCK> > group; - Alternative< Lazy<Choice> > choice; - Alternative< Lazy<Sequence, IS_A_BLOCK> > sequence; - Alternative< Lazy<Any> > any; + Alternative< Lazy<Element, IS_A_BLOCK> > element; + Alternative< Lazy<Group, IS_A_BLOCK> > group; + Alternative< Lazy<Choice> > choice; + Alternative< Lazy<Sequence, IS_A_BLOCK> > sequence; + Alternative< Lazy<Any> > any; }; struct GroupContents : public LLInitParam::ChoiceBlock<GroupContents, Occurs> { - Alternative<All> all; - Alternative<Choice> choice; - Alternative<Sequence> sequence; + Alternative<All> all; + Alternative<Choice> choice; + Alternative<Sequence> sequence; - GroupContents() - : all("all"), - choice("choice"), - sequence("sequence") - {} + GroupContents() + : all("all"), + choice("choice"), + sequence("sequence") + {} }; struct Group : public LLInitParam::Block<Group, GroupContents> { - Optional<std::string> name, - ref; + Optional<std::string> name, + ref; - Group() - : name("name"), - ref("ref") - {} + Group() + : name("name"), + ref("ref") + {} }; struct Restriction : public LLInitParam::Block<Restriction> @@ -195,120 +195,120 @@ struct Extension : public LLInitParam::Block<Extension> struct SimpleContent : public LLInitParam::ChoiceBlock<SimpleContent> { - Alternative<Restriction> restriction; - Alternative<Extension> extension; + Alternative<Restriction> restriction; + Alternative<Extension> extension; - SimpleContent() - : restriction("restriction"), - extension("extension") - {} + SimpleContent() + : restriction("restriction"), + extension("extension") + {} }; struct SimpleType : public LLInitParam::Block<SimpleType> { - // TODO + // TODO }; struct ComplexContent : public LLInitParam::Block<ComplexContent, SimpleContent> { - Optional<bool> mixed; + Optional<bool> mixed; - ComplexContent() - : mixed("mixed", true) - {} + ComplexContent() + : mixed("mixed", true) + {} }; struct ComplexTypeContents : public LLInitParam::ChoiceBlock<ComplexTypeContents> { - Alternative<SimpleContent> simple_content; - Alternative<ComplexContent> complex_content; - Alternative<Group> group; - Alternative<All> all; - Alternative<Choice> choice; - Alternative<Sequence> sequence; - - ComplexTypeContents() - : simple_content("simpleContent"), - complex_content("complexContent"), - group("group"), - all("all"), - choice("choice"), - sequence("sequence") - {} + Alternative<SimpleContent> simple_content; + Alternative<ComplexContent> complex_content; + Alternative<Group> group; + Alternative<All> all; + Alternative<Choice> choice; + Alternative<Sequence> sequence; + + ComplexTypeContents() + : simple_content("simpleContent"), + complex_content("complexContent"), + group("group"), + all("all"), + choice("choice"), + sequence("sequence") + {} }; struct ComplexType : public LLInitParam::Block<ComplexType, ComplexTypeContents> { - Optional<std::string> name; - Optional<bool> mixed; + Optional<std::string> name; + Optional<bool> mixed; - Multiple<Attribute> attribute; - Multiple< Lazy<Element, IS_A_BLOCK > > elements; + Multiple<Attribute> attribute; + Multiple< Lazy<Element, IS_A_BLOCK > > elements; - ComplexType() - : name("name"), - attribute("xs:attribute"), - elements("xs:element"), - mixed("mixed") - { - } + ComplexType() + : name("name"), + attribute("xs:attribute"), + elements("xs:element"), + mixed("mixed") + { + } }; struct ElementContents : public LLInitParam::ChoiceBlock<ElementContents, Occurs> { - Alternative<SimpleType> simpleType; - Alternative<ComplexType> complexType; + Alternative<SimpleType> simpleType; + Alternative<ComplexType> complexType; - ElementContents() - : simpleType("simpleType"), - complexType("complexType") - {} + ElementContents() + : simpleType("simpleType"), + complexType("complexType") + {} }; struct Element : public LLInitParam::Block<Element, ElementContents> { - Optional<std::string> name, - ref, - type; + Optional<std::string> name, + ref, + type; - Element() - : name("xs:name"), - ref("xs:ref"), - type("xs:type") - {} + Element() + : name("xs:name"), + ref("xs:ref"), + type("xs:type") + {} }; struct Schema : public LLInitParam::Block<Schema> { private: - Mandatory<std::string> targetNamespace, - xmlns, - xs; + Mandatory<std::string> targetNamespace, + xmlns, + xs; public: - Optional<std::string> attributeFormDefault, - elementFormDefault; - - Mandatory<Element> root_element; - - void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;} - - Schema(const std::string& ns = LLStringUtil::null) - : attributeFormDefault("attributeFormDefault"), - elementFormDefault("elementFormDefault"), - xs("xmlns:xs"), - targetNamespace("targetNamespace"), - xmlns("xmlns"), - root_element("xs:element") - { - attributeFormDefault = "unqualified"; - elementFormDefault = "qualified"; - xs = "http://www.w3.org/2001/XMLSchema"; - if (!ns.empty()) - { - setNameSpace(ns); - }; - } + Optional<std::string> attributeFormDefault, + elementFormDefault; + + Mandatory<Element> root_element; + + void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;} + + Schema(const std::string& ns = LLStringUtil::null) + : attributeFormDefault("attributeFormDefault"), + elementFormDefault("elementFormDefault"), + xs("xmlns:xs"), + targetNamespace("targetNamespace"), + xmlns("xmlns"), + root_element("xs:element") + { + attributeFormDefault = "unqualified"; + elementFormDefault = "qualified"; + xs = "http://www.w3.org/2001/XMLSchema"; + if (!ns.empty()) + { + setNameSpace(ns); + }; + } }; // @@ -317,277 +317,277 @@ public: LLXSDWriter::LLXSDWriter() : Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs) { - registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4)); - registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); - registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4)); - registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4)); - registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4)); - registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4)); - registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4)); - registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4)); - registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4)); - registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4)); - registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); - registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); - registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); - registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4)); + registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4)); + registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4)); + registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4)); + registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4)); + registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4)); + registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4)); + registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4)); + registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4)); + registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); + registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); } LLXSDWriter::~LLXSDWriter() {} void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace) { - Schema schema(xml_namespace); - - schema.root_element.name = type_name; - Choice& choice = schema.root_element.complexType.choice; - - choice.minOccurs = 0; - choice.maxOccurs = "unbounded"; - - mSchemaNode = node; - //node->setName("xs:schema"); - //node->createChild("attributeFormDefault", true)->setStringValue("unqualified"); - //node->createChild("elementFormDefault", true)->setStringValue("qualified"); - //node->createChild("targetNamespace", true)->setStringValue(xml_namespace); - //node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema"); - //node->createChild("xmlns", true)->setStringValue(xml_namespace); - - //node = node->createChild("xs:complexType", false); - //node->createChild("name", true)->setStringValue(type_name); - //node->createChild("mixed", true)->setStringValue("true"); - - //mAttributeNode = node; - //mElementNode = node->createChild("xs:choice", false); - //mElementNode->createChild("minOccurs", true)->setStringValue("0"); - //mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded"); - block.inspectBlock(*this); - - // duplicate element choices - LLXMLNodeList children; - mElementNode->getChildren("xs:element", children, FALSE); - for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it) - { - LLXMLNodePtr child_copy = child_it->second->deepCopy(); - std::string child_name; - child_copy->getAttributeString("name", child_name); - child_copy->setAttributeString("name", type_name + "." + child_name); - mElementNode->addChild(child_copy); - } - - LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false); - element_declaration_node->createChild("name", true)->setStringValue(type_name); - element_declaration_node->createChild("type", true)->setStringValue(type_name); + Schema schema(xml_namespace); + + schema.root_element.name = type_name; + Choice& choice = schema.root_element.complexType.choice; + + choice.minOccurs = 0; + choice.maxOccurs = "unbounded"; + + mSchemaNode = node; + //node->setName("xs:schema"); + //node->createChild("attributeFormDefault", true)->setStringValue("unqualified"); + //node->createChild("elementFormDefault", true)->setStringValue("qualified"); + //node->createChild("targetNamespace", true)->setStringValue(xml_namespace); + //node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema"); + //node->createChild("xmlns", true)->setStringValue(xml_namespace); + + //node = node->createChild("xs:complexType", false); + //node->createChild("name", true)->setStringValue(type_name); + //node->createChild("mixed", true)->setStringValue("true"); + + //mAttributeNode = node; + //mElementNode = node->createChild("xs:choice", false); + //mElementNode->createChild("minOccurs", true)->setStringValue("0"); + //mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded"); + block.inspectBlock(*this); + + // duplicate element choices + LLXMLNodeList children; + mElementNode->getChildren("xs:element", children, FALSE); + for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it) + { + LLXMLNodePtr child_copy = child_it->second->deepCopy(); + std::string child_name; + child_copy->getAttributeString("name", child_name); + child_copy->setAttributeString("name", type_name + "." + child_name); + mElementNode->addChild(child_copy); + } + + LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false); + element_declaration_node->createChild("name", true)->setStringValue(type_name); + element_declaration_node->createChild("type", true)->setStringValue(type_name); } void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values) { - name_stack_t non_empty_names; - std::string attribute_name; - for (name_stack_t::const_iterator it = stack.begin(); - it != stack.end(); - ++it) - { - const std::string& name = it->first; - if (!name.empty()) - { - non_empty_names.push_back(*it); - } - } - - for (name_stack_t::const_iterator it = non_empty_names.begin(); - it != non_empty_names.end(); - ++it) - { - if (!attribute_name.empty()) - { - attribute_name += "."; - } - attribute_name += it->first; - } - - // only flag non-nested attributes as mandatory, nested attributes have variant syntax - // that can't be properly constrained in XSD - // e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo> - bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; - - // don't bother supporting "Multiple" params as xml attributes - if (max_count <= 1) - { - // add compound attribute to root node - addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); - } - - // now generated nested elements for compound attributes - if (non_empty_names.size() > 1 && !attribute_mandatory) - { - std::string element_name; - - // traverse all but last element, leaving that as an attribute name - name_stack_t::const_iterator end_it = non_empty_names.end(); - end_it--; - - for (name_stack_t::const_iterator it = non_empty_names.begin(); - it != end_it; - ++it) - { - if (it != non_empty_names.begin()) - { - element_name += "."; - } - element_name += it->first; - } - - std::string short_attribute_name = non_empty_names.back().first; - - LLXMLNodePtr complex_type_node; - - // find existing element node here, starting at tail of child list - if (mElementNode->mChildren.notNull()) - { - for(LLXMLNodePtr element = mElementNode->mChildren->tail; - element.notNull(); - element = element->mPrev) - { - std::string name; - if(element->getAttributeString("name", name) && name == element_name) - { - complex_type_node = element->mChildren->head; - break; - } - } - } - //create complex_type node - // - //<xs:element + name_stack_t non_empty_names; + std::string attribute_name; + for (name_stack_t::const_iterator it = stack.begin(); + it != stack.end(); + ++it) + { + const std::string& name = it->first; + if (!name.empty()) + { + non_empty_names.push_back(*it); + } + } + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != non_empty_names.end(); + ++it) + { + if (!attribute_name.empty()) + { + attribute_name += "."; + } + attribute_name += it->first; + } + + // only flag non-nested attributes as mandatory, nested attributes have variant syntax + // that can't be properly constrained in XSD + // e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo> + bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; + + // don't bother supporting "Multiple" params as xml attributes + if (max_count <= 1) + { + // add compound attribute to root node + addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); + } + + // now generated nested elements for compound attributes + if (non_empty_names.size() > 1 && !attribute_mandatory) + { + std::string element_name; + + // traverse all but last element, leaving that as an attribute name + name_stack_t::const_iterator end_it = non_empty_names.end(); + end_it--; + + for (name_stack_t::const_iterator it = non_empty_names.begin(); + it != end_it; + ++it) + { + if (it != non_empty_names.begin()) + { + element_name += "."; + } + element_name += it->first; + } + + std::string short_attribute_name = non_empty_names.back().first; + + LLXMLNodePtr complex_type_node; + + // find existing element node here, starting at tail of child list + if (mElementNode->mChildren.notNull()) + { + for(LLXMLNodePtr element = mElementNode->mChildren->tail; + element.notNull(); + element = element->mPrev) + { + std::string name; + if(element->getAttributeString("name", name) && name == element_name) + { + complex_type_node = element->mChildren->head; + break; + } + } + } + //create complex_type node + // + //<xs:element // maxOccurs="1" // minOccurs="0" // name="name"> // <xs:complexType> // </xs:complexType> //</xs:element> - if(complex_type_node.isNull()) - { - complex_type_node = mElementNode->createChild("xs:element", false); + if(complex_type_node.isNull()) + { + complex_type_node = mElementNode->createChild("xs:element", false); - complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); - complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); - complex_type_node->createChild("name", true)->setStringValue(element_name); - complex_type_node = complex_type_node->createChild("xs:complexType", false); - } + complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); + complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); + complex_type_node->createChild("name", true)->setStringValue(element_name); + complex_type_node = complex_type_node->createChild("xs:complexType", false); + } - addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); - } + addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); + } } void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values) { - if (!attribute_name.empty()) - { - LLXMLNodePtr new_enum_type_node; - if (possible_values != NULL) - { - // custom attribute type, for example - //<xs:simpleType> - // <xs:restriction - // base="xs:string"> - // <xs:enumeration - // value="a" /> - // <xs:enumeration - // value="b" /> - // </xs:restriction> - // </xs:simpleType> - new_enum_type_node = new LLXMLNode("xs:simpleType", false); - - LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); - restriction_node->createChild("base", true)->setStringValue("xs:string"); - - for (std::vector<std::string>::const_iterator it = possible_values->begin(); - it != possible_values->end(); - ++it) - { - LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); - enum_node->createChild("value", true)->setStringValue(*it); - } - } - - string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; - - string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); - - // attribute not yet declared - if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) - { - attributes_written.insert(found_it, attribute_name); - - LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); - - // attribute name - attribute_node->createChild("name", true)->setStringValue(attribute_name); - - if (new_enum_type_node.notNull()) - { - attribute_node->addChild(new_enum_type_node); - } - else - { - // simple attribute type - attribute_node->createChild("type", true)->setStringValue(type); - } - - // required or optional - attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); - } - // attribute exists...handle collision of same name attributes with potentially different types - else - { - LLXMLNodePtr attribute_declaration; - if (type_declaration_node.notNull()) - { - for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; - node.notNull(); - node = node->mPrev) - { - std::string name; - if (node->getAttributeString("name", name) && name == attribute_name) - { - attribute_declaration = node; - break; - } - } - } - - bool new_type_is_enum = new_enum_type_node.notNull(); - bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); - - // either type is enum, revert to string in collision - // don't bother to check for enum equivalence - if (new_type_is_enum || existing_type_is_enum) - { - if (attribute_declaration->hasAttribute("type")) - { - attribute_declaration->setAttributeString("type", "xs:string"); - } - else - { - attribute_declaration->createChild("type", true)->setStringValue("xs:string"); - } - attribute_declaration->deleteChildren("xs:simpleType"); - } - else - { - // check for collision of different standard types - std::string existing_type; - attribute_declaration->getAttributeString("type", existing_type); - // if current type is not the same as the new type, revert to strnig - if (existing_type != type) - { - // ...than use most general type, string - attribute_declaration->setAttributeString("type", "string"); - } - } - } - } + if (!attribute_name.empty()) + { + LLXMLNodePtr new_enum_type_node; + if (possible_values != NULL) + { + // custom attribute type, for example + //<xs:simpleType> + // <xs:restriction + // base="xs:string"> + // <xs:enumeration + // value="a" /> + // <xs:enumeration + // value="b" /> + // </xs:restriction> + // </xs:simpleType> + new_enum_type_node = new LLXMLNode("xs:simpleType", false); + + LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); + restriction_node->createChild("base", true)->setStringValue("xs:string"); + + for (std::vector<std::string>::const_iterator it = possible_values->begin(); + it != possible_values->end(); + ++it) + { + LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); + enum_node->createChild("value", true)->setStringValue(*it); + } + } + + string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; + + string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); + + // attribute not yet declared + if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) + { + attributes_written.insert(found_it, attribute_name); + + LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); + + // attribute name + attribute_node->createChild("name", true)->setStringValue(attribute_name); + + if (new_enum_type_node.notNull()) + { + attribute_node->addChild(new_enum_type_node); + } + else + { + // simple attribute type + attribute_node->createChild("type", true)->setStringValue(type); + } + + // required or optional + attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); + } + // attribute exists...handle collision of same name attributes with potentially different types + else + { + LLXMLNodePtr attribute_declaration; + if (type_declaration_node.notNull()) + { + for(LLXMLNodePtr node = type_declaration_node->mChildren->tail; + node.notNull(); + node = node->mPrev) + { + std::string name; + if (node->getAttributeString("name", name) && name == attribute_name) + { + attribute_declaration = node; + break; + } + } + } + + bool new_type_is_enum = new_enum_type_node.notNull(); + bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); + + // either type is enum, revert to string in collision + // don't bother to check for enum equivalence + if (new_type_is_enum || existing_type_is_enum) + { + if (attribute_declaration->hasAttribute("type")) + { + attribute_declaration->setAttributeString("type", "xs:string"); + } + else + { + attribute_declaration->createChild("type", true)->setStringValue("xs:string"); + } + attribute_declaration->deleteChildren("xs:simpleType"); + } + else + { + // check for collision of different standard types + std::string existing_type; + attribute_declaration->getAttributeString("type", existing_type); + // if current type is not the same as the new type, revert to strnig + if (existing_type != type) + { + // ...than use most general type, string + attribute_declaration->setAttributeString("type", "string"); + } + } + } + } } // @@ -595,84 +595,84 @@ void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const // void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block) { - std::string file_name(path); - file_name += type_name + ".xsd"; - LLXMLNodePtr root_nodep = new LLXMLNode(); - - LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); - - // add includes for all possible children - const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); - const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); - - // add choices for valid children - if (widget_registryp) - { - // add include declarations for all valid children - for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); - it != widget_registryp->currentRegistrar().endItems(); - ++it) - { - std::string widget_name = it->first; - if (widget_name == type_name) - { - continue; - } - LLXMLNodePtr nodep = new LLXMLNode("xs:include", false); - nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd"); - - // add to front of schema - mSchemaNode->addChild(nodep); - } - - for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); - it != widget_registryp->currentRegistrar().endItems(); - ++it) - { - std::string widget_name = it->first; - //<xs:element name="widget_name" type="widget_name"> - LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false); - widget_node->createChild("name", true)->setStringValue(widget_name); - widget_node->createChild("type", true)->setStringValue(widget_name); - } - } - - LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); - LLXMLNode::writeHeaderToFile(xsd_file); - root_nodep->writeToFile(xsd_file); - fclose(xsd_file); -} - -static LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs; + std::string file_name(path); + file_name += type_name + ".xsd"; + LLXMLNodePtr root_nodep = new LLXMLNode(); + + LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); + + // add includes for all possible children + const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); + const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); + + // add choices for valid children + if (widget_registryp) + { + // add include declarations for all valid children + for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); + it != widget_registryp->currentRegistrar().endItems(); + ++it) + { + std::string widget_name = it->first; + if (widget_name == type_name) + { + continue; + } + LLXMLNodePtr nodep = new LLXMLNode("xs:include", false); + nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd"); + + // add to front of schema + mSchemaNode->addChild(nodep); + } + + for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); + it != widget_registryp->currentRegistrar().endItems(); + ++it) + { + std::string widget_name = it->first; + //<xs:element name="widget_name" type="widget_name"> + LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false); + widget_node->createChild("name", true)->setStringValue(widget_name); + widget_node->createChild("type", true)->setStringValue(widget_name); + } + } + + LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); + LLXMLNode::writeHeaderToFile(xsd_file); + root_nodep->writeToFile(xsd_file); + fclose(xsd_file); +} + +static LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs; // // LLXUIParser // LLXUIParser::LLXUIParser() -: Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs), - mCurReadDepth(0) -{ - if (sXUIReadFuncs.empty()) - { - registerParserFuncs<LLInitParam::Flag>(readFlag, writeFlag); - registerParserFuncs<bool>(readBoolValue, writeBoolValue); - registerParserFuncs<std::string>(readStringValue, writeStringValue); - registerParserFuncs<U8>(readU8Value, writeU8Value); - registerParserFuncs<S8>(readS8Value, writeS8Value); - registerParserFuncs<U16>(readU16Value, writeU16Value); - registerParserFuncs<S16>(readS16Value, writeS16Value); - registerParserFuncs<U32>(readU32Value, writeU32Value); - registerParserFuncs<S32>(readS32Value, writeS32Value); - registerParserFuncs<F32>(readF32Value, writeF32Value); - registerParserFuncs<F64>(readF64Value, writeF64Value); - registerParserFuncs<LLVector3>(readVector3Value, writeVector3Value); - registerParserFuncs<LLColor4>(readColor4Value, writeColor4Value); - registerParserFuncs<LLUIColor>(readUIColorValue, writeUIColorValue); - registerParserFuncs<LLUUID>(readUUIDValue, writeUUIDValue); - registerParserFuncs<LLSD>(readSDValue, writeSDValue); - } +: Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs), + mCurReadDepth(0) +{ + if (sXUIReadFuncs.empty()) + { + registerParserFuncs<LLInitParam::Flag>(readFlag, writeFlag); + registerParserFuncs<bool>(readBoolValue, writeBoolValue); + registerParserFuncs<std::string>(readStringValue, writeStringValue); + registerParserFuncs<U8>(readU8Value, writeU8Value); + registerParserFuncs<S8>(readS8Value, writeS8Value); + registerParserFuncs<U16>(readU16Value, writeU16Value); + registerParserFuncs<S16>(readS16Value, writeS16Value); + registerParserFuncs<U32>(readU32Value, writeU32Value); + registerParserFuncs<S32>(readS32Value, writeS32Value); + registerParserFuncs<F32>(readF32Value, writeF32Value); + registerParserFuncs<F64>(readF64Value, writeF64Value); + registerParserFuncs<LLVector3>(readVector3Value, writeVector3Value); + registerParserFuncs<LLColor4>(readColor4Value, writeColor4Value); + registerParserFuncs<LLUIColor>(readUIColorValue, writeUIColorValue); + registerParserFuncs<LLUUID>(readUUIDValue, writeUUIDValue); + registerParserFuncs<LLSD>(readSDValue, writeSDValue); + } } static LLTrace::BlockTimerStatHandle FTM_PARSE_XUI("XUI Parsing"); @@ -680,643 +680,643 @@ const LLXMLNodePtr DUMMY_NODE = new LLXMLNode(); void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent) { - LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); - mNameStack.clear(); - mRootNodeName = node->getName()->mString; - mCurFileName = filename; - mCurReadDepth = 0; - setParseSilently(silent); + LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); + mNameStack.clear(); + mRootNodeName = node->getName()->mString; + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); - if (node.isNull()) - { - parserWarning("Invalid node"); - } - else - { - readXUIImpl(node, block); - } + if (node.isNull()) + { + parserWarning("Invalid node"); + } + else + { + readXUIImpl(node, block); + } } bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("."); - - bool values_parsed = false; - bool silent = mCurReadDepth > 0; - - if (nodep->getFirstChild().isNull() - && nodep->mAttributes.empty() - && nodep->getSanitizedValue().empty()) - { - // empty node, just parse as flag - mCurReadNode = DUMMY_NODE; - return block.submitValue(mNameStack, *this, silent); - } - - // submit attributes for current node - values_parsed |= readAttributes(nodep, block); - - // treat text contents of xml node as "value" parameter - std::string text_contents = nodep->getSanitizedValue(); - if (!text_contents.empty()) - { - mCurReadNode = nodep; - mNameStack.push_back(std::make_pair(std::string("value"), true)); - // child nodes are not necessarily valid parameters (could be a child widget) - // so don't complain once we've recursed - if (!block.submitValue(mNameStack, *this, true)) - { - mNameStack.pop_back(); - block.submitValue(mNameStack, *this, silent); - } - else - { - mNameStack.pop_back(); - } - } - - // then traverse children - // child node must start with last name of parent node (our "scope") - // for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>" - // which equates to the following nesting: - // button - // param - // nested_param1 - // nested_param2 - // nested_param3 - mCurReadDepth++; - for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) - { - std::string child_name(childp->getName()->mString); - S32 num_tokens_pushed = 0; - - // for non "dotted" child nodes check to see if child node maps to another widget type - // and if not, treat as a child element of the current node - // e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect" - // since there is no widget named "rect" - if (child_name.find(".") == std::string::npos) - { - mNameStack.push_back(std::make_pair(child_name, true)); - num_tokens_pushed++; - } - else - { - // parse out "dotted" name into individual tokens - tokenizer name_tokens(child_name, sep); - - tokenizer::iterator name_token_it = name_tokens.begin(); - if(name_token_it == name_tokens.end()) - { - childp = childp->getNextSibling(); - continue; - } - - // check for proper nesting - if (mNameStack.empty()) - { - if (*name_token_it != mRootNodeName) - { - childp = childp->getNextSibling(); - continue; - } - } - else if(mNameStack.back().first != *name_token_it) - { - childp = childp->getNextSibling(); - continue; - } - - // now ignore first token - ++name_token_it; - - // copy remaining tokens on to our running token list - for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) - { - mNameStack.push_back(std::make_pair(*token_to_push, true)); - num_tokens_pushed++; - } - } - - // recurse and visit children XML nodes - if(readXUIImpl(childp, block)) - { - // child node successfully parsed, remove from DOM - - values_parsed = true; - LLXMLNodePtr node_to_remove = childp; - childp = childp->getNextSibling(); - - nodep->deleteChild(node_to_remove); - } - else - { - childp = childp->getNextSibling(); - } - - while(num_tokens_pushed-- > 0) - { - mNameStack.pop_back(); - } - } - mCurReadDepth--; - return values_parsed; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("."); + + bool values_parsed = false; + bool silent = mCurReadDepth > 0; + + if (nodep->getFirstChild().isNull() + && nodep->mAttributes.empty() + && nodep->getSanitizedValue().empty()) + { + // empty node, just parse as flag + mCurReadNode = DUMMY_NODE; + return block.submitValue(mNameStack, *this, silent); + } + + // submit attributes for current node + values_parsed |= readAttributes(nodep, block); + + // treat text contents of xml node as "value" parameter + std::string text_contents = nodep->getSanitizedValue(); + if (!text_contents.empty()) + { + mCurReadNode = nodep; + mNameStack.push_back(std::make_pair(std::string("value"), true)); + // child nodes are not necessarily valid parameters (could be a child widget) + // so don't complain once we've recursed + if (!block.submitValue(mNameStack, *this, true)) + { + mNameStack.pop_back(); + block.submitValue(mNameStack, *this, silent); + } + else + { + mNameStack.pop_back(); + } + } + + // then traverse children + // child node must start with last name of parent node (our "scope") + // for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>" + // which equates to the following nesting: + // button + // param + // nested_param1 + // nested_param2 + // nested_param3 + mCurReadDepth++; + for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) + { + std::string child_name(childp->getName()->mString); + S32 num_tokens_pushed = 0; + + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect" + // since there is no widget named "rect" + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + childp = childp->getNextSibling(); + continue; + } + + // check for proper nesting + if (mNameStack.empty()) + { + if (*name_token_it != mRootNodeName) + { + childp = childp->getNextSibling(); + continue; + } + } + else if(mNameStack.back().first != *name_token_it) + { + childp = childp->getNextSibling(); + continue; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + } + + // recurse and visit children XML nodes + if(readXUIImpl(childp, block)) + { + // child node successfully parsed, remove from DOM + + values_parsed = true; + LLXMLNodePtr node_to_remove = childp; + childp = childp->getNextSibling(); + + nodep->deleteChild(node_to_remove); + } + else + { + childp = childp->getNextSibling(); + } + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + mCurReadDepth--; + return values_parsed; } bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("."); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("."); + + bool any_parsed = false; + bool silent = mCurReadDepth > 0; - bool any_parsed = false; - bool silent = mCurReadDepth > 0; + for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); + attribute_it != nodep->mAttributes.end(); + ++attribute_it) + { + S32 num_tokens_pushed = 0; + std::string attribute_name(attribute_it->first->mString); + mCurReadNode = attribute_it->second; - for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); - attribute_it != nodep->mAttributes.end(); - ++attribute_it) - { - S32 num_tokens_pushed = 0; - std::string attribute_name(attribute_it->first->mString); - mCurReadNode = attribute_it->second; + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } - tokenizer name_tokens(attribute_name, sep); - // copy remaining tokens on to our running token list - for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) - { - mNameStack.push_back(std::make_pair(*token_to_push, true)); - num_tokens_pushed++; - } + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= block.submitValue(mNameStack, *this, silent); - // child nodes are not necessarily valid attributes, so don't complain once we've recursed - any_parsed |= block.submitValue(mNameStack, *this, silent); - - while(num_tokens_pushed-- > 0) - { - mNameStack.pop_back(); - } - } + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } - return any_parsed; + return any_parsed; } void LLXUIParser::writeXUIImpl(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { - mWriteRootNode = node; - name_stack_t name_stack = Parser::name_stack_t(); - block.serializeBlock(*this, name_stack, rules, diff_block); - mOutNodes.clear(); + mWriteRootNode = node; + name_stack_t name_stack = Parser::name_stack_t(); + block.serializeBlock(*this, name_stack, rules, diff_block); + mOutNodes.clear(); } // go from a stack of names to a specific XML node LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack) { - LLXMLNodePtr out_node = mWriteRootNode; - - name_stack_t::iterator next_it = stack.begin(); - for (name_stack_t::iterator it = stack.begin(); - it != stack.end(); - it = next_it) - { - ++next_it; - bool force_new_node = false; - - if (it->first.empty()) - { - it->second = false; - continue; - } - - if (next_it != stack.end() && next_it->first.empty() && next_it->second) - { - force_new_node = true; - } - - - out_nodes_t::iterator found_it = mOutNodes.find(it->first); - - // node with this name not yet written - if (found_it == mOutNodes.end() || it->second || force_new_node) - { - // make an attribute if we are the last element on the name stack - bool is_attribute = next_it == stack.end(); - LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); - out_node->addChild(new_node); - mOutNodes[it->first] = new_node; - out_node = new_node; - it->second = false; - } - else - { - out_node = found_it->second; - } - } - - return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); + LLXMLNodePtr out_node = mWriteRootNode; + + name_stack_t::iterator next_it = stack.begin(); + for (name_stack_t::iterator it = stack.begin(); + it != stack.end(); + it = next_it) + { + ++next_it; + bool force_new_node = false; + + if (it->first.empty()) + { + it->second = false; + continue; + } + + if (next_it != stack.end() && next_it->first.empty() && next_it->second) + { + force_new_node = true; + } + + + out_nodes_t::iterator found_it = mOutNodes.find(it->first); + + // node with this name not yet written + if (found_it == mOutNodes.end() || it->second || force_new_node) + { + // make an attribute if we are the last element on the name stack + bool is_attribute = next_it == stack.end(); + LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); + out_node->addChild(new_node); + mOutNodes[it->first] = new_node; + out_node = new_node; + it->second = false; + } + else + { + out_node = found_it->second; + } + } + + return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); } bool LLXUIParser::readFlag(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode == DUMMY_NODE; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode == DUMMY_NODE; } bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack) { - // just create node - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - return node.notNull(); + // just create node + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + return node.notNull(); } bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) { - S32 value; - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - bool success = self.mCurReadNode->getBoolValue(1, &value); - *((bool*)val_ptr) = (value != FALSE); - return success; + S32 value; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + bool success = self.mCurReadNode->getBoolValue(1, &value); + *((bool*)val_ptr) = (value != FALSE); + return success; } bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setBoolValue(*((bool*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setBoolValue(*((bool*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - *((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); - return true; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + *((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); + return true; } bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr); - if (string_val->find('\n') != std::string::npos - || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) - { - // don't write strings with newlines into attributes - std::string attribute_name = node->getName()->mString; - LLXMLNodePtr parent_node = node->mParent; - parent_node->deleteChild(node); - // write results in text contents of node - if (attribute_name == "value") - { - // "value" is implicit, just write to parent - node = parent_node; - } - else - { - // create a child that is not an attribute, but with same name - node = parent_node->createChild(attribute_name.c_str(), false); - } - } - node->setStringValue(*string_val); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr); + if (string_val->find('\n') != std::string::npos + || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + // create a child that is not an attribute, but with same name + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + node->setStringValue(*string_val); + return true; + } + return false; } bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); } bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setUnsignedValue(*((U8*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U8*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - S32 value; - if(self.mCurReadNode->getIntValue(1, &value)) - { - *((S8*)val_ptr) = value; - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S8*)val_ptr) = value; + return true; + } + return false; } bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setIntValue(*((S8*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S8*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - U32 value; - if(self.mCurReadNode->getUnsignedValue(1, &value)) - { - *((U16*)val_ptr) = value; - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + U32 value; + if(self.mCurReadNode->getUnsignedValue(1, &value)) + { + *((U16*)val_ptr) = value; + return true; + } + return false; } bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setUnsignedValue(*((U16*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U16*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - S32 value; - if(self.mCurReadNode->getIntValue(1, &value)) - { - *((S16*)val_ptr) = value; - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S16*)val_ptr) = value; + return true; + } + return false; } bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setIntValue(*((S16*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S16*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); } bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setUnsignedValue(*((U32*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U32*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); } bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setIntValue(*((S32*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S32*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); } bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setFloatValue(*((F32*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setFloatValue(*((F32*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); } bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setDoubleValue(*((F64*)val_ptr)); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setDoubleValue(*((F64*)val_ptr)); + return true; + } + return false; } bool LLXUIParser::readVector3Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLVector3* vecp = (LLVector3*)val_ptr; - if(self.mCurReadNode->getFloatValue(3, vecp->mV) >= 3) - { - return true; - } + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLVector3* vecp = (LLVector3*)val_ptr; + if(self.mCurReadNode->getFloatValue(3, vecp->mV) >= 3) + { + return true; + } - return false; + return false; } bool LLXUIParser::writeVector3Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - LLVector3 vector = *((LLVector3*)val_ptr); - node->setFloatValue(3, vector.mV); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLVector3 vector = *((LLVector3*)val_ptr); + node->setFloatValue(3, vector.mV); + return true; + } + return false; } bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLColor4* colorp = (LLColor4*)val_ptr; - if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) - { - return true; - } + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLColor4* colorp = (LLColor4*)val_ptr; + if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + { + return true; + } - return false; + return false; } bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - LLColor4 color = *((LLColor4*)val_ptr); - node->setFloatValue(4, color.mV); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLColor4 color = *((LLColor4*)val_ptr); + node->setFloatValue(4, color.mV); + return true; + } + return false; } bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLUIColor* param = (LLUIColor*)val_ptr; - LLColor4 color; - bool success = self.mCurReadNode->getFloatValue(4, color.mV) >= 3; - if (success) - { - param->set(color); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLUIColor* param = (LLUIColor*)val_ptr; + LLColor4 color; + bool success = self.mCurReadNode->getFloatValue(4, color.mV) >= 3; + if (success) + { + param->set(color); + return true; + } + return false; } bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - LLUIColor color = *((LLUIColor*)val_ptr); - //RN: don't write out the color that is represented by a function - // rely on param block exporting to get the reference to the color settings - if (color.isReference()) return false; - node->setFloatValue(4, color.get().mV); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLUIColor color = *((LLUIColor*)val_ptr); + //RN: don't write out the color that is represented by a function + // rely on param block exporting to get the reference to the color settings + if (color.isReference()) return false; + node->setFloatValue(4, color.get().mV); + return true; + } + return false; } bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLUUID temp_id; - // LLUUID::set is destructive, so use temporary value - if (temp_id.set(self.mCurReadNode->getSanitizedValue())) - { - *(LLUUID*)(val_ptr) = temp_id; - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(self.mCurReadNode->getSanitizedValue())) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; } bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - node->setStringValue(((LLUUID*)val_ptr)->asString()); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLUUID*)val_ptr)->asString()); + return true; + } + return false; } bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - *((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); - return true; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); + return true; } bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) { - LLXUIParser& self = static_cast<LLXUIParser&>(parser); - - LLXMLNodePtr node = self.getNode(stack); - if (node.notNull()) - { - std::string string_val = ((LLSD*)val_ptr)->asString(); - if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) - { - // don't write strings with newlines into attributes - std::string attribute_name = node->getName()->mString; - LLXMLNodePtr parent_node = node->mParent; - parent_node->deleteChild(node); - // write results in text contents of node - if (attribute_name == "value") - { - // "value" is implicit, just write to parent - node = parent_node; - } - else - { - node = parent_node->createChild(attribute_name.c_str(), false); - } - } - - node->setStringValue(string_val); - return true; - } - return false; + LLXUIParser& self = static_cast<LLXUIParser&>(parser); + + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + std::string string_val = ((LLSD*)val_ptr)->asString(); + if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + + node->setStringValue(string_val); + return true; + } + return false; } /*virtual*/ std::string LLXUIParser::getCurrentElementName() { - std::string full_name; - for (name_stack_t::iterator it = mNameStack.begin(); - it != mNameStack.end(); - ++it) - { - full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." - } + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } - return full_name; + return full_name; } void LLXUIParser::parserWarning(const std::string& message) { - std::string warning_msg = llformat("%s:\t%s(%d)", message.c_str(), mCurFileName.c_str(), mCurReadNode->getLineNumber()); - Parser::parserWarning(warning_msg); + std::string warning_msg = llformat("%s:\t%s(%d)", message.c_str(), mCurFileName.c_str(), mCurReadNode->getLineNumber()); + Parser::parserWarning(warning_msg); } void LLXUIParser::parserError(const std::string& message) { - std::string error_msg = llformat("%s:\t%s(%d)", message.c_str(), mCurFileName.c_str(), mCurReadNode->getLineNumber()); - Parser::parserError(error_msg); + std::string error_msg = llformat("%s:\t%s(%d)", message.c_str(), mCurFileName.c_str(), mCurReadNode->getLineNumber()); + Parser::parserError(error_msg); } @@ -1326,55 +1326,55 @@ void LLXUIParser::parserError(const std::string& message) struct ScopedFile { - ScopedFile( const std::string& filename, const char* accessmode ) - { - mFile = LLFile::fopen(filename, accessmode); - } + ScopedFile( const std::string& filename, const char* accessmode ) + { + mFile = LLFile::fopen(filename, accessmode); + } - ~ScopedFile() - { - fclose(mFile); - mFile = NULL; - } + ~ScopedFile() + { + fclose(mFile); + mFile = NULL; + } - S32 getRemainingBytes() - { - if (!isOpen()) return 0; + S32 getRemainingBytes() + { + if (!isOpen()) return 0; - S32 cur_pos = ftell(mFile); - fseek(mFile, 0L, SEEK_END); - S32 file_size = ftell(mFile); - fseek(mFile, cur_pos, SEEK_SET); - return file_size - cur_pos; - } + S32 cur_pos = ftell(mFile); + fseek(mFile, 0L, SEEK_END); + S32 file_size = ftell(mFile); + fseek(mFile, cur_pos, SEEK_SET); + return file_size - cur_pos; + } - bool isOpen() { return mFile != NULL; } + bool isOpen() { return mFile != NULL; } - LLFILE* mFile; + LLFILE* mFile; }; LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb) -: Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), - mCurReadDepth(0), - mElementCB(element_cb) -{ - if (sSimpleXUIReadFuncs.empty()) - { - registerParserFuncs<LLInitParam::Flag>(readFlag); - registerParserFuncs<bool>(readBoolValue); - registerParserFuncs<std::string>(readStringValue); - registerParserFuncs<U8>(readU8Value); - registerParserFuncs<S8>(readS8Value); - registerParserFuncs<U16>(readU16Value); - registerParserFuncs<S16>(readS16Value); - registerParserFuncs<U32>(readU32Value); - registerParserFuncs<S32>(readS32Value); - registerParserFuncs<F32>(readF32Value); - registerParserFuncs<F64>(readF64Value); - registerParserFuncs<LLColor4>(readColor4Value); - registerParserFuncs<LLUIColor>(readUIColorValue); - registerParserFuncs<LLUUID>(readUUIDValue); - registerParserFuncs<LLSD>(readSDValue); - } +: Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), + mCurReadDepth(0), + mElementCB(element_cb) +{ + if (sSimpleXUIReadFuncs.empty()) + { + registerParserFuncs<LLInitParam::Flag>(readFlag); + registerParserFuncs<bool>(readBoolValue); + registerParserFuncs<std::string>(readStringValue); + registerParserFuncs<U8>(readU8Value); + registerParserFuncs<S8>(readS8Value); + registerParserFuncs<U16>(readU16Value); + registerParserFuncs<S16>(readS16Value); + registerParserFuncs<U32>(readU32Value); + registerParserFuncs<S32>(readS32Value); + registerParserFuncs<F32>(readF32Value); + registerParserFuncs<F64>(readF64Value); + registerParserFuncs<LLColor4>(readColor4Value); + registerParserFuncs<LLUIColor>(readUIColorValue); + registerParserFuncs<LLUUID>(readUUIDValue); + registerParserFuncs<LLSD>(readSDValue); + } } LLSimpleXUIParser::~LLSimpleXUIParser() @@ -1384,382 +1384,382 @@ LLSimpleXUIParser::~LLSimpleXUIParser() bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) { - LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); - - mParser = XML_ParserCreate(NULL); - XML_SetUserData(mParser, this); - XML_SetElementHandler( mParser, startElementHandler, endElementHandler); - XML_SetCharacterDataHandler( mParser, characterDataHandler); - - mOutputStack.push_back(std::make_pair(&block, 0)); - mNameStack.clear(); - mCurFileName = filename; - mCurReadDepth = 0; - setParseSilently(silent); - - ScopedFile file(filename, "rb"); - if( !file.isOpen() ) - { - LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; - XML_ParserFree( mParser ); - return false; - } - - S32 bytes_read = 0; - - S32 buffer_size = file.getRemainingBytes(); - void* buffer = XML_GetBuffer(mParser, buffer_size); - if( !buffer ) - { - LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; - XML_ParserFree( mParser ); - return false; - } - - bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); - if( bytes_read <= 0 ) - { - LL_WARNS("ReadXUI") << "Error while reading file " << filename << LL_ENDL; - XML_ParserFree( mParser ); - return false; - } - - mEmptyLeafNode.push_back(false); - - if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) - { - LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL; - XML_ParserFree( mParser ); - return false; - } - - mEmptyLeafNode.pop_back(); - - XML_ParserFree( mParser ); - return true; + LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); + + mParser = XML_ParserCreate(NULL); + XML_SetUserData(mParser, this); + XML_SetElementHandler( mParser, startElementHandler, endElementHandler); + XML_SetCharacterDataHandler( mParser, characterDataHandler); + + mOutputStack.push_back(std::make_pair(&block, 0)); + mNameStack.clear(); + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); + + ScopedFile file(filename, "rb"); + if( !file.isOpen() ) + { + LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + S32 bytes_read = 0; + + S32 buffer_size = file.getRemainingBytes(); + void* buffer = XML_GetBuffer(mParser, buffer_size); + if( !buffer ) + { + LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); + if( bytes_read <= 0 ) + { + LL_WARNS("ReadXUI") << "Error while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.push_back(false); + + if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) + { + LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.pop_back(); + + XML_ParserFree( mParser ); + return true; } void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) { - LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); - self->startElement(name, atts); + LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); + self->startElement(name, atts); } void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) { - LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); - self->endElement(name); + LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); + self->endElement(name); } void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) { - LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); - self->characterData(s, len); + LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); + self->characterData(s, len); } void LLSimpleXUIParser::characterData(const char *s, int len) { - mTextContents += std::string(s, len); + mTextContents += std::string(s, len); } void LLSimpleXUIParser::startElement(const char *name, const char **atts) { - processText(); - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("."); - - if (mElementCB) - { - LLInitParam::BaseBlock* blockp = mElementCB(*this, name); - if (blockp) - { - mOutputStack.push_back(std::make_pair(blockp, 0)); - } - } - - mOutputStack.back().second++; - S32 num_tokens_pushed = 0; - std::string child_name(name); - - if (mOutputStack.back().second == 1) - { // root node for this block - mScope.push_back(child_name); - } - else - { // compound attribute - if (child_name.find(".") == std::string::npos) - { - mNameStack.push_back(std::make_pair(child_name, true)); - num_tokens_pushed++; - mScope.push_back(child_name); - } - else - { - // parse out "dotted" name into individual tokens - tokenizer name_tokens(child_name, sep); - - tokenizer::iterator name_token_it = name_tokens.begin(); - if(name_token_it == name_tokens.end()) - { - return; - } - - // check for proper nesting - if(!mScope.empty() && *name_token_it != mScope.back()) - { - return; - } - - // now ignore first token - ++name_token_it; - - // copy remaining tokens on to our running token list - for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) - { - mNameStack.push_back(std::make_pair(*token_to_push, true)); - num_tokens_pushed++; - } - mScope.push_back(mNameStack.back().first); - } - } - - // parent node is not empty - mEmptyLeafNode.back() = false; - // we are empty if we have no attributes - mEmptyLeafNode.push_back(atts[0] == NULL); - - mTokenSizeStack.push_back(num_tokens_pushed); - readAttributes(atts); + processText(); + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("."); + + if (mElementCB) + { + LLInitParam::BaseBlock* blockp = mElementCB(*this, name); + if (blockp) + { + mOutputStack.push_back(std::make_pair(blockp, 0)); + } + } + + mOutputStack.back().second++; + S32 num_tokens_pushed = 0; + std::string child_name(name); + + if (mOutputStack.back().second == 1) + { // root node for this block + mScope.push_back(child_name); + } + else + { // compound attribute + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + mScope.push_back(child_name); + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + return; + } + + // check for proper nesting + if(!mScope.empty() && *name_token_it != mScope.back()) + { + return; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + mScope.push_back(mNameStack.back().first); + } + } + + // parent node is not empty + mEmptyLeafNode.back() = false; + // we are empty if we have no attributes + mEmptyLeafNode.push_back(atts[0] == NULL); + + mTokenSizeStack.push_back(num_tokens_pushed); + readAttributes(atts); } void LLSimpleXUIParser::endElement(const char *name) { - bool has_text = processText(); - - // no text, attributes, or children - if (!has_text && mEmptyLeafNode.back()) - { - // submit this as a valueless name (even though there might be text contents we haven't seen yet) - mCurAttributeValueBegin = NO_VALUE_MARKER; - mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); - } - - if (--mOutputStack.back().second == 0) - { - if (mOutputStack.empty()) - { - LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; - } - mOutputStack.pop_back(); - } - - S32 num_tokens_to_pop = mTokenSizeStack.back(); - mTokenSizeStack.pop_back(); - while(num_tokens_to_pop-- > 0) - { - mNameStack.pop_back(); - } - mScope.pop_back(); - mEmptyLeafNode.pop_back(); + bool has_text = processText(); + + // no text, attributes, or children + if (!has_text && mEmptyLeafNode.back()) + { + // submit this as a valueless name (even though there might be text contents we haven't seen yet) + mCurAttributeValueBegin = NO_VALUE_MARKER; + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + } + + if (--mOutputStack.back().second == 0) + { + if (mOutputStack.empty()) + { + LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; + } + mOutputStack.pop_back(); + } + + S32 num_tokens_to_pop = mTokenSizeStack.back(); + mTokenSizeStack.pop_back(); + while(num_tokens_to_pop-- > 0) + { + mNameStack.pop_back(); + } + mScope.pop_back(); + mEmptyLeafNode.pop_back(); } bool LLSimpleXUIParser::readAttributes(const char **atts) { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("."); - - bool any_parsed = false; - for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) - { - std::string attribute_name(atts[i]); - mCurAttributeValueBegin = atts[i+1]; - - S32 num_tokens_pushed = 0; - tokenizer name_tokens(attribute_name, sep); - // copy remaining tokens on to our running token list - for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) - { - mNameStack.push_back(std::make_pair(*token_to_push, true)); - num_tokens_pushed++; - } - - // child nodes are not necessarily valid attributes, so don't complain once we've recursed - any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); - - while(num_tokens_pushed-- > 0) - { - mNameStack.pop_back(); - } - } - return any_parsed; + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("."); + + bool any_parsed = false; + for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) + { + std::string attribute_name(atts[i]); + mCurAttributeValueBegin = atts[i+1]; + + S32 num_tokens_pushed = 0; + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + return any_parsed; } bool LLSimpleXUIParser::processText() { - if (!mTextContents.empty()) - { - LLStringUtil::trim(mTextContents); - if (!mTextContents.empty()) - { - mNameStack.push_back(std::make_pair(std::string("value"), true)); - mCurAttributeValueBegin = mTextContents.c_str(); - mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); - mNameStack.pop_back(); - } - mTextContents.clear(); - return true; - } - return false; + if (!mTextContents.empty()) + { + LLStringUtil::trim(mTextContents); + if (!mTextContents.empty()) + { + mNameStack.push_back(std::make_pair(std::string("value"), true)); + mCurAttributeValueBegin = mTextContents.c_str(); + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + mNameStack.pop_back(); + } + mTextContents.clear(); + return true; + } + return false; } /*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName() { - std::string full_name; - for (name_stack_t::iterator it = mNameStack.begin(); - it != mNameStack.end(); - ++it) - { - full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." - } + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } - return full_name; + return full_name; } void LLSimpleXUIParser::parserWarning(const std::string& message) { - std::string warning_msg = llformat("%s:\t%s", message.c_str(), mCurFileName.c_str()); - Parser::parserWarning(warning_msg); + std::string warning_msg = llformat("%s:\t%s", message.c_str(), mCurFileName.c_str()); + Parser::parserWarning(warning_msg); } void LLSimpleXUIParser::parserError(const std::string& message) { - std::string error_msg = llformat("%s:\t%s", message.c_str(), mCurFileName.c_str()); - Parser::parserError(error_msg); + std::string error_msg = llformat("%s:\t%s", message.c_str(), mCurFileName.c_str()); + Parser::parserError(error_msg); } bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return self.mCurAttributeValueBegin == NO_VALUE_MARKER; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return self.mCurAttributeValueBegin == NO_VALUE_MARKER; } bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - if (!strcmp(self.mCurAttributeValueBegin, "true")) - { - *((bool*)val_ptr) = true; - return true; - } - else if (!strcmp(self.mCurAttributeValueBegin, "false")) - { - *((bool*)val_ptr) = false; - return true; - } + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + if (!strcmp(self.mCurAttributeValueBegin, "true")) + { + *((bool*)val_ptr) = true; + return true; + } + else if (!strcmp(self.mCurAttributeValueBegin, "false")) + { + *((bool*)val_ptr) = false; + return true; + } - return false; + return false; } bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - *((std::string*)val_ptr) = self.mCurAttributeValueBegin; - return true; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + *((std::string*)val_ptr) = self.mCurAttributeValueBegin; + return true; } bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; } bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; } bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; } bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; } bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; } bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; } bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; } bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; } - + bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - LLColor4 value; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + LLColor4 value; - if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) - { - *(LLColor4*)(val_ptr) = value; - return true; - } - return false; + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + *(LLColor4*)(val_ptr) = value; + return true; + } + return false; } bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - LLColor4 value; - LLUIColor* colorp = (LLUIColor*)val_ptr; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + LLColor4 value; + LLUIColor* colorp = (LLUIColor*)val_ptr; - if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) - { - colorp->set(value); - return true; - } - return false; + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + colorp->set(value); + return true; + } + return false; } bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - LLUUID temp_id; - // LLUUID::set is destructive, so use temporary value - if (temp_id.set(std::string(self.mCurAttributeValueBegin))) - { - *(LLUUID*)(val_ptr) = temp_id; - return true; - } - return false; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(std::string(self.mCurAttributeValueBegin))) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; } bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) { - LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); - *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); - return true; + LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); + return true; } diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h index eb0eac8194..f755c12cbf 100644 --- a/indra/llui/llxuiparser.h +++ b/indra/llui/llxuiparser.h @@ -1,25 +1,25 @@ -/** +/** * @file llxuiparser.h * @brief Utility functions for handling XUI structures in XML * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,9 +40,9 @@ class LLView; // lookup widget type by name class LLWidgetTypeRegistry -: public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry> +: public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry> { - LLSINGLETON_EMPTY_CTOR(LLWidgetTypeRegistry); + LLSINGLETON_EMPTY_CTOR(LLWidgetTypeRegistry); }; @@ -54,30 +54,30 @@ typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t; class LLChildRegistryRegistry : public LLRegistrySingleton<const std::type_info*, widget_registry_t, LLChildRegistryRegistry> { - LLSINGLETON_EMPTY_CTOR(LLChildRegistryRegistry); + LLSINGLETON_EMPTY_CTOR(LLChildRegistryRegistry); }; class LLXSDWriter : public LLInitParam::Parser { - LOG_CLASS(LLXSDWriter); + LOG_CLASS(LLXSDWriter); public: - void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); - /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } - /*virtual*/ std::string getCurrentFileName() { return LLStringUtil::null; } - LLXSDWriter(); - ~LLXSDWriter(); + /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + /*virtual*/ std::string getCurrentFileName() { return LLStringUtil::null; } + LLXSDWriter(); + ~LLXSDWriter(); protected: - void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); - void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values); - LLXMLNodePtr mAttributeNode; - LLXMLNodePtr mElementNode; - LLXMLNodePtr mSchemaNode; - - typedef std::set<std::string> string_set_t; - typedef std::map<LLXMLNodePtr, string_set_t> attributes_map_t; - attributes_map_t mAttributesWritten; + void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); + void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values); + LLXMLNodePtr mAttributeNode; + LLXMLNodePtr mElementNode; + LLXMLNodePtr mSchemaNode; + + typedef std::set<std::string> string_set_t; + typedef std::map<LLXMLNodePtr, string_set_t> attributes_map_t; + attributes_map_t mAttributesWritten; }; @@ -87,7 +87,7 @@ protected: class LLXUIXSDWriter : public LLXSDWriter { public: - void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); + void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); }; @@ -98,97 +98,97 @@ class LLXUIParser : public LLInitParam::Parser LOG_CLASS(LLXUIParser); public: - LLXUIParser(); - typedef LLInitParam::Parser::name_stack_t name_stack_t; - - /*virtual*/ std::string getCurrentElementName(); - /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } - /*virtual*/ void parserWarning(const std::string& message); - /*virtual*/ void parserError(const std::string& message); - - void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); - template<typename BLOCK> - void writeXUI(LLXMLNodePtr node, - const BLOCK& block, - const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), - const LLInitParam::BaseBlock* diff_block = NULL) - { - if (!diff_block - && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) - { - diff_block = &LLInitParam::defaultValue<BLOCK>(); - } - writeXUIImpl(node, block, rules, diff_block); - } + LLXUIParser(); + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); + template<typename BLOCK> + void writeXUI(LLXMLNodePtr node, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue<BLOCK>(); + } + writeXUIImpl(node, block, rules, diff_block); + } private: - LLXUIParser(const LLXUIParser& other); // no-copy - void writeXUIImpl(LLXMLNodePtr node, - const LLInitParam::BaseBlock& block, - const LLInitParam::predicate_rule_t rules, - const LLInitParam::BaseBlock* diff_block); - bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); - bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); - - //reader helper functions - static bool readFlag(Parser& parser, void* val_ptr); - static bool readBoolValue(Parser& parser, void* val_ptr); - static bool readStringValue(Parser& parser, void* val_ptr); - static bool readU8Value(Parser& parser, void* val_ptr); - static bool readS8Value(Parser& parser, void* val_ptr); - static bool readU16Value(Parser& parser, void* val_ptr); - static bool readS16Value(Parser& parser, void* val_ptr); - static bool readU32Value(Parser& parser, void* val_ptr); - static bool readS32Value(Parser& parser, void* val_ptr); - static bool readF32Value(Parser& parser, void* val_ptr); - static bool readF64Value(Parser& parser, void* val_ptr); - static bool readVector3Value(Parser& parser, void* val_ptr); - static bool readColor4Value(Parser& parser, void* val_ptr); - static bool readUIColorValue(Parser& parser, void* val_ptr); - static bool readUUIDValue(Parser& parser, void* val_ptr); - static bool readSDValue(Parser& parser, void* val_ptr); - - //writer helper functions - static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeVector3Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); - static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); - - LLXMLNodePtr getNode(name_stack_t& stack); + LLXUIParser(const LLXUIParser& other); // no-copy + void writeXUIImpl(LLXMLNodePtr node, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t rules, + const LLInitParam::BaseBlock* diff_block); + bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + static bool readFlag(Parser& parser, void* val_ptr); + static bool readBoolValue(Parser& parser, void* val_ptr); + static bool readStringValue(Parser& parser, void* val_ptr); + static bool readU8Value(Parser& parser, void* val_ptr); + static bool readS8Value(Parser& parser, void* val_ptr); + static bool readU16Value(Parser& parser, void* val_ptr); + static bool readS16Value(Parser& parser, void* val_ptr); + static bool readU32Value(Parser& parser, void* val_ptr); + static bool readS32Value(Parser& parser, void* val_ptr); + static bool readF32Value(Parser& parser, void* val_ptr); + static bool readF64Value(Parser& parser, void* val_ptr); + static bool readVector3Value(Parser& parser, void* val_ptr); + static bool readColor4Value(Parser& parser, void* val_ptr); + static bool readUIColorValue(Parser& parser, void* val_ptr); + static bool readUUIDValue(Parser& parser, void* val_ptr); + static bool readSDValue(Parser& parser, void* val_ptr); + + //writer helper functions + static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeVector3Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); + + LLXMLNodePtr getNode(name_stack_t& stack); private: - Parser::name_stack_t mNameStack; - LLXMLNodePtr mCurReadNode; - // Root of the widget XML sub-tree, for example, "line_editor" - LLXMLNodePtr mWriteRootNode; - - typedef std::map<std::string, LLXMLNodePtr> out_nodes_t; - out_nodes_t mOutNodes; - LLXMLNodePtr mLastWrittenChild; - S32 mCurReadDepth; - std::string mCurFileName; - std::string mRootNodeName; + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + + typedef std::map<std::string, LLXMLNodePtr> out_nodes_t; + out_nodes_t mOutNodes; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mRootNodeName; }; -// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization +// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization // or parsing of a tree of independent param blocks, such as child widgets. // Use this for reading non-localized files that only need a single param block as a result. // // NOTE: In order to support nested block parsing, we need callbacks for start element that // push new blocks contexts on the mScope stack. -// NOTE: To support localization without building a DOM, we need to enforce consistent +// NOTE: To support localization without building a DOM, we need to enforce consistent // ordering of child elements from base file to localized diff file. Then we can use a pair // of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead // of coroutines would offset the gain from SAX parsing @@ -198,62 +198,62 @@ class LLSimpleXUIParser : public LLInitParam::Parser { LOG_CLASS(LLSimpleXUIParser); public: - typedef LLInitParam::Parser::name_stack_t name_stack_t; - typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); + typedef LLInitParam::Parser::name_stack_t name_stack_t; + typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); - LLSimpleXUIParser(element_start_callback_t element_cb = NULL); - virtual ~LLSimpleXUIParser(); + LLSimpleXUIParser(element_start_callback_t element_cb = NULL); + virtual ~LLSimpleXUIParser(); - /*virtual*/ std::string getCurrentElementName(); - /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } - /*virtual*/ void parserWarning(const std::string& message); - /*virtual*/ void parserError(const std::string& message); + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); - bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); private: - //reader helper functions - static bool readFlag(Parser&, void* val_ptr); - static bool readBoolValue(Parser&, void* val_ptr); - static bool readStringValue(Parser&, void* val_ptr); - static bool readU8Value(Parser&, void* val_ptr); - static bool readS8Value(Parser&, void* val_ptr); - static bool readU16Value(Parser&, void* val_ptr); - static bool readS16Value(Parser&, void* val_ptr); - static bool readU32Value(Parser&, void* val_ptr); - static bool readS32Value(Parser&, void* val_ptr); - static bool readF32Value(Parser&, void* val_ptr); - static bool readF64Value(Parser&, void* val_ptr); - static bool readColor4Value(Parser&, void* val_ptr); - static bool readUIColorValue(Parser&, void* val_ptr); - static bool readUUIDValue(Parser&, void* val_ptr); - static bool readSDValue(Parser&, void* val_ptr); + //reader helper functions + static bool readFlag(Parser&, void* val_ptr); + static bool readBoolValue(Parser&, void* val_ptr); + static bool readStringValue(Parser&, void* val_ptr); + static bool readU8Value(Parser&, void* val_ptr); + static bool readS8Value(Parser&, void* val_ptr); + static bool readU16Value(Parser&, void* val_ptr); + static bool readS16Value(Parser&, void* val_ptr); + static bool readU32Value(Parser&, void* val_ptr); + static bool readS32Value(Parser&, void* val_ptr); + static bool readF32Value(Parser&, void* val_ptr); + static bool readF64Value(Parser&, void* val_ptr); + static bool readColor4Value(Parser&, void* val_ptr); + static bool readUIColorValue(Parser&, void* val_ptr); + static bool readUUIDValue(Parser&, void* val_ptr); + static bool readSDValue(Parser&, void* val_ptr); private: - static void startElementHandler(void *userData, const char *name, const char **atts); - static void endElementHandler(void *userData, const char *name); - static void characterDataHandler(void *userData, const char *s, int len); - - void startElement(const char *name, const char **atts); - void endElement(const char *name); - void characterData(const char *s, int len); - bool readAttributes(const char **atts); - bool processText(); - - Parser::name_stack_t mNameStack; - struct XML_ParserStruct* mParser; - LLXMLNodePtr mLastWrittenChild; - S32 mCurReadDepth; - std::string mCurFileName; - std::string mTextContents; - const char* mCurAttributeValueBegin; - std::vector<S32> mTokenSizeStack; - std::vector<std::string> mScope; - std::vector<bool> mEmptyLeafNode; - element_start_callback_t mElementCB; - - std::vector<std::pair<LLInitParam::BaseBlock*, S32> > mOutputStack; + static void startElementHandler(void *userData, const char *name, const char **atts); + static void endElementHandler(void *userData, const char *name); + static void characterDataHandler(void *userData, const char *s, int len); + + void startElement(const char *name, const char **atts); + void endElement(const char *name); + void characterData(const char *s, int len); + bool readAttributes(const char **atts); + bool processText(); + + Parser::name_stack_t mNameStack; + struct XML_ParserStruct* mParser; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mTextContents; + const char* mCurAttributeValueBegin; + std::vector<S32> mTokenSizeStack; + std::vector<std::string> mScope; + std::vector<bool> mEmptyLeafNode; + element_start_callback_t mElementCB; + + std::vector<std::pair<LLInitParam::BaseBlock*, S32> > mOutputStack; }; diff --git a/indra/llui/llxyvector.cpp b/indra/llui/llxyvector.cpp index d7ba243e1d..9fc31488a5 100644 --- a/indra/llui/llxyvector.cpp +++ b/indra/llui/llxyvector.cpp @@ -25,7 +25,7 @@ * $/LicenseInfo$ */ -// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. #include "linden_common.h" @@ -158,7 +158,7 @@ void drawArrow(S32 tailX, S32 tailY, S32 tipX, S32 tipY, LLColor4 color) S32 dy = tipY - tailY; S32 arrowLength = (abs(dx) < ARROW_LENGTH_LONG && abs(dy) < ARROW_LENGTH_LONG) ? ARROW_LENGTH_SHORT : ARROW_LENGTH_LONG; - + F32 theta = std::atan2(dy, dx); F32 rad = ARROW_ANGLE * std::atan(1) * 4 / 180; diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h index bb3822dd26..6bebf347e8 100644 --- a/indra/llui/llxyvector.h +++ b/indra/llui/llxyvector.h @@ -25,7 +25,7 @@ * $/LicenseInfo$ */ -// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. +// A control that allows to set two related vector magnitudes by manipulating a single vector on a plane. #ifndef LL_LLXYVECTOR_H #define LL_LLXYVECTOR_H @@ -42,13 +42,13 @@ public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<LLLineEditor::Params> x_entry; - Optional<LLLineEditor::Params> y_entry; - Optional<LLPanel::Params> touch_area; - Optional<LLViewBorder::Params> border; - Optional<S32> edit_bar_height; - Optional<S32> padding; - Optional<S32> label_width; + Optional<LLLineEditor::Params> x_entry; + Optional<LLLineEditor::Params> y_entry; + Optional<LLPanel::Params> touch_area; + Optional<LLViewBorder::Params> border; + Optional<S32> edit_bar_height; + Optional<S32> padding; + Optional<S32> label_width; Optional<F32> min_val_x; Optional<F32> max_val_x; Optional<F32> increment_x; @@ -68,15 +68,15 @@ public: virtual ~LLXYVector(); /*virtual*/ BOOL postBuild(); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual void draw(); + virtual void draw(); - virtual void setValue(const LLSD& value); - void setValue(F32 x, F32 y); - virtual LLSD getValue() const; + virtual void setValue(const LLSD& value); + void setValue(F32 x, F32 y); + virtual LLSD getValue() const; protected: friend class LLUICtrlFactory; @@ -86,10 +86,10 @@ protected: protected: LLTextBox* mXLabel; LLTextBox* mYLabel; - LLLineEditor* mXEntry; - LLLineEditor* mYEntry; + LLLineEditor* mXEntry; + LLLineEditor* mYEntry; LLPanel* mTouchArea; - LLViewBorder* mBorder; + LLViewBorder* mBorder; private: void update(); diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index 338be1808d..95d1586495 100755 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,13 +38,13 @@ // Stub for LLAvatarNameCache bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { - return false; + return false; } LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { - callback_connection_t connection; - return connection; + callback_connection_t connection; + return connection; } // @@ -52,24 +52,24 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag // BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) { - fullname = "Lynx Linden"; - return TRUE; + fullname = "Lynx Linden"; + return TRUE; } BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) { - group = "My Group"; - return TRUE; + group = "My Group"; + return TRUE; } boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback) { - return boost::signals2::connection(); + return boost::signals2::connection(); } boost::signals2::connection LLCacheName::getGroup(const LLUUID& id, const LLCacheNameCallback& callback) { - return boost::signals2::connection(); + return boost::signals2::connection(); } LLCacheName* gCacheName = NULL; @@ -80,12 +80,12 @@ LLCacheName* gCacheName = NULL; class LLTrans { public: - static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); + static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); }; std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { - return std::string(); + return std::string(); } // @@ -102,65 +102,65 @@ LLStyle::Params::Params() namespace LLInitParam { - ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) - : super_t(color) - {} - - void ParamValue<LLUIColor>::updateValueFromBlock() - {} - - void ParamValue<LLUIColor>::updateBlockFromValue(bool) - {} - - bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) - { - return false; - } - - ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) - : super_t(fontp) - {} - - void ParamValue<const LLFontGL*>::updateValueFromBlock() - {} - - void ParamValue<const LLFontGL*>::updateBlockFromValue(bool) - {} - - void TypeValues<LLFontGL::HAlign>::declareValues() - {} - - void TypeValues<LLFontGL::VAlign>::declareValues() - {} - - void TypeValues<LLFontGL::ShadowType>::declareValues() - {} - - void ParamValue<LLUIImage*>::updateValueFromBlock() - {} - - void ParamValue<LLUIImage*>::updateBlockFromValue(bool) - {} - - - bool ParamCompare<LLUIImage*, false>::equals( - LLUIImage* const &a, - LLUIImage* const &b) - { - return false; - } - - bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) - { - return false; - } + ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) + : super_t(color) + {} + + void ParamValue<LLUIColor>::updateValueFromBlock() + {} + + void ParamValue<LLUIColor>::updateBlockFromValue(bool) + {} + + bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) + { + return false; + } + + ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) + : super_t(fontp) + {} + + void ParamValue<const LLFontGL*>::updateValueFromBlock() + {} + + void ParamValue<const LLFontGL*>::updateBlockFromValue(bool) + {} + + void TypeValues<LLFontGL::HAlign>::declareValues() + {} + + void TypeValues<LLFontGL::VAlign>::declareValues() + {} + + void TypeValues<LLFontGL::ShadowType>::declareValues() + {} + + void ParamValue<LLUIImage*>::updateValueFromBlock() + {} + + void ParamValue<LLUIImage*>::updateBlockFromValue(bool) + {} + + + bool ParamCompare<LLUIImage*, false>::equals( + LLUIImage* const &a, + LLUIImage* const &b) + { + return false; + } + + bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) + { + return false; + } } //static LLFontGL* LLFontGL::getFontDefault() { - return NULL; + return NULL; } char const* const _PREHASH_AgentData = (char *)"AgentData"; diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 1a474cca90..729b983e79 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,12 +46,12 @@ // { // const LLSD& get( const LLUUID& key) // { -// static LLSD boo; +// static LLSD boo; // return boo; // } -// +// // void get( const LLUUID& key, callback_slot_t slot ){} -// +// // } /*==========================================================================*| @@ -60,12 +60,12 @@ settings_map_t LLUI::sSettingGroups; BOOL LLControlGroup::getBOOL(const std::string& name) { - return false; + return false; } LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const { - return LLUIColor(); + return LLUIColor(); } LLUIColor::LLUIColor() : mColorPtr(NULL) {} @@ -81,855 +81,855 @@ LLUIImage::~LLUIImage() //virtual S32 LLUIImage::getWidth() const { - return 0; + return 0; } //virtual S32 LLUIImage::getHeight() const { - return 0; + return 0; } |*==========================================================================*/ namespace tut { - struct LLUrlEntryData - { - }; + struct LLUrlEntryData + { + }; - typedef test_group<LLUrlEntryData> factory; - typedef factory::object object; + typedef test_group<LLUrlEntryData> factory; + typedef factory::object object; } namespace { - tut::factory tf("LLUrlEntry"); + tut::factory tf("LLUrlEntry"); } namespace tut { - void testRegex(const std::string &testname, LLUrlEntryBase &entry, - const char *text, const std::string &expected) - { - boost::regex regex = entry.getPattern(); - std::string url = ""; - boost::cmatch result; - bool found = boost::regex_search(text, result, regex); - if (found) - { - S32 start = static_cast<U32>(result[0].first - text); - S32 end = static_cast<U32>(result[0].second - text); - url = entry.getUrl(std::string(text+start, end-start)); - } - ensure_equals(testname, url, expected); - } - - void dummyCallback(const std::string &url, const std::string &label, const std::string& icon) - { - } - - void testLabel(const std::string &testname, LLUrlEntryBase &entry, - const char *text, const std::string &expected) - { - boost::regex regex = entry.getPattern(); - std::string label = ""; - boost::cmatch result; - bool found = boost::regex_search(text, result, regex); - if (found) - { - S32 start = static_cast<U32>(result[0].first - text); - S32 end = static_cast<U32>(result[0].second - text); - std::string url = std::string(text+start, end-start); - label = entry.getLabel(url, boost::bind(dummyCallback, _1, _2, _3)); - } - ensure_equals(testname, label, expected); - } - - void testLocation(const std::string &testname, LLUrlEntryBase &entry, - const char *text, const std::string &expected) - { - boost::regex regex = entry.getPattern(); - std::string location = ""; - boost::cmatch result; - bool found = boost::regex_search(text, result, regex); - if (found) - { - S32 start = static_cast<U32>(result[0].first - text); - S32 end = static_cast<U32>(result[0].second - text); - std::string url = std::string(text+start, end-start); - location = entry.getLocation(url); - } - ensure_equals(testname, location, expected); - } - - - template<> template<> - void object::test<1>() - { - // - // test LLUrlEntryHTTP - standard http Urls - // - LLUrlEntryHTTP url; - - testRegex("no valid url", url, - "htp://slurl.com/", - ""); - - testRegex("simple http (1)", url, - "http://slurl.com/", - "http://slurl.com/"); - - testRegex("simple http (2)", url, - "http://slurl.com", - "http://slurl.com"); - - testRegex("simple http (3)", url, - "http://slurl.com/about.php", - "http://slurl.com/about.php"); - - testRegex("simple https", url, - "https://slurl.com/about.php", - "https://slurl.com/about.php"); - - testRegex("http in text (1)", url, - "XX http://slurl.com/ XX", - "http://slurl.com/"); - - testRegex("http in text (2)", url, - "XX http://slurl.com/about.php XX", - "http://slurl.com/about.php"); - - testRegex("https in text", url, - "XX https://slurl.com/about.php XX", - "https://slurl.com/about.php"); - - testRegex("two http urls", url, - "XX http://slurl.com/about.php http://secondlife.com/ XX", - "http://slurl.com/about.php"); - - testRegex("http url with port and username", url, - "XX http://nobody@slurl.com:80/about.php http://secondlife.com/ XX", - "http://nobody@slurl.com:80/about.php"); - - testRegex("http url with port, username, and query string", url, - "XX http://nobody@slurl.com:80/about.php?title=hi%20there http://secondlife.com/ XX", - "http://nobody@slurl.com:80/about.php?title=hi%20there"); - - // note: terminating commas will be removed by LLUrlRegistry:findUrl() - testRegex("http url with commas in middle and terminating", url, - "XX http://slurl.com/?title=Hi,There, XX", - "http://slurl.com/?title=Hi,There,"); - - // note: terminating periods will be removed by LLUrlRegistry:findUrl() - testRegex("http url with periods in middle and terminating", url, - "XX http://slurl.com/index.php. XX", - "http://slurl.com/index.php."); - - // DEV-19842: Closing parenthesis ")" breaks urls - testRegex("http url with brackets (1)", url, - "XX http://en.wikipedia.org/wiki/JIRA_(software) XX", - "http://en.wikipedia.org/wiki/JIRA_(software)"); - - // DEV-19842: Closing parenthesis ")" breaks urls - testRegex("http url with brackets (2)", url, - "XX http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg XX", - "http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg"); - - // DEV-10353: URLs in chat log terminated incorrectly when newline in chat - testRegex("http url with newlines", url, - "XX\nhttp://www.secondlife.com/\nXX", - "http://www.secondlife.com/"); - - testRegex("http url without tld shouldn't be decorated (1)", url, - "http://test", - ""); - - testRegex("http url without tld shouldn't be decorated (2)", url, - "http://test .com", - ""); - } - - template<> template<> - void object::test<2>() - { - // - // test LLUrlEntryHTTPLabel - wiki-style http Urls with labels - // - LLUrlEntryHTTPLabel url; - - testRegex("invalid wiki url [1]", url, - "[http://www.example.org]", - ""); - - testRegex("invalid wiki url [2]", url, - "[http://www.example.org", - ""); - - testRegex("invalid wiki url [3]", url, - "[http://www.example.org Label", - ""); - - testRegex("example.org with label (spaces)", url, - "[http://www.example.org Text]", - "http://www.example.org"); - - testRegex("example.org with label (tabs)", url, - "[http://www.example.org\t Text]", - "http://www.example.org"); - - testRegex("SL http URL with label", url, - "[http://www.secondlife.com/ Second Life]", - "http://www.secondlife.com/"); - - testRegex("SL https URL with label", url, - "XXX [https://www.secondlife.com/ Second Life] YYY", - "https://www.secondlife.com/"); - - testRegex("SL http URL with label", url, - "[http://www.secondlife.com/?test=Hi%20There Second Life]", - "http://www.secondlife.com/?test=Hi%20There"); - } - - template<> template<> - void object::test<3>() - { - // - // test LLUrlEntrySLURL - second life URLs - // - LLUrlEntrySLURL url; - - testRegex("no valid slurl [1]", url, - "htp://slurl.com/secondlife/Ahern/50/50/50/", - ""); - - testRegex("no valid slurl [2]", url, - "http://slurl.com/secondlife/", - ""); - - testRegex("no valid slurl [3]", url, - "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", - ""); - - testRegex("Ahern (50,50,50) [1]", url, - "http://slurl.com/secondlife/Ahern/50/50/50/", - "http://slurl.com/secondlife/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [2]", url, - "XXX http://slurl.com/secondlife/Ahern/50/50/50/ XXX", - "http://slurl.com/secondlife/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [3]", url, - "XXX http://slurl.com/secondlife/Ahern/50/50/50 XXX", - "http://slurl.com/secondlife/Ahern/50/50/50"); - - testRegex("Ahern (50,50,50) multicase", url, - "XXX http://SLUrl.com/SecondLife/Ahern/50/50/50/ XXX", - "http://SLUrl.com/SecondLife/Ahern/50/50/50/"); - - testRegex("Ahern (50,50) [1]", url, - "XXX http://slurl.com/secondlife/Ahern/50/50/ XXX", - "http://slurl.com/secondlife/Ahern/50/50/"); - - testRegex("Ahern (50,50) [2]", url, - "XXX http://slurl.com/secondlife/Ahern/50/50 XXX", - "http://slurl.com/secondlife/Ahern/50/50"); - - testRegex("Ahern (50)", url, - "XXX http://slurl.com/secondlife/Ahern/50 XXX", - "http://slurl.com/secondlife/Ahern/50"); - - testRegex("Ahern", url, - "XXX http://slurl.com/secondlife/Ahern/ XXX", - "http://slurl.com/secondlife/Ahern/"); - - testRegex("Ahern SLURL with title", url, - "XXX http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", - "http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); - - testRegex("Ahern SLURL with msg", url, - "XXX http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here. XXX", - "http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here."); - - // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat - testRegex("SLURL with brackets", url, - "XXX http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30 XXX", - "http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30"); - - // DEV-35459: SLURLs and teleport Links not parsed properly - testRegex("SLURL with quote", url, - "XXX http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701 XXX", - "http://slurl.com/secondlife/A%27ksha%20Oasis/41/166/701"); - } - - template<> template<> - void object::test<4>() - { - // - // test LLUrlEntryAgent - secondlife://app/agent Urls - // - LLUrlEntryAgent url; - - testRegex("Invalid Agent Url", url, - "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about", - ""); - - testRegex("Agent Url ", url, - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("Agent Url in text", url, - "XXX secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about XXX", - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("Agent Url multicase", url, - "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX", - "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About"); - - testRegex("Agent Url alternate command", url, - "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar", - "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar"); - - testRegex("Standalone Agent Url ", url, - "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", - "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("Standalone Agent Url Multicase with Text", url, - "M x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", - "x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - } - - template<> template<> - void object::test<5>() - { - // - // test LLUrlEntryGroup - secondlife://app/group Urls - // - LLUrlEntryGroup url; - - testRegex("Invalid Group Url", url, - "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about", - ""); - - testRegex("Group Url ", url, - "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about", - "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); - - testRegex("Group Url ", url, - "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect", - "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect"); - - testRegex("Group Url in text", url, - "XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX", - "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); - - testRegex("Group Url multicase", url, - "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX", - "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About"); - - testRegex("Standalone Group Url ", url, - "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", - "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("Standalone Group Url Multicase ith Text", url, - "M x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", - "x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - } - - template<> template<> - void object::test<6>() - { - // - // test LLUrlEntryPlace - secondlife://<location> URLs - // - LLUrlEntryPlace url; - - testRegex("no valid slurl [1]", url, - "secondlife://Ahern/FOO/50/", - ""); - - testRegex("Ahern (50,50,50) [1]", url, - "secondlife://Ahern/50/50/50/", - "secondlife://Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [2]", url, - "XXX secondlife://Ahern/50/50/50/ XXX", - "secondlife://Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [3]", url, - "XXX secondlife://Ahern/50/50/50 XXX", - "secondlife://Ahern/50/50/50"); - - testRegex("Ahern (50,50,50) multicase", url, - "XXX SecondLife://Ahern/50/50/50/ XXX", - "SecondLife://Ahern/50/50/50/"); - - testRegex("Ahern (50,50) [1]", url, - "XXX secondlife://Ahern/50/50/ XXX", - "secondlife://Ahern/50/50/"); - - testRegex("Ahern (50,50) [2]", url, - "XXX secondlife://Ahern/50/50 XXX", - "secondlife://Ahern/50/50"); - - // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat - testRegex("SLURL with brackets", url, - "XXX secondlife://Burning%20Life%20(Hyper)/27/210/30 XXX", - "secondlife://Burning%20Life%20(Hyper)/27/210/30"); - - // DEV-35459: SLURLs and teleport Links not parsed properly - testRegex("SLURL with quote", url, - "XXX secondlife://A'ksha%20Oasis/41/166/701 XXX", - "secondlife://A%27ksha%20Oasis/41/166/701"); - - testRegex("Standalone All Hands (50,50) [2] with text", url, - "XXX x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50 XXX", - "x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50"); - } - - template<> template<> - void object::test<7>() - { - // - // test LLUrlEntryParcel - secondlife://app/parcel Urls - // - LLUrlEntryParcel url; - - testRegex("Invalid Classified Url", url, - "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about", - ""); - - testRegex("Classified Url ", url, - "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about", - "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); - - testRegex("Classified Url in text", url, - "XXX secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about XXX", - "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); - - testRegex("Classified Url multicase", url, - "XXX secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About XXX", - "secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About"); - } - template<> template<> - void object::test<8>() - { - // - // test LLUrlEntryTeleport - secondlife://app/teleport URLs - // - LLUrlEntryTeleport url; - - testRegex("no valid teleport [1]", url, - "http://slurl.com/secondlife/Ahern/50/50/50/", - ""); - - testRegex("no valid teleport [2]", url, - "secondlife:///app/teleport/", - ""); - - testRegex("no valid teleport [3]", url, - "second-life:///app/teleport/Ahern/50/50/50/", - ""); - - testRegex("no valid teleport [3]", url, - "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", - ""); - - testRegex("Ahern (50,50,50) [1]", url, - "secondlife:///app/teleport/Ahern/50/50/50/", - "secondlife:///app/teleport/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [2]", url, - "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", - "secondlife:///app/teleport/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [3]", url, - "XXX secondlife:///app/teleport/Ahern/50/50/50 XXX", - "secondlife:///app/teleport/Ahern/50/50/50"); - - testRegex("Ahern (50,50,50) multicase", url, - "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", - "secondlife:///app/teleport/Ahern/50/50/50/"); - - testRegex("Ahern (50,50) [1]", url, - "XXX secondlife:///app/teleport/Ahern/50/50/ XXX", - "secondlife:///app/teleport/Ahern/50/50/"); - - testRegex("Ahern (50,50) [2]", url, - "XXX secondlife:///app/teleport/Ahern/50/50 XXX", - "secondlife:///app/teleport/Ahern/50/50"); - - testRegex("Ahern (50)", url, - "XXX secondlife:///app/teleport/Ahern/50 XXX", - "secondlife:///app/teleport/Ahern/50"); - - testRegex("Ahern", url, - "XXX secondlife:///app/teleport/Ahern/ XXX", - "secondlife:///app/teleport/Ahern/"); - - testRegex("Ahern teleport with title", url, - "XXX secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", - "secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); - - testRegex("Ahern teleport with msg", url, - "XXX secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here. XXX", - "secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here."); - - // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat - testRegex("Teleport with brackets", url, - "XXX secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30 XXX", - "secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30"); - - // DEV-35459: SLURLs and teleport Links not parsed properly - testRegex("Teleport url with quote", url, - "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX", - "secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701"); - - testRegex("Standalone All Hands", url, - "XXX x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50 XXX", - "x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50"); - } - - template<> template<> - void object::test<9>() - { - // - // test LLUrlEntrySL - general secondlife:// URLs - // - LLUrlEntrySL url; - - testRegex("no valid slapp [1]", url, - "http:///app/", - ""); - - testRegex("valid slapp [1]", url, - "secondlife:///app/", - "secondlife:///app/"); - - testRegex("valid slapp [2]", url, - "secondlife:///app/teleport/Ahern/50/50/50/", - "secondlife:///app/teleport/Ahern/50/50/50/"); - - testRegex("valid slapp [3]", url, - "secondlife:///app/foo", - "secondlife:///app/foo"); - - testRegex("valid slapp [4]", url, - "secondlife:///APP/foo?title=Hi%20There", - "secondlife:///APP/foo?title=Hi%20There"); - - testRegex("valid slapp [5]", url, - "secondlife://host/app/", - "secondlife://host/app/"); - - testRegex("valid slapp [6]", url, - "secondlife://host:8080/foo/bar", - "secondlife://host:8080/foo/bar"); - } - - template<> template<> - void object::test<10>() - { - // - // test LLUrlEntrySLLabel - general secondlife:// URLs with labels - // - LLUrlEntrySLLabel url; - - testRegex("invalid wiki url [1]", url, - "[secondlife:///app/]", - ""); - - testRegex("invalid wiki url [2]", url, - "[secondlife:///app/", - ""); - - testRegex("invalid wiki url [3]", url, - "[secondlife:///app/ Label", - ""); - - testRegex("agent slurl with label (spaces)", url, - "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]", - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("agent slurl with label (tabs)", url, - "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]", - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("agent slurl with label", url, - "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]", - "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); - - testRegex("teleport slurl with label", url, - "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY", - "secondlife:///app/teleport/Ahern/50/50/50/"); - } - - template<> template<> - void object::test<11>() - { - // - // test LLUrlEntryNoLink - turn off hyperlinking - // - LLUrlEntryNoLink url; - - testRegex("<nolink> [1]", url, - "<nolink>google.com</nolink>", - "google.com"); - - testRegex("<nolink> [2]", url, - "<nolink>google.com", - ""); - - testRegex("<nolink> [3]", url, - "google.com</nolink>", - ""); - - testRegex("<nolink> [4]", url, - "<nolink>Hello World</nolink>", - "Hello World"); - - testRegex("<nolink> [5]", url, - "<nolink>My Object</nolink>", - "My Object"); - } - - template<> template<> - void object::test<12>() - { - // - // test LLUrlEntryRegion - secondlife:///app/region/<location> URLs - // - LLUrlEntryRegion url; - - // Regex tests. - testRegex("no valid region", url, - "secondlife:///app/region/", - ""); - - testRegex("invalid coords", url, - "secondlife:///app/region/Korea2/a/b/c", - "secondlife:///app/region/Korea2/"); // don't count invalid coords - - testRegex("Ahern (50,50,50) [1]", url, - "secondlife:///app/region/Ahern/50/50/50/", - "secondlife:///app/region/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [2]", url, - "XXX secondlife:///app/region/Ahern/50/50/50/ XXX", - "secondlife:///app/region/Ahern/50/50/50/"); - - testRegex("Ahern (50,50,50) [3]", url, - "XXX secondlife:///app/region/Ahern/50/50/50 XXX", - "secondlife:///app/region/Ahern/50/50/50"); - - testRegex("Ahern (50,50,50) multicase", url, - "XXX secondlife:///app/region/Ahern/50/50/50/ XXX", - "secondlife:///app/region/Ahern/50/50/50/"); - - testRegex("Ahern (50,50) [1]", url, - "XXX secondlife:///app/region/Ahern/50/50/ XXX", - "secondlife:///app/region/Ahern/50/50/"); - - testRegex("Ahern (50,50) [2]", url, - "XXX secondlife:///app/region/Ahern/50/50 XXX", - "secondlife:///app/region/Ahern/50/50"); - - // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat - testRegex("Region with brackets", url, - "XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX", - "secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30"); - - // Rendering tests. - testLabel("Render /app/region/Ahern/50/50/50/", url, - "secondlife:///app/region/Ahern/50/50/50/", - "Ahern (50,50,50)"); - - testLabel("Render /app/region/Ahern/50/50/50", url, - "secondlife:///app/region/Ahern/50/50/50", - "Ahern (50,50,50)"); - - testLabel("Render /app/region/Ahern/50/50/", url, - "secondlife:///app/region/Ahern/50/50/", - "Ahern (50,50)"); - - testLabel("Render /app/region/Ahern/50/50", url, - "secondlife:///app/region/Ahern/50/50", - "Ahern (50,50)"); - - testLabel("Render /app/region/Ahern/50/", url, - "secondlife:///app/region/Ahern/50/", - "Ahern (50)"); - - testLabel("Render /app/region/Ahern/50", url, - "secondlife:///app/region/Ahern/50", - "Ahern (50)"); - - testLabel("Render /app/region/Ahern/", url, - "secondlife:///app/region/Ahern/", - "Ahern"); - - testLabel("Render /app/region/Ahern/ within context", url, - "XXX secondlife:///app/region/Ahern/ XXX", - "Ahern"); - - testLabel("Render /app/region/Ahern", url, - "secondlife:///app/region/Ahern", - "Ahern"); - - testLabel("Render /app/region/Ahern within context", url, - "XXX secondlife:///app/region/Ahern XXX", - "Ahern"); - - testLabel("Render /app/region/Product%20Engine/", url, - "secondlife:///app/region/Product%20Engine/", - "Product Engine"); - - testLabel("Render /app/region/Product%20Engine", url, - "secondlife:///app/region/Product%20Engine", - "Product Engine"); - - // Location parsing texts. - testLocation("Location /app/region/Ahern/50/50/50/", url, - "secondlife:///app/region/Ahern/50/50/50/", - "Ahern"); - - testLocation("Location /app/region/Product%20Engine", url, - "secondlife:///app/region/Product%20Engine", - "Product Engine"); - } - - template<> template<> - void object::test<13>() - { - // - // test LLUrlEntryemail - general emails - // - LLUrlEntryEmail url; - - // Regex tests. - testRegex("match e-mail addresses", url, - "test@lindenlab.com", - "mailto:test@lindenlab.com"); - - testRegex("match e-mail addresses with mailto: prefix", url, - "mailto:test@lindenlab.com", - "mailto:test@lindenlab.com"); - - testRegex("match e-mail addresses with different domains", url, - "test@foo.org.us", - "mailto:test@foo.org.us"); - - testRegex("match e-mail addresses with different domains", url, - "test@foo.bar", - "mailto:test@foo.bar"); - - testRegex("don't match incorrect e-mail addresses", url, - "test @foo.com", - ""); - - testRegex("don't match incorrect e-mail addresses", url, - "test@ foo.com", - ""); - } - - template<> template<> - void object::test<14>() - { - // - // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls - // - LLUrlEntrySecondlifeURL url; - - testRegex("match urls with protocol", url, - "this url should match http://lindenlab.com/products/second-life", - "http://lindenlab.com/products/second-life"); - - testRegex("match urls with protocol", url, - "search something https://marketplace.secondlife.com/products/search on marketplace and test the https", - "https://marketplace.secondlife.com/products/search"); - - testRegex("match HTTPS urls with port", url, - "let's specify some port https://secondlife.com:888/status", - "https://secondlife.com:888/status"); - - testRegex("don't match HTTP urls with port", url, - "let's specify some port for HTTP http://secondlife.com:888/status", - ""); - - testRegex("don't match urls w/o protocol", url, - "looks like an url something www.marketplace.secondlife.com/products but no https prefix", - ""); - - testRegex("but with a protocol www is fine", url, - "so let's add a protocol https://www.marketplace.secondlife.com:8888/products", - "https://www.marketplace.secondlife.com:8888/products"); - - testRegex("don't match urls w/o protocol", url, - "and even no www something secondlife.com/status", - ""); - } - - template<> template<> - void object::test<15>() - { - // - // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls - // - - LLUrlEntrySimpleSecondlifeURL url; - - testRegex("match urls with a protocol", url, - "this url should match http://lindenlab.com", - "http://lindenlab.com"); - - testRegex("match urls with a protocol", url, - "search something https://marketplace.secondlife.com on marketplace and test the https", - "https://marketplace.secondlife.com"); - - testRegex("don't match urls w/o protocol", url, - "looks like an url something www.marketplace.secondlife.com but no https prefix", - ""); - - testRegex("but with a protocol www is fine", url, - "so let's add a protocol http://www.marketplace.secondlife.com", - "http://www.marketplace.secondlife.com"); - - testRegex("don't match urls w/o protocol", url, - "and even no www something lindenlab.com", - ""); - } - - template<> template<> - void object::test<16>() - { - // - // test LLUrlEntryIPv6 - // - LLUrlEntryIPv6 url; - - // Regex tests. - testRegex("match urls with a protocol", url, - "this url should match http://[::1]", - "http://[::1]"); - - testRegex("match urls with a protocol and query", url, - "this url should match http://[::1]/file.mp3", - "http://[::1]/file.mp3"); - - testRegex("match urls with a protocol", url, - "this url should match http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]", - "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]"); - - testRegex("match urls with port", url, - "let's specify some port http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080", - "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080"); - - testRegex("don't match urls w/o protocol", url, - "looks like an url something [2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d] but no https prefix", - ""); - - testRegex("don't match incorrect urls", url, - "http://[ 2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d ]", - ""); - } + void testRegex(const std::string &testname, LLUrlEntryBase &entry, + const char *text, const std::string &expected) + { + boost::regex regex = entry.getPattern(); + std::string url = ""; + boost::cmatch result; + bool found = boost::regex_search(text, result, regex); + if (found) + { + S32 start = static_cast<U32>(result[0].first - text); + S32 end = static_cast<U32>(result[0].second - text); + url = entry.getUrl(std::string(text+start, end-start)); + } + ensure_equals(testname, url, expected); + } + + void dummyCallback(const std::string &url, const std::string &label, const std::string& icon) + { + } + + void testLabel(const std::string &testname, LLUrlEntryBase &entry, + const char *text, const std::string &expected) + { + boost::regex regex = entry.getPattern(); + std::string label = ""; + boost::cmatch result; + bool found = boost::regex_search(text, result, regex); + if (found) + { + S32 start = static_cast<U32>(result[0].first - text); + S32 end = static_cast<U32>(result[0].second - text); + std::string url = std::string(text+start, end-start); + label = entry.getLabel(url, boost::bind(dummyCallback, _1, _2, _3)); + } + ensure_equals(testname, label, expected); + } + + void testLocation(const std::string &testname, LLUrlEntryBase &entry, + const char *text, const std::string &expected) + { + boost::regex regex = entry.getPattern(); + std::string location = ""; + boost::cmatch result; + bool found = boost::regex_search(text, result, regex); + if (found) + { + S32 start = static_cast<U32>(result[0].first - text); + S32 end = static_cast<U32>(result[0].second - text); + std::string url = std::string(text+start, end-start); + location = entry.getLocation(url); + } + ensure_equals(testname, location, expected); + } + + + template<> template<> + void object::test<1>() + { + // + // test LLUrlEntryHTTP - standard http Urls + // + LLUrlEntryHTTP url; + + testRegex("no valid url", url, + "htp://slurl.com/", + ""); + + testRegex("simple http (1)", url, + "http://slurl.com/", + "http://slurl.com/"); + + testRegex("simple http (2)", url, + "http://slurl.com", + "http://slurl.com"); + + testRegex("simple http (3)", url, + "http://slurl.com/about.php", + "http://slurl.com/about.php"); + + testRegex("simple https", url, + "https://slurl.com/about.php", + "https://slurl.com/about.php"); + + testRegex("http in text (1)", url, + "XX http://slurl.com/ XX", + "http://slurl.com/"); + + testRegex("http in text (2)", url, + "XX http://slurl.com/about.php XX", + "http://slurl.com/about.php"); + + testRegex("https in text", url, + "XX https://slurl.com/about.php XX", + "https://slurl.com/about.php"); + + testRegex("two http urls", url, + "XX http://slurl.com/about.php http://secondlife.com/ XX", + "http://slurl.com/about.php"); + + testRegex("http url with port and username", url, + "XX http://nobody@slurl.com:80/about.php http://secondlife.com/ XX", + "http://nobody@slurl.com:80/about.php"); + + testRegex("http url with port, username, and query string", url, + "XX http://nobody@slurl.com:80/about.php?title=hi%20there http://secondlife.com/ XX", + "http://nobody@slurl.com:80/about.php?title=hi%20there"); + + // note: terminating commas will be removed by LLUrlRegistry:findUrl() + testRegex("http url with commas in middle and terminating", url, + "XX http://slurl.com/?title=Hi,There, XX", + "http://slurl.com/?title=Hi,There,"); + + // note: terminating periods will be removed by LLUrlRegistry:findUrl() + testRegex("http url with periods in middle and terminating", url, + "XX http://slurl.com/index.php. XX", + "http://slurl.com/index.php."); + + // DEV-19842: Closing parenthesis ")" breaks urls + testRegex("http url with brackets (1)", url, + "XX http://en.wikipedia.org/wiki/JIRA_(software) XX", + "http://en.wikipedia.org/wiki/JIRA_(software)"); + + // DEV-19842: Closing parenthesis ")" breaks urls + testRegex("http url with brackets (2)", url, + "XX http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg XX", + "http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg"); + + // DEV-10353: URLs in chat log terminated incorrectly when newline in chat + testRegex("http url with newlines", url, + "XX\nhttp://www.secondlife.com/\nXX", + "http://www.secondlife.com/"); + + testRegex("http url without tld shouldn't be decorated (1)", url, + "http://test", + ""); + + testRegex("http url without tld shouldn't be decorated (2)", url, + "http://test .com", + ""); + } + + template<> template<> + void object::test<2>() + { + // + // test LLUrlEntryHTTPLabel - wiki-style http Urls with labels + // + LLUrlEntryHTTPLabel url; + + testRegex("invalid wiki url [1]", url, + "[http://www.example.org]", + ""); + + testRegex("invalid wiki url [2]", url, + "[http://www.example.org", + ""); + + testRegex("invalid wiki url [3]", url, + "[http://www.example.org Label", + ""); + + testRegex("example.org with label (spaces)", url, + "[http://www.example.org Text]", + "http://www.example.org"); + + testRegex("example.org with label (tabs)", url, + "[http://www.example.org\t Text]", + "http://www.example.org"); + + testRegex("SL http URL with label", url, + "[http://www.secondlife.com/ Second Life]", + "http://www.secondlife.com/"); + + testRegex("SL https URL with label", url, + "XXX [https://www.secondlife.com/ Second Life] YYY", + "https://www.secondlife.com/"); + + testRegex("SL http URL with label", url, + "[http://www.secondlife.com/?test=Hi%20There Second Life]", + "http://www.secondlife.com/?test=Hi%20There"); + } + + template<> template<> + void object::test<3>() + { + // + // test LLUrlEntrySLURL - second life URLs + // + LLUrlEntrySLURL url; + + testRegex("no valid slurl [1]", url, + "htp://slurl.com/secondlife/Ahern/50/50/50/", + ""); + + testRegex("no valid slurl [2]", url, + "http://slurl.com/secondlife/", + ""); + + testRegex("no valid slurl [3]", url, + "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", + ""); + + testRegex("Ahern (50,50,50) [1]", url, + "http://slurl.com/secondlife/Ahern/50/50/50/", + "http://slurl.com/secondlife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", url, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/ XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", url, + "XXX http://slurl.com/secondlife/Ahern/50/50/50 XXX", + "http://slurl.com/secondlife/Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", url, + "XXX http://SLUrl.com/SecondLife/Ahern/50/50/50/ XXX", + "http://SLUrl.com/SecondLife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", url, + "XXX http://slurl.com/secondlife/Ahern/50/50/ XXX", + "http://slurl.com/secondlife/Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", url, + "XXX http://slurl.com/secondlife/Ahern/50/50 XXX", + "http://slurl.com/secondlife/Ahern/50/50"); + + testRegex("Ahern (50)", url, + "XXX http://slurl.com/secondlife/Ahern/50 XXX", + "http://slurl.com/secondlife/Ahern/50"); + + testRegex("Ahern", url, + "XXX http://slurl.com/secondlife/Ahern/ XXX", + "http://slurl.com/secondlife/Ahern/"); + + testRegex("Ahern SLURL with title", url, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); + + testRegex("Ahern SLURL with msg", url, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here. XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here."); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("SLURL with brackets", url, + "XXX http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30 XXX", + "http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30"); + + // DEV-35459: SLURLs and teleport Links not parsed properly + testRegex("SLURL with quote", url, + "XXX http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701 XXX", + "http://slurl.com/secondlife/A%27ksha%20Oasis/41/166/701"); + } + + template<> template<> + void object::test<4>() + { + // + // test LLUrlEntryAgent - secondlife://app/agent Urls + // + LLUrlEntryAgent url; + + testRegex("Invalid Agent Url", url, + "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about", + ""); + + testRegex("Agent Url ", url, + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Agent Url in text", url, + "XXX secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about XXX", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Agent Url multicase", url, + "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX", + "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About"); + + testRegex("Agent Url alternate command", url, + "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar", + "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar"); + + testRegex("Standalone Agent Url ", url, + "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Standalone Agent Url Multicase with Text", url, + "M x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", + "x-grid-location-info://lincoln.lindenlab.com/app/AGENT/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + } + + template<> template<> + void object::test<5>() + { + // + // test LLUrlEntryGroup - secondlife://app/group Urls + // + LLUrlEntryGroup url; + + testRegex("Invalid Group Url", url, + "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about", + ""); + + testRegex("Group Url ", url, + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about", + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); + + testRegex("Group Url ", url, + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect", + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect"); + + testRegex("Group Url in text", url, + "XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX", + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); + + testRegex("Group Url multicase", url, + "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX", + "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About"); + + testRegex("Standalone Group Url ", url, + "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "x-grid-location-info://lincoln.lindenlab.com/app/group/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Standalone Group Url Multicase ith Text", url, + "M x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about M", + "x-grid-location-info://lincoln.lindenlab.com/app/GROUP/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + } + + template<> template<> + void object::test<6>() + { + // + // test LLUrlEntryPlace - secondlife://<location> URLs + // + LLUrlEntryPlace url; + + testRegex("no valid slurl [1]", url, + "secondlife://Ahern/FOO/50/", + ""); + + testRegex("Ahern (50,50,50) [1]", url, + "secondlife://Ahern/50/50/50/", + "secondlife://Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", url, + "XXX secondlife://Ahern/50/50/50/ XXX", + "secondlife://Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", url, + "XXX secondlife://Ahern/50/50/50 XXX", + "secondlife://Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", url, + "XXX SecondLife://Ahern/50/50/50/ XXX", + "SecondLife://Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", url, + "XXX secondlife://Ahern/50/50/ XXX", + "secondlife://Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", url, + "XXX secondlife://Ahern/50/50 XXX", + "secondlife://Ahern/50/50"); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("SLURL with brackets", url, + "XXX secondlife://Burning%20Life%20(Hyper)/27/210/30 XXX", + "secondlife://Burning%20Life%20(Hyper)/27/210/30"); + + // DEV-35459: SLURLs and teleport Links not parsed properly + testRegex("SLURL with quote", url, + "XXX secondlife://A'ksha%20Oasis/41/166/701 XXX", + "secondlife://A%27ksha%20Oasis/41/166/701"); + + testRegex("Standalone All Hands (50,50) [2] with text", url, + "XXX x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50 XXX", + "x-grid-location-info://lincoln.lindenlab.com/region/All%20Hands/50/50/50"); + } + + template<> template<> + void object::test<7>() + { + // + // test LLUrlEntryParcel - secondlife://app/parcel Urls + // + LLUrlEntryParcel url; + + testRegex("Invalid Classified Url", url, + "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about", + ""); + + testRegex("Classified Url ", url, + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about", + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); + + testRegex("Classified Url in text", url, + "XXX secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about XXX", + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); + + testRegex("Classified Url multicase", url, + "XXX secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About XXX", + "secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About"); + } + template<> template<> + void object::test<8>() + { + // + // test LLUrlEntryTeleport - secondlife://app/teleport URLs + // + LLUrlEntryTeleport url; + + testRegex("no valid teleport [1]", url, + "http://slurl.com/secondlife/Ahern/50/50/50/", + ""); + + testRegex("no valid teleport [2]", url, + "secondlife:///app/teleport/", + ""); + + testRegex("no valid teleport [3]", url, + "second-life:///app/teleport/Ahern/50/50/50/", + ""); + + testRegex("no valid teleport [3]", url, + "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", + ""); + + testRegex("Ahern (50,50,50) [1]", url, + "secondlife:///app/teleport/Ahern/50/50/50/", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", url, + "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", url, + "XXX secondlife:///app/teleport/Ahern/50/50/50 XXX", + "secondlife:///app/teleport/Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", url, + "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", url, + "XXX secondlife:///app/teleport/Ahern/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", url, + "XXX secondlife:///app/teleport/Ahern/50/50 XXX", + "secondlife:///app/teleport/Ahern/50/50"); + + testRegex("Ahern (50)", url, + "XXX secondlife:///app/teleport/Ahern/50 XXX", + "secondlife:///app/teleport/Ahern/50"); + + testRegex("Ahern", url, + "XXX secondlife:///app/teleport/Ahern/ XXX", + "secondlife:///app/teleport/Ahern/"); + + testRegex("Ahern teleport with title", url, + "XXX secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", + "secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); + + testRegex("Ahern teleport with msg", url, + "XXX secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here. XXX", + "secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here."); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("Teleport with brackets", url, + "XXX secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30 XXX", + "secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30"); + + // DEV-35459: SLURLs and teleport Links not parsed properly + testRegex("Teleport url with quote", url, + "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX", + "secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701"); + + testRegex("Standalone All Hands", url, + "XXX x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50 XXX", + "x-grid-location-info://lincoln.lindenlab.com/app/teleport/All%20Hands/50/50/50"); + } + + template<> template<> + void object::test<9>() + { + // + // test LLUrlEntrySL - general secondlife:// URLs + // + LLUrlEntrySL url; + + testRegex("no valid slapp [1]", url, + "http:///app/", + ""); + + testRegex("valid slapp [1]", url, + "secondlife:///app/", + "secondlife:///app/"); + + testRegex("valid slapp [2]", url, + "secondlife:///app/teleport/Ahern/50/50/50/", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("valid slapp [3]", url, + "secondlife:///app/foo", + "secondlife:///app/foo"); + + testRegex("valid slapp [4]", url, + "secondlife:///APP/foo?title=Hi%20There", + "secondlife:///APP/foo?title=Hi%20There"); + + testRegex("valid slapp [5]", url, + "secondlife://host/app/", + "secondlife://host/app/"); + + testRegex("valid slapp [6]", url, + "secondlife://host:8080/foo/bar", + "secondlife://host:8080/foo/bar"); + } + + template<> template<> + void object::test<10>() + { + // + // test LLUrlEntrySLLabel - general secondlife:// URLs with labels + // + LLUrlEntrySLLabel url; + + testRegex("invalid wiki url [1]", url, + "[secondlife:///app/]", + ""); + + testRegex("invalid wiki url [2]", url, + "[secondlife:///app/", + ""); + + testRegex("invalid wiki url [3]", url, + "[secondlife:///app/ Label", + ""); + + testRegex("agent slurl with label (spaces)", url, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("agent slurl with label (tabs)", url, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("agent slurl with label", url, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("teleport slurl with label", url, + "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY", + "secondlife:///app/teleport/Ahern/50/50/50/"); + } + + template<> template<> + void object::test<11>() + { + // + // test LLUrlEntryNoLink - turn off hyperlinking + // + LLUrlEntryNoLink url; + + testRegex("<nolink> [1]", url, + "<nolink>google.com</nolink>", + "google.com"); + + testRegex("<nolink> [2]", url, + "<nolink>google.com", + ""); + + testRegex("<nolink> [3]", url, + "google.com</nolink>", + ""); + + testRegex("<nolink> [4]", url, + "<nolink>Hello World</nolink>", + "Hello World"); + + testRegex("<nolink> [5]", url, + "<nolink>My Object</nolink>", + "My Object"); + } + + template<> template<> + void object::test<12>() + { + // + // test LLUrlEntryRegion - secondlife:///app/region/<location> URLs + // + LLUrlEntryRegion url; + + // Regex tests. + testRegex("no valid region", url, + "secondlife:///app/region/", + ""); + + testRegex("invalid coords", url, + "secondlife:///app/region/Korea2/a/b/c", + "secondlife:///app/region/Korea2/"); // don't count invalid coords + + testRegex("Ahern (50,50,50) [1]", url, + "secondlife:///app/region/Ahern/50/50/50/", + "secondlife:///app/region/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", url, + "XXX secondlife:///app/region/Ahern/50/50/50/ XXX", + "secondlife:///app/region/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", url, + "XXX secondlife:///app/region/Ahern/50/50/50 XXX", + "secondlife:///app/region/Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", url, + "XXX secondlife:///app/region/Ahern/50/50/50/ XXX", + "secondlife:///app/region/Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", url, + "XXX secondlife:///app/region/Ahern/50/50/ XXX", + "secondlife:///app/region/Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", url, + "XXX secondlife:///app/region/Ahern/50/50 XXX", + "secondlife:///app/region/Ahern/50/50"); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("Region with brackets", url, + "XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX", + "secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30"); + + // Rendering tests. + testLabel("Render /app/region/Ahern/50/50/50/", url, + "secondlife:///app/region/Ahern/50/50/50/", + "Ahern (50,50,50)"); + + testLabel("Render /app/region/Ahern/50/50/50", url, + "secondlife:///app/region/Ahern/50/50/50", + "Ahern (50,50,50)"); + + testLabel("Render /app/region/Ahern/50/50/", url, + "secondlife:///app/region/Ahern/50/50/", + "Ahern (50,50)"); + + testLabel("Render /app/region/Ahern/50/50", url, + "secondlife:///app/region/Ahern/50/50", + "Ahern (50,50)"); + + testLabel("Render /app/region/Ahern/50/", url, + "secondlife:///app/region/Ahern/50/", + "Ahern (50)"); + + testLabel("Render /app/region/Ahern/50", url, + "secondlife:///app/region/Ahern/50", + "Ahern (50)"); + + testLabel("Render /app/region/Ahern/", url, + "secondlife:///app/region/Ahern/", + "Ahern"); + + testLabel("Render /app/region/Ahern/ within context", url, + "XXX secondlife:///app/region/Ahern/ XXX", + "Ahern"); + + testLabel("Render /app/region/Ahern", url, + "secondlife:///app/region/Ahern", + "Ahern"); + + testLabel("Render /app/region/Ahern within context", url, + "XXX secondlife:///app/region/Ahern XXX", + "Ahern"); + + testLabel("Render /app/region/Product%20Engine/", url, + "secondlife:///app/region/Product%20Engine/", + "Product Engine"); + + testLabel("Render /app/region/Product%20Engine", url, + "secondlife:///app/region/Product%20Engine", + "Product Engine"); + + // Location parsing texts. + testLocation("Location /app/region/Ahern/50/50/50/", url, + "secondlife:///app/region/Ahern/50/50/50/", + "Ahern"); + + testLocation("Location /app/region/Product%20Engine", url, + "secondlife:///app/region/Product%20Engine", + "Product Engine"); + } + + template<> template<> + void object::test<13>() + { + // + // test LLUrlEntryemail - general emails + // + LLUrlEntryEmail url; + + // Regex tests. + testRegex("match e-mail addresses", url, + "test@lindenlab.com", + "mailto:test@lindenlab.com"); + + testRegex("match e-mail addresses with mailto: prefix", url, + "mailto:test@lindenlab.com", + "mailto:test@lindenlab.com"); + + testRegex("match e-mail addresses with different domains", url, + "test@foo.org.us", + "mailto:test@foo.org.us"); + + testRegex("match e-mail addresses with different domains", url, + "test@foo.bar", + "mailto:test@foo.bar"); + + testRegex("don't match incorrect e-mail addresses", url, + "test @foo.com", + ""); + + testRegex("don't match incorrect e-mail addresses", url, + "test@ foo.com", + ""); + } + + template<> template<> + void object::test<14>() + { + // + // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls + // + LLUrlEntrySecondlifeURL url; + + testRegex("match urls with protocol", url, + "this url should match http://lindenlab.com/products/second-life", + "http://lindenlab.com/products/second-life"); + + testRegex("match urls with protocol", url, + "search something https://marketplace.secondlife.com/products/search on marketplace and test the https", + "https://marketplace.secondlife.com/products/search"); + + testRegex("match HTTPS urls with port", url, + "let's specify some port https://secondlife.com:888/status", + "https://secondlife.com:888/status"); + + testRegex("don't match HTTP urls with port", url, + "let's specify some port for HTTP http://secondlife.com:888/status", + ""); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something www.marketplace.secondlife.com/products but no https prefix", + ""); + + testRegex("but with a protocol www is fine", url, + "so let's add a protocol https://www.marketplace.secondlife.com:8888/products", + "https://www.marketplace.secondlife.com:8888/products"); + + testRegex("don't match urls w/o protocol", url, + "and even no www something secondlife.com/status", + ""); + } + + template<> template<> + void object::test<15>() + { + // + // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls + // + + LLUrlEntrySimpleSecondlifeURL url; + + testRegex("match urls with a protocol", url, + "this url should match http://lindenlab.com", + "http://lindenlab.com"); + + testRegex("match urls with a protocol", url, + "search something https://marketplace.secondlife.com on marketplace and test the https", + "https://marketplace.secondlife.com"); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something www.marketplace.secondlife.com but no https prefix", + ""); + + testRegex("but with a protocol www is fine", url, + "so let's add a protocol http://www.marketplace.secondlife.com", + "http://www.marketplace.secondlife.com"); + + testRegex("don't match urls w/o protocol", url, + "and even no www something lindenlab.com", + ""); + } + + template<> template<> + void object::test<16>() + { + // + // test LLUrlEntryIPv6 + // + LLUrlEntryIPv6 url; + + // Regex tests. + testRegex("match urls with a protocol", url, + "this url should match http://[::1]", + "http://[::1]"); + + testRegex("match urls with a protocol and query", url, + "this url should match http://[::1]/file.mp3", + "http://[::1]/file.mp3"); + + testRegex("match urls with a protocol", url, + "this url should match http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]", + "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]"); + + testRegex("match urls with port", url, + "let's specify some port http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080", + "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080"); + + testRegex("don't match urls w/o protocol", url, + "looks like an url something [2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d] but no https prefix", + ""); + + testRegex("don't match incorrect urls", url, + "http://[ 2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d ]", + ""); + } } diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index 843886eb69..d03efbc1c9 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ // link seams LLUIColor::LLUIColor() - : mColorPtr(NULL) + : mColorPtr(NULL) {} LLStyle::Params::Params() @@ -52,228 +52,228 @@ LLUIImage::~LLUIImage() //virtual S32 LLUIImage::getWidth() const { - return 0; + return 0; } //virtual S32 LLUIImage::getHeight() const { - return 0; + return 0; } namespace LLInitParam { - ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) - : super_t(color) - {} - - void ParamValue<LLUIColor>::updateValueFromBlock() - {} - - void ParamValue<LLUIColor>::updateBlockFromValue(bool) - {} - - bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) - { - return false; - } - - - ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) - : super_t(fontp) - {} - - void ParamValue<const LLFontGL*>::updateValueFromBlock() - {} - - void ParamValue<const LLFontGL*>::updateBlockFromValue(bool) - {} - - void TypeValues<LLFontGL::HAlign>::declareValues() - {} - - void TypeValues<LLFontGL::VAlign>::declareValues() - {} - - void TypeValues<LLFontGL::ShadowType>::declareValues() - {} - - void ParamValue<LLUIImage*>::updateValueFromBlock() - {} - - void ParamValue<LLUIImage*>::updateBlockFromValue(bool) - {} - - bool ParamCompare<LLUIImage*, false>::equals( - LLUIImage* const &a, - LLUIImage* const &b) - { - return false; - } - - bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) - { - return false; - } + ParamValue<LLUIColor>::ParamValue(const LLUIColor& color) + : super_t(color) + {} + + void ParamValue<LLUIColor>::updateValueFromBlock() + {} + + void ParamValue<LLUIColor>::updateBlockFromValue(bool) + {} + + bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) + { + return false; + } + + + ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp) + : super_t(fontp) + {} + + void ParamValue<const LLFontGL*>::updateValueFromBlock() + {} + + void ParamValue<const LLFontGL*>::updateBlockFromValue(bool) + {} + + void TypeValues<LLFontGL::HAlign>::declareValues() + {} + + void TypeValues<LLFontGL::VAlign>::declareValues() + {} + + void TypeValues<LLFontGL::ShadowType>::declareValues() + {} + + void ParamValue<LLUIImage*>::updateValueFromBlock() + {} + + void ParamValue<LLUIImage*>::updateBlockFromValue(bool) + {} + + bool ParamCompare<LLUIImage*, false>::equals( + LLUIImage* const &a, + LLUIImage* const &b) + { + return false; + } + + bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) + { + return false; + } } //static LLFontGL* LLFontGL::getFontDefault() { - return NULL; + return NULL; } namespace tut { - struct LLUrlMatchData - { - }; + struct LLUrlMatchData + { + }; - typedef test_group<LLUrlMatchData> factory; - typedef factory::object object; + typedef test_group<LLUrlMatchData> factory; + typedef factory::object object; } namespace { - tut::factory tf("LLUrlMatch"); + tut::factory tf("LLUrlMatch"); } namespace tut { - template<> template<> - void object::test<1>() - { - // - // test the empty() method - // - LLUrlMatch match; - ensure("empty()", match.empty()); - - match.setValues(0, 1, "http://secondlife.com", "", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure("! empty()", ! match.empty()); - } - - template<> template<> - void object::test<2>() - { - // - // test the getStart() method - // - LLUrlMatch match; - ensure_equals("getStart() == 0", match.getStart(), 0); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getStart() == 10", match.getStart(), 10); - } - - template<> template<> - void object::test<3>() - { - // - // test the getEnd() method - // - LLUrlMatch match; - ensure_equals("getEnd() == 0", match.getEnd(), 0); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getEnd() == 20", match.getEnd(), 20); - } - - template<> template<> - void object::test<4>() - { - // - // test the getUrl() method - // - LLUrlMatch match; - ensure_equals("getUrl() == ''", match.getUrl(), ""); - - match.setValues(10, 20, "http://slurl.com/", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getUrl() == '' (2)", match.getUrl(), ""); - } - - template<> template<> - void object::test<5>() - { - // - // test the getLabel() method - // - LLUrlMatch match; - ensure_equals("getLabel() == ''", match.getLabel(), ""); - - match.setValues(10, 20, "", "Label", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getLabel() == '' (2)", match.getLabel(), ""); - } - - template<> template<> - void object::test<6>() - { - // - // test the getTooltip() method - // - LLUrlMatch match; - ensure_equals("getTooltip() == ''", match.getTooltip(), ""); - - match.setValues(10, 20, "", "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getTooltip() == '' (2)", match.getTooltip(), ""); - } - - template<> template<> - void object::test<7>() - { - // - // test the getIcon() method - // - LLUrlMatch match; - ensure_equals("getIcon() == ''", match.getIcon(), ""); - - match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure_equals("getIcon() == '' (2)", match.getIcon(), ""); - } - - template<> template<> - void object::test<8>() - { - // - // test the getMenuName() method - // - LLUrlMatch match; - ensure("getMenuName() empty", match.getMenuName().empty()); - - match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null); - ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure("getMenuName() empty (2)", match.getMenuName().empty()); - } - - template<> template<> - void object::test<9>() - { - // - // test the getLocation() method - // - LLUrlMatch match; - ensure("getLocation() empty", match.getLocation().empty()); - - match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null); - ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris"); - - match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); - ensure("getLocation() empty (2)", match.getLocation().empty()); - } + template<> template<> + void object::test<1>() + { + // + // test the empty() method + // + LLUrlMatch match; + ensure("empty()", match.empty()); + + match.setValues(0, 1, "http://secondlife.com", "", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure("! empty()", ! match.empty()); + } + + template<> template<> + void object::test<2>() + { + // + // test the getStart() method + // + LLUrlMatch match; + ensure_equals("getStart() == 0", match.getStart(), 0); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getStart() == 10", match.getStart(), 10); + } + + template<> template<> + void object::test<3>() + { + // + // test the getEnd() method + // + LLUrlMatch match; + ensure_equals("getEnd() == 0", match.getEnd(), 0); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getEnd() == 20", match.getEnd(), 20); + } + + template<> template<> + void object::test<4>() + { + // + // test the getUrl() method + // + LLUrlMatch match; + ensure_equals("getUrl() == ''", match.getUrl(), ""); + + match.setValues(10, 20, "http://slurl.com/", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getUrl() == '' (2)", match.getUrl(), ""); + } + + template<> template<> + void object::test<5>() + { + // + // test the getLabel() method + // + LLUrlMatch match; + ensure_equals("getLabel() == ''", match.getLabel(), ""); + + match.setValues(10, 20, "", "Label", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getLabel() == '' (2)", match.getLabel(), ""); + } + + template<> template<> + void object::test<6>() + { + // + // test the getTooltip() method + // + LLUrlMatch match; + ensure_equals("getTooltip() == ''", match.getTooltip(), ""); + + match.setValues(10, 20, "", "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getTooltip() == '' (2)", match.getTooltip(), ""); + } + + template<> template<> + void object::test<7>() + { + // + // test the getIcon() method + // + LLUrlMatch match; + ensure_equals("getIcon() == ''", match.getIcon(), ""); + + match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure_equals("getIcon() == '' (2)", match.getIcon(), ""); + } + + template<> template<> + void object::test<8>() + { + // + // test the getMenuName() method + // + LLUrlMatch match; + ensure("getMenuName() empty", match.getMenuName().empty()); + + match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null); + ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure("getMenuName() empty (2)", match.getMenuName().empty()); + } + + template<> template<> + void object::test<9>() + { + // + // test the getLocation() method + // + LLUrlMatch match; + ensure("getLocation() empty", match.getLocation().empty()); + + match.setValues(10, 20, "", "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null); + ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris"); + + match.setValues(10, 20, "", "", "", "", "", LLStyle::Params(), "", "", LLUUID::null); + ensure("getLocation() empty (2)", match.getLocation().empty()); + } } |