summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llaccordionctrl.cpp32
-rw-r--r--indra/llui/llaccordionctrl.h5
-rw-r--r--indra/llui/llaccordionctrltab.cpp29
-rw-r--r--indra/llui/llaccordionctrltab.h1
-rw-r--r--indra/llui/llbadgeowner.cpp8
-rw-r--r--indra/llui/llbadgeowner.h1
-rw-r--r--indra/llui/llbutton.cpp27
-rw-r--r--indra/llui/llbutton.h1
-rw-r--r--indra/llui/llcheckboxctrl.cpp30
-rw-r--r--indra/llui/llcombobox.cpp8
-rw-r--r--indra/llui/llcombobox.h2
-rw-r--r--indra/llui/llfloater.cpp10
-rw-r--r--indra/llui/llfolderview.cpp4
-rw-r--r--indra/llui/llfolderviewitem.cpp74
-rw-r--r--indra/llui/llfolderviewitem.h10
-rw-r--r--indra/llui/llfolderviewmodel.cpp3
-rw-r--r--indra/llui/llfolderviewmodel.h16
-rw-r--r--indra/llui/lllayoutstack.cpp2
-rw-r--r--indra/llui/lllineeditor.cpp1
-rw-r--r--indra/llui/llmenugl.cpp63
-rw-r--r--indra/llui/llmenugl.h20
-rw-r--r--indra/llui/llmultisliderctrl.cpp1
-rw-r--r--indra/llui/llnotifications.cpp32
-rw-r--r--indra/llui/llnotifications.h2
-rw-r--r--indra/llui/llscrolllistcell.cpp149
-rw-r--r--indra/llui/llscrolllistcell.h31
-rw-r--r--indra/llui/llscrolllistctrl.cpp248
-rw-r--r--indra/llui/llscrolllistctrl.h22
-rw-r--r--indra/llui/llscrolllistitem.cpp56
-rw-r--r--indra/llui/llscrolllistitem.h21
-rw-r--r--indra/llui/llsliderctrl.cpp1
-rw-r--r--indra/llui/llspellcheck.cpp8
-rw-r--r--indra/llui/llspellcheck.h1
-rw-r--r--indra/llui/llspinctrl.cpp3
-rw-r--r--indra/llui/lltabcontainer.cpp13
-rw-r--r--indra/llui/lltabcontainer.h8
-rw-r--r--indra/llui/lltextbase.cpp47
-rw-r--r--indra/llui/lltextbase.h2
-rw-r--r--indra/llui/lltextbox.cpp4
-rw-r--r--indra/llui/lltextbox.h2
-rw-r--r--indra/llui/lluictrl.cpp3
-rw-r--r--indra/llui/llurlentry.cpp105
-rw-r--r--indra/llui/llurlentry.h37
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/llui/llview.cpp14
-rw-r--r--indra/llui/llview.h1
-rw-r--r--indra/llui/tests/llurlentry_test.cpp34
47 files changed, 1015 insertions, 178 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index edcbc3fbb7..809d72208f 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -55,6 +55,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
, mTabComparator( NULL )
, mNoVisibleTabsHelpText(NULL)
, mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString())
+ , mSkipScrollToChild(false)
{
initNoTabsWidget(params.no_matched_tabs_text);
@@ -655,6 +656,37 @@ void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
{
updateLayout(getRect().getWidth(),getRect().getHeight());
}
+
+// virtual
+void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl)
+{
+ if (mScrollbar && mScrollbar->getVisible() && !mSkipScrollToChild)
+ {
+ // same as scrollToShowRect
+ LLRect rect;
+ cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this);
+
+ // Translate to parent coordinatess to check if we are in visible rectangle
+ rect.translate(getRect().mLeft, getRect().mBottom);
+
+ if (!getRect().contains(rect))
+ {
+ // for accordition's scroll, height is in pixels
+ // Back to local coords and calculate position for scroller
+ S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom;
+ S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop;
+
+ S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
+ bottom, // min vertical scroll
+ top); // max vertical scroll
+
+ mScrollbar->setDocPos(scroll_pos);
+ }
+ }
+
+ LLUICtrl::onUpdateScrollToChild(cntrl);
+}
+
void LLAccordionCtrl::onOpen (const LLSD& key)
{
for(size_t i=0;i<mAccordionTabs.size();++i)
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 1fe64c472e..2828254472 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -111,6 +111,7 @@ public:
void draw();
void onScrollPosChangeCallback(S32, LLScrollbar*);
+ virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
void onOpen (const LLSD& key);
S32 notifyParent(const LLSD& info);
@@ -137,6 +138,8 @@ public:
bool getFitParent() const {return mFitParent;}
+ void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; }
+
private:
void initNoTabsWidget(const LLTextBox::Params& tb_params);
void updateNoTabsHelpTextVisibility();
@@ -182,6 +185,8 @@ private:
F32 mAutoScrollRate;
LLTextBox* mNoVisibleTabsHelpText;
+ bool mSkipScrollToChild;
+
std::string mNoMatchedTabsOrigString;
std::string mNoVisibleTabsOrigString;
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 1034a21905..098621b543 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -452,6 +452,35 @@ void LLAccordionCtrlTab::onVisibilityChange(BOOL new_visibility)
notifyParent(LLSD().with("child_visibility_change", new_visibility));
}
+// virtual
+void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl)
+{
+ if (mScrollbar && mScrollbar->getVisible())
+ {
+ LLRect rect;
+ cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this);
+
+ // Translate to parent coordinatess to check if we are in visible rectangle
+ rect.translate(getRect().mLeft, getRect().mBottom);
+
+ if (!getRect().contains(rect))
+ {
+ // for accordition's scroll, height is in pixels
+ // Back to local coords and calculate position for scroller
+ S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom;
+ S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop;
+
+ S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
+ bottom, // min vertical scroll
+ top); // max vertical scroll
+
+ mScrollbar->setDocPos(scroll_pos);
+ }
+ }
+
+ LLUICtrl::onUpdateScrollToChild(cntrl);
+}
+
BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
{
if(mCollapsible && mHeaderVisible && mCanOpenClose)
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index 0263bce4be..2c72e8c036 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -159,6 +159,7 @@ public:
* 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);
diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp
index 0557cd4375..5f11c383ef 100644
--- a/indra/llui/llbadgeowner.cpp
+++ b/indra/llui/llbadgeowner.cpp
@@ -56,6 +56,14 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p)
}
}
+void LLBadgeOwner::reshapeBadge(const LLRect& new_rect)
+{
+ if (mBadge)
+ {
+ mBadge->setShape(new_rect);
+ }
+}
+
void LLBadgeOwner::setBadgeVisibility(bool visible)
{
if (mBadge)
diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h
index 01ed95f3a3..4ce208fa0d 100644
--- a/indra/llui/llbadgeowner.h
+++ b/indra/llui/llbadgeowner.h
@@ -46,6 +46,7 @@ public:
bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; };
void setBadgeVisibility(bool visible);
void setDrawBadgeAtTop(bool draw_at_top);
+ void reshapeBadge(const LLRect& new_rect);
private:
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 27444b7f5b..9682c3bc10 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -643,7 +643,8 @@ void LLButton::draw()
LLColor4 highlighting_color = LLColor4::white;
LLColor4 glow_color = LLColor4::white;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
- LLUIImage* imagep = NULL;
+ 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
@@ -710,17 +711,18 @@ void LLButton::draw()
imagep = mImageDisabled;
}
+ image_glow = imagep;
+
if (mFlashing)
{
- // if button should flash and we have icon for flashing, use it as image for button
- if(flash && mImageFlash)
+ if (flash && mImageFlash)
{
- // setting flash to false to avoid its further influence on glow
- flash = false;
- imagep = mImageFlash;
+ // if button should flash and we have icon for flashing, use it as image for button
+ image_glow = mImageFlash;
}
- // else use usual flashing via flash_color
- else if (mFlashingTimer)
+
+ // provide fade-in and fade-out via flash_color
+ if (mFlashingTimer)
{
LLColor4 flash_color = mFlashBgColor.get();
use_glow_effect = TRUE;
@@ -734,6 +736,11 @@ void LLButton::draw()
{
glow_color = highlighting_color;
}
+ else
+ {
+ // will fade from highlight color
+ glow_color = flash_color;
+ }
}
}
@@ -806,7 +813,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
- imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
+ image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
@@ -817,7 +824,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
- imagep->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
+ image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 7629ed1fea..572d36996c 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -205,6 +205,7 @@ public:
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; }
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 6a51c4240b..08da599ef2 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -187,10 +187,32 @@ void LLCheckBoxCtrl::clear()
void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- S32 label_top = mLabel->getRect().mTop;
- mLabel->reshapeToFitText();
+ LLRect rect = getRect();
+ S32 delta_width = width - rect.getWidth();
+ S32 delta_height = height - rect.getHeight();
- LLRect label_rect = mLabel->getRect();
+ if (delta_width || delta_height)
+ {
+ // adjust our rectangle
+ rect.mRight = getRect().mLeft + width;
+ rect.mTop = getRect().mBottom + height;
+ setRect(rect);
+ }
+
+ // 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.
+
+ static LLUICachedControl<S32> llcheckboxctrl_hpad("UICheckboxctrlHPad", 0);
+ LLRect label_rect = mLabel->getRect();
+ S32 new_width = getRect().getWidth() - label_rect.mLeft - llcheckboxctrl_hpad;
+ label_rect.mRight = label_rect.mLeft + new_width;
+ mLabel->setRect(label_rect);
+
+ 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
@@ -210,6 +232,8 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
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();
}
//virtual
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index c7f0326ed4..52dc908655 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -514,6 +514,14 @@ S32 LLComboBox::getCurrentIndex() const
return -1;
}
+void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled)
+{
+ LLScrollListItem *found = mList->getItem(value);
+ if (found)
+ {
+ found->setEnabled(enabled);
+ }
+}
void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 7d38c051a5..4af3313162 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -158,6 +158,8 @@ public:
BOOL setCurrentByIndex( S32 index );
S32 getCurrentIndex() const;
+ void setEnabledByValue(const LLSD& value, BOOL enabled);
+
void createLineEditor(const Params&);
//========================================================================
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index abb043f428..e9c980ad9a 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -303,12 +303,10 @@ void LLFloater::initFloater(const Params& p)
mButtonsEnabled[BUTTON_CLOSE] = TRUE;
}
- // Help button: '?'
- if ( !mHelpTopic.empty() )
- {
- mButtonsEnabled[BUTTON_HELP] = TRUE;
- }
-
+ // Help button: '?'
+ //SL-14050 Disable all Help question marks
+ mButtonsEnabled[BUTTON_HELP] = FALSE;
+
// Minimize button only for top draggers
if ( !mDragOnLeft && mCanMinimize )
{
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index e718fcec46..0c1dcc301b 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -342,7 +342,9 @@ static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View");
void LLFolderView::filter( LLFolderViewFilter& filter )
{
LL_RECORD_BLOCK_TIME(FTM_FILTER);
- filter.resetTime(llclamp(LLUI::getInstance()->mSettingGroups["config"]->getS32(mParentPanel.get()->getVisible() ? "FilterItemsMaxTimePerFrameVisible" : "FilterItemsMaxTimePerFrameUnvisible"), 1, 100));
+ static LLCachedControl<S32> filter_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
+ static LLCachedControl<S32> filter_hidden(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
+ filter.resetTime(llclamp(mParentPanel.get()->getVisible() ? filter_visible() : filter_hidden(), 1, 100));
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 9a1f7de73b..1c6c7b1b35 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -122,6 +122,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
: LLView(p),
mLabelWidth(0),
mLabelWidthDirty(false),
+ mSuffixNeedsRefresh(false),
mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT),
mParentFolder( NULL ),
mIsSelected( FALSE ),
@@ -181,11 +182,25 @@ LLFolderViewItem::~LLFolderViewItem()
BOOL LLFolderViewItem::postBuild()
{
- refresh();
+ LLFolderViewModelItem& vmi = *getViewModelItem();
+ // getDisplayName() is expensive (due to internal getLabelSuffix() and name building)
+ // it also sets search strings so it requires a filter reset
+ mLabel = vmi.getDisplayName();
+ setToolTip(vmi.getName());
+
+ // Dirty the filter flag of the model from the view (CHUI-849)
+ vmi.dirtyFilter();
+
+ // Don't do full refresh on constructor if it is possible to avoid
+ // it significantly slows down bulk view creation.
+ // Todo: Ideally we need to move getDisplayName() out of constructor as well.
+ // Like: make a logic that will let filter update search string,
+ // while LLFolderViewItem::arrange() updates visual part
+ mSuffixNeedsRefresh = true;
+ mLabelWidthDirty = true;
return TRUE;
}
-
LLFolderView* LLFolderViewItem::getRoot()
{
return mRoot;
@@ -280,24 +295,51 @@ BOOL LLFolderViewItem::isPotentiallyVisible(S32 filter_generation)
void LLFolderViewItem::refresh()
{
- LLFolderViewModelItem& vmi = *getViewModelItem();
+ LLFolderViewModelItem& vmi = *getViewModelItem();
+
+ mLabel = vmi.getDisplayName();
+ setToolTip(vmi.getName());
+ // icons are slightly expensive to get, can be optimized
+ // see LLInventoryIcon::getIcon()
+ mIcon = vmi.getIcon();
+ mIconOpen = vmi.getIconOpen();
+ mIconOverlay = vmi.getIconOverlay();
- mLabel = vmi.getDisplayName();
+ 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();
+ }
- setToolTip(vmi.getName());
- mIcon = vmi.getIcon();
- mIconOpen = vmi.getIconOpen();
- mIconOverlay = vmi.getIconOverlay();
+ // Dirty the filter flag of the model from the view (CHUI-849)
+ vmi.dirtyFilter();
+
+ mLabelWidthDirty = true;
+ mSuffixNeedsRefresh = false;
+}
+
+void LLFolderViewItem::refreshSuffix()
+{
+ LLFolderViewModelItem const* vmi = getViewModelItem();
+
+ // icons are slightly expensive to get, can be optimized
+ // see LLInventoryIcon::getIcon()
+ mIcon = vmi->getIcon();
+ mIconOpen = vmi->getIconOpen();
+ mIconOverlay = vmi->getIconOverlay();
if (mRoot->useLabelSuffix())
{
- mLabelStyle = vmi.getLabelStyle();
- mLabelSuffix = vmi.getLabelSuffix();
+ // 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;
- // Dirty the filter flag of the model from the view (CHUI-849)
- vmi.dirtyFilter();
+ mLabelWidthDirty = true;
+ mSuffixNeedsRefresh = false;
}
// Utility function for LLFolderView
@@ -348,6 +390,12 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )
: 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(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;
mLabelWidthDirty = false;
}
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 61c39e0175..da09d139e9 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -95,6 +95,7 @@ protected:
LLPointer<LLFolderViewModelItem> mViewModelItem;
LLFontGL::StyleFlags mLabelStyle;
std::string mLabelSuffix;
+ bool mSuffixNeedsRefresh; //suffix and icons
LLUIImagePtr mIcon,
mIconOpen,
mIconOverlay;
@@ -266,8 +267,13 @@ public:
virtual BOOL passedFilter(S32 filter_generation = -1);
virtual BOOL isPotentiallyVisible(S32 filter_generation = -1);
- // refresh information from the object being viewed.
- virtual void refresh();
+ // refresh information from the object being viewed.
+ // refreshes label, suffixes and sets icons. Expensive!
+ // Causes filter update
+ virtual void refresh();
+ // refreshes suffixes and sets icons. Expensive!
+ // Does not need filter update
+ virtual void refreshSuffix();
// LLView functionality
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp
index 3b45fb53a2..ea106b5fae 100644
--- a/indra/llui/llfolderviewmodel.cpp
+++ b/indra/llui/llfolderviewmodel.cpp
@@ -48,7 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText()
void LLFolderViewModelCommon::filter()
{
- getFilter().resetTime(llclamp(LLUI::getInstance()->mSettingGroups["config"]->getS32("FilterItemsMaxTimePerFrameVisible"), 1, 100));
+ static LLCachedControl<S32> filter_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
+ getFilter().resetTime(llclamp(filter_visible(), 1, 100));
mFolderView->getViewModelItem()->filter(getFilter());
}
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index f71a88c56e..e62b2779dd 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -204,6 +204,7 @@ public:
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
@@ -286,16 +287,6 @@ public:
virtual void addChild(LLFolderViewModelItem* child)
{
- // Avoid duplicates: bail out if that child is already present in the list
- // Note: this happens when models are created before views
- child_list_t::const_iterator iter;
- for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
- {
- if (child == *iter)
- {
- return;
- }
- }
mChildren.push_back(child);
child->setParent(this);
dirtyFilter();
@@ -311,9 +302,8 @@ public:
virtual void clearChildren()
{
- // As this is cleaning the whole list of children wholesale, we do need to delete the pointed objects
- // This is different and not equivalent to calling removeChild() on each child
- std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
+ // 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();
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 4aae1e374b..29a156e933 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -166,7 +166,7 @@ void LLLayoutPanel::setVisible( BOOL visible )
void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ )
{
- if (width == getRect().getWidth() && height == getRect().getHeight()) return;
+ if (width == getRect().getWidth() && height == getRect().getHeight() && !LLView::sForceReshape) return;
if (!mIgnoreReshape && mAutoResize == false)
{
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 70304cdfd2..1badd54fca 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -2151,6 +2151,7 @@ void LLLineEditor::clear()
void LLLineEditor::onTabInto()
{
selectAll();
+ LLUICtrl::onTabInto();
}
//virtual
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 5568a84494..37dbe9b40e 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -213,6 +213,12 @@ LLSD LLMenuItemGL::getValue() const
}
//virtual
+bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ 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)) )
@@ -263,13 +269,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK 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 <LLKeyBinding*> *listp)
+BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp)
{
- LLKeyBinding *accelerator = NULL;
+ LLMenuKeyboardBinding *accelerator = NULL;
if (mAcceleratorKey != KEY_NONE)
{
- std::list<LLKeyBinding*>::iterator list_it;
+ std::list<LLMenuKeyboardBinding*>::iterator list_it;
for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
{
accelerator = *list_it;
@@ -293,7 +299,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
}
if (!accelerator)
{
- accelerator = new LLKeyBinding;
+ accelerator = new LLMenuKeyboardBinding;
if (accelerator)
{
accelerator->mKey = mAcceleratorKey;
@@ -1017,6 +1023,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
return TRUE;
}
+bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ return getBranch() && getBranch()->hasAccelerator(key, mask);
+}
+
BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
{
return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
@@ -1024,7 +1035,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK 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<LLKeyBinding*> *listp)
+BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp)
{
LLMenuGL* branch = getBranch();
if (!branch)
@@ -3023,6 +3034,27 @@ void LLMenuGL::updateParent(LLView* 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;
+}
+
BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
{
// don't handle if not enabled
@@ -3244,7 +3276,7 @@ void hide_top_view( LLView* view )
// x and y are the desired location for the popup, in the spawning_view's
// coordinate frame, NOT necessarily the mouse location
// static
-void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
+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;
@@ -3275,12 +3307,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
}
}
- // 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()
- S32 mouse_x, mouse_y;
-
// Resetting scrolling position
if (menu->isScrollable() && menu->isScrollPositionOnShowReset())
{
@@ -3291,7 +3317,18 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
menu->needsArrange();
menu->arrangeAndClear();
- LLUI::getInstance()->getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y);
+ 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();
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 1f11f26192..273bd789c4 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -42,6 +42,13 @@
extern S32 MENU_BAR_HEIGHT;
extern S32 MENU_BAR_WIDTH;
+class LLMenuKeyboardBinding
+{
+public:
+ KEY mKey;
+ MASK mMask;
+};
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemGL
//
@@ -91,6 +98,7 @@ public:
/*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(); }
@@ -109,7 +117,7 @@ public:
virtual void setBriefItem(BOOL brief);
virtual BOOL isBriefItem() const;
- virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp);
+ virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; }
BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; }
@@ -436,7 +444,8 @@ public:
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*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;
@@ -510,7 +519,7 @@ public:
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);
+ 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 );
@@ -628,10 +637,11 @@ public:
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
// check if we've used these accelerators already
- virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp);
+ virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -797,7 +807,7 @@ private:
void checkMenuTrigger();
- std::list <LLKeyBinding*> mAccelerators;
+ std::list <LLMenuKeyboardBinding*> mAccelerators;
BOOL mAltKeyTrigger;
};
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 20e2b569f1..b3df7c154b 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -509,6 +509,7 @@ void LLMultiSliderCtrl::onTabInto()
{
mEditor->onTabInto();
}
+ LLF32UICtrl::onTabInto();
}
void LLMultiSliderCtrl::reportInvalidData()
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 6a7075301b..06ec648178 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -255,7 +255,7 @@ LLNotificationForm::LLNotificationForm(const LLSD& sd)
}
else
{
- LL_WARNS() << "Invalid form data " << sd << LL_ENDL;
+ LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL;
mFormData = LLSD::emptyArray();
}
}
@@ -448,11 +448,11 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
mUniqueContext.push_back(context.value);
}
- LL_DEBUGS() << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL;
BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags)
{
- LL_DEBUGS() << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL;
+ LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL;
mTags.push_back(tag.value);
}
@@ -1398,8 +1398,14 @@ void LLNotifications::initSingleton()
createDefaultChannels();
}
+void LLNotifications::cleanupSingleton()
+{
+ clear();
+}
+
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", "",
@@ -1455,7 +1461,7 @@ void LLNotifications::forceResponse(const LLNotification::Params& params, S32 op
if (selected_item.isUndefined())
{
- LL_WARNS() << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL;
+ LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL;
return;
}
response[selected_item["name"].asString()] = true;
@@ -1489,12 +1495,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
if (found != replacements.end())
{
replacement = found->second;
- LL_DEBUGS() << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL;
+ LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL;
it->second->setValue(replacement);
}
else
{
- LL_WARNS() << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL;
+ LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL;
}
}
}
@@ -1533,7 +1539,7 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path
bool LLNotifications::loadTemplates()
{
- LL_INFOS() << "Reading notifications template" << LL_ENDL;
+ 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.
@@ -1604,7 +1610,7 @@ bool LLNotifications::loadTemplates()
mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification));
}
- LL_INFOS() << "...done" << LL_ENDL;
+ LL_INFOS("Notifications") << "...done" << LL_ENDL;
return true;
}
@@ -1832,7 +1838,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
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()
+ LL_DEBUGS("Notifications")
<< "notification \"" << n->getName() << "\" "
<< "testing against " << ((*it)->mVisible?"show":"hide") << " rule, "
<< "name = \"" << (*it)->mName << "\" "
@@ -1877,7 +1883,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
if((*it)->mResponse.empty())
{
// Response property is empty. Cancel this notification.
- LL_DEBUGS() << "cancelling notification " << n->getName() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL;
cancel(n);
}
@@ -1888,7 +1894,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
// TODO: verify that the response template has an item with the correct name
response[(*it)->mResponse] = true;
- LL_DEBUGS() << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL;
+ LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL;
n->respond(response);
}
@@ -1900,7 +1906,7 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n)
break;
}
- LL_DEBUGS() << "allowing notification " << n->getName() << LL_ENDL;
+ LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL;
return true;
}
@@ -1961,7 +1967,7 @@ void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
// from PE merge - we should figure out if this is the right thing to do
if (name.empty())
{
- LL_WARNS() << "Empty name received for Id: " << agent_id << LL_ENDL;
+ LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL;
name = SYSTEM_FROM;
}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index cac687f53d..2f4578da17 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -957,6 +957,7 @@ public:
private:
/*virtual*/ void initSingleton();
+ /*virtual*/ void cleanupSingleton();
void loadPersistentNotifications();
@@ -1069,6 +1070,7 @@ public:
LLPersistentNotificationChannel()
: LLNotificationChannel("Persistent", "Visible", &notificationFilter)
{}
+ virtual ~LLPersistentNotificationChannel() {}
typedef std::vector<LLNotificationPtr> history_list_t;
history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); }
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 8000efad0e..13839da400 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
{
cell = new LLScrollListDate(cell_p);
}
+ else if (cell_p.type() == "icontext")
+ {
+ cell = new LLScrollListIconText(cell_p);
+ }
else // default is "text"
{
cell = new LLScrollListText(cell_p);
@@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0;
LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
- mText(p.value().asString()),
+ mText(p.label.isProvided() ? p.label() : p.value().asString()),
mFont(p.font),
mColor(p.color),
mUseColor(p.color.isProvided()),
@@ -192,7 +196,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
void LLScrollListText::highlightText(S32 offset, S32 num_chars)
{
mHighlightOffset = offset;
- mHighlightCount = num_chars;
+ mHighlightCount = llmax(0, num_chars);
}
//virtual
@@ -292,11 +296,12 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
if (mHighlightCount > 0)
{
+ // Highlight text
S32 left = 0;
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
+ left = mFont->getWidth(mText.getString(), 1, mHighlightOffset);
break;
case LLFontGL::RIGHT:
left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
@@ -319,7 +324,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- start_x = 0.f;
+ start_x = 1.f;
break;
case LLFontGL::RIGHT:
start_x = (F32)getWidth();
@@ -435,3 +440,139 @@ const LLSD LLScrollListDate::getValue() const
{
return mDate;
}
+
+//
+// LLScrollListIconText
+//
+LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p)
+ : LLScrollListText(p),
+ mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())),
+ mPad(4)
+{
+ mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+LLScrollListIconText::~LLScrollListIconText()
+{
+}
+
+const LLSD LLScrollListIconText::getValue() const
+{
+ if (mIcon.isNull())
+ {
+ return LLStringUtil::null;
+ }
+ return mIcon->getName();
+}
+
+void LLScrollListIconText::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;
+ }
+ }
+}
+
+void LLScrollListIconText::setWidth(S32 width)
+{
+ LLScrollListCell::setWidth(width);
+ // Assume that iamge height and width is identical to font height and width
+ mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+
+void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const
+{
+ LLColor4 display_color;
+ if (mUseColor)
+ {
+ display_color = mColor;
+ }
+ else
+ {
+ display_color = color;
+ }
+
+ S32 icon_height = mFont->getLineHeight();
+ S32 icon_space = mIcon ? (icon_height + mPad) : 0;
+
+ if (mHighlightCount > 0)
+ {
+ S32 left = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset);
+ break;
+ case LLFontGL::RIGHT:
+ left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 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_text_x = 0.f;
+ S32 start_icon_x = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ start_text_x = icon_space + 1;
+ start_icon_x = 1;
+ break;
+ case LLFontGL::RIGHT:
+ start_text_x = (F32)getWidth();
+ start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ F32 center = (F32)getWidth()* 0.5f;
+ start_text_x = center + ((F32)icon_space * 0.5f);
+ start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f);
+ break;
+ }
+ mFont->render(mText.getWString(), 0,
+ start_text_x, 0.f,
+ display_color,
+ mFontAlignment,
+ LLFontGL::BOTTOM,
+ 0,
+ LLFontGL::NO_SHADOW,
+ string_chars,
+ getTextWidth(),
+ &right_x,
+ TRUE);
+
+ if (mIcon)
+ {
+ mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor);
+ }
+}
+
+
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index d625ebddcc..19576fb247 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -59,7 +59,8 @@ public:
visible;
Optional<void*> userdata;
- Optional<LLSD> value;
+ Optional<LLSD> value; // state of checkbox, icon id/name, date
+ Optional<std::string> label; // description or text
Optional<std::string> tool_tip;
Optional<const LLFontGL*> font;
@@ -75,6 +76,7 @@ public:
enabled("enabled", true),
visible("visible", true),
value("value"),
+ label("label"),
tool_tip("tool_tip", ""),
font("font", LLFontGL::getFontSansSerifSmall()),
font_color("font_color", LLColor4::black),
@@ -152,11 +154,12 @@ public:
void setText(const LLStringExplicit& text);
void setFontStyle(const U8 font_style);
-private:
+protected:
LLUIString mText;
S32 mTextWidth;
const LLFontGL* mFont;
LLColor4 mColor;
+ LLColor4 mHighlightColor;
U8 mUseColor;
LLFontGL::HAlign mFontAlignment;
BOOL mVisible;
@@ -169,7 +172,7 @@ private:
};
/*
- * Cell displaying an image.
+ * Cell displaying an image. AT the moment, this is specifically UI image
*/
class LLScrollListIcon : public LLScrollListCell
{
@@ -223,4 +226,26 @@ private:
LLDate mDate;
};
+/*
+* Cell displaying icon and text.
+*/
+
+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);
+
+
+ S32 getIconWidth() const;
+ /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/
+
+private:
+ LLPointer<LLUIImage> mIcon;
+ S32 mPad;
+};
+
#endif
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 763c3aeb81..be85f1cb6a 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -115,6 +115,13 @@ struct SortScrollListItem
// LLScrollListCtrl
//---------------------------------------------------------------------------
+void LLScrollListCtrl::SelectionTypeNames::declareValues()
+{
+ declare("row", LLScrollListCtrl::ROW);
+ declare("cell", LLScrollListCtrl::CELL);
+ declare("header", LLScrollListCtrl::HEADER);
+}
+
LLScrollListCtrl::Contents::Contents()
: columns("column"),
rows("row")
@@ -128,10 +135,13 @@ LLScrollListCtrl::Params::Params()
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"),
@@ -162,10 +172,12 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mMaxSelectable(0),
mAllowKeyboardMovement(true),
mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
- mCommitOnSelectionChange(false),
+ 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 ),
@@ -762,14 +774,20 @@ void LLScrollListCtrl::updateColumns(bool force_update)
}
}
+ 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);
- last_header->getColumn()->setWidth(new_width);
- }
+ if (old_width != new_width)
+ {
+ last_header->getColumn()->setWidth(new_width);
+ header_changed_width = true;
+ }
+ }
// propagate column widths to individual cells
if (columns_changed_width || force_update)
@@ -788,6 +806,20 @@ void LLScrollListCtrl::updateColumns(bool force_update)
}
}
}
+ else if (header_changed_width)
+ {
+ item_list::iterator iter;
+ S32 index = last_header->getColumn()->mIndex; // Not always identical to last column!
+ for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListItem *itemp = *iter;
+ LLScrollListCell* cell = itemp->getColumn(index);
+ if (cell)
+ {
+ cell->setWidth(last_header->getColumn()->getWidth());
+ }
+ }
+ }
}
void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
@@ -819,7 +851,15 @@ BOOL LLScrollListCtrl::selectFirstItem()
{
if (!itemp->getSelected())
{
- selectItem(itemp);
+ switch (mSelectionType)
+ {
+ case CELL:
+ selectItem(itemp, 0);
+ break;
+ case HEADER:
+ case ROW:
+ selectItem(itemp, -1);
+ }
}
success = TRUE;
mOriginalSelection = 0;
@@ -878,7 +918,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
{
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ // TODO: support range selection for cells
+ selectItem(itemp, -1, FALSE);
success = TRUE;
}
}
@@ -1004,10 +1045,14 @@ void LLScrollListCtrl::clearHighlightedItems()
void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
{
- if (mHighlightedItem != target_index)
- {
- mHighlightedItem = target_index;
- }
+ if (mHighlightedItem != target_index)
+ {
+ if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size())
+ {
+ mItemList[mHighlightedItem]->setHoverCell(-1);
+ }
+ mHighlightedItem = target_index;
+ }
}
S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
@@ -1022,7 +1067,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
{
if (item->getEnabled() && (item->getUUID() == (*iditr)))
{
- selectItem(item,FALSE);
+ // TODO: support multiple selection for cells
+ selectItem(item, -1, FALSE);
++count;
break;
}
@@ -1095,7 +1141,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
{
if (prev_item)
{
- selectItem(prev_item, !extend_selection);
+ selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1139,7 +1185,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
{
if (next_item)
{
- selectItem(next_item, !extend_selection);
+ selectItem(next_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1210,7 +1256,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
bool found = NULL != item;
if(found)
{
- selectItem(item);
+ selectItem(item, -1);
}
if (mCommitOnSelectionChange)
@@ -1278,7 +1324,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1318,7 +1364,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
// find offset of matching text (might have leading whitespace)
S32 offset = item_label.find(target_trimmed);
cellp->highlightText(offset, target_trimmed.size());
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1380,18 +1426,34 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
LLScrollListItem* item = *iter;
- if (item->getEnabled() && (item->getValue().asString() == value.asString()))
- {
- if (selected)
- {
- selectItem(item);
- }
- else
- {
- deselectItem(item);
- }
- found = TRUE;
- break;
+ if (item->getEnabled())
+ {
+ if (value.isBinary())
+ {
+ if (item->getValue().isBinary())
+ {
+ LLSD::Binary data1 = value.asBinary();
+ LLSD::Binary data2 = item->getValue().asBinary();
+ found = std::equal(data1.begin(), data1.end(), data2.begin()) ? TRUE : FALSE;
+ }
+ }
+ else
+ {
+ found = item->getValue().asString() == value.asString() ? TRUE : FALSE;
+ }
+
+ if (found)
+ {
+ if (selected)
+ {
+ selectItem(item, -1);
+ }
+ else
+ {
+ deselectItem(item);
+ }
+ break;
+ }
}
}
@@ -1464,7 +1526,7 @@ void LLScrollListCtrl::drawItems()
S32 max_columns = 0;
- LLColor4 highlight_color = LLColor4::white;
+ 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);
@@ -1490,7 +1552,8 @@ void LLScrollListCtrl::drawItems()
max_columns = llmax(max_columns, item->getNumColumns());
LLColor4 fg_color;
- LLColor4 bg_color(LLColor4::transparent);
+ LLColor4 hover_color(LLColor4::transparent);
+ LLColor4 select_color(LLColor4::transparent);
if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{
@@ -1499,44 +1562,44 @@ void LLScrollListCtrl::drawItems()
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+ select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just select-highlight it
{
- bg_color = mBgSelectedColor.get();
+ select_color = mBgSelectedColor.get();
}
fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
}
- else if (mHighlightedItem == line && mCanSelect)
+ if (mHighlightedItem == line && mCanSelect)
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+ hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just hover-highlight it
{
- bg_color = mHoveredColor.get();
+ hover_color = mHoveredColor.get();
}
}
else if (item->getHighlighted())
{
- bg_color = mHighlightedColor.get();
+ hover_color = mHighlightedColor.get();
}
else
{
if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
{
- bg_color = mBgStripeColor.get();
+ hover_color = mBgStripeColor.get();
}
}
if (!item->getEnabled())
{
- bg_color = mBgReadOnlyColor.get();
+ hover_color = mBgReadOnlyColor.get();
}
- item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
+ item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding);
cur_y -= mLineHeight;
}
@@ -1688,7 +1751,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if (mLastSelected == NULL)
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
else
{
@@ -1712,7 +1775,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
LLScrollListItem *item = *itor;
if (item == hit_item || item == lastSelected)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
selecting = !selecting;
if (hit_item == lastSelected)
{
@@ -1722,7 +1785,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
}
if (selecting)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
}
}
}
@@ -1737,7 +1800,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
{
- selectItem(hit_item, FALSE);
+ selectItem(hit_item, getColumnIndexFromOffset(x), FALSE);
}
else
{
@@ -1751,12 +1814,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
else
{
deselectAllItems(TRUE);
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
}
else
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
selection_changed = mSelectionChanged;
@@ -2124,8 +2187,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{
LLScrollListItem* item = hitItem(x, y);
if (item)
- {
- mouseOverHighlightNthItem(getItemIndex(item));
+ {
+ mouseOverHighlightNthItem(getItemIndex(item));
+ switch (mSelectionType)
+ {
+ case CELL:
+ item->setHoverCell(getColumnIndexFromOffset(x));
+ break;
+ case HEADER:
+ {
+ S32 cell = getColumnIndexFromOffset(x);
+ if (cell > 0)
+ {
+ item->setHoverCell(cell);
+ }
+ else
+ {
+ item->setHoverCell(-1);
+ }
+ break;
+ }
+ case ROW:
+ break;
+ }
}
else
{
@@ -2173,6 +2257,58 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
handled = TRUE;
}
break;
+ case KEY_LEFT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell < mColumns.size()) cell++;
+ break;
+ case HEADER:
+ if (cell == -1) cell = 1;
+ else if (cell > 1 && cell < mColumns.size()) cell++; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell >= 0) cell--;
+ break;
+ case HEADER:
+ if (cell > 1) cell--;
+ else if (cell == 1) cell = -1; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
case KEY_PAGE_UP:
if (mAllowKeyboardMovement || hasFocus())
{
@@ -2341,7 +2477,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
{
- selectItem(item);
+ selectItem(item, -1);
mNeedsScroll = true;
cellp->highlightText(0, 1);
mSearchTimer.reset();
@@ -2393,7 +2529,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
return TRUE;
}
-void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
+void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item)
{
if (!itemp) return;
@@ -2412,6 +2548,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
deselectAllItems(TRUE);
}
itemp->setSelected(TRUE);
+ switch (mSelectionType)
+ {
+ case CELL:
+ itemp->setSelectedCell(cell);
+ break;
+ case HEADER:
+ itemp->setSelectedCell(cell <= 0 ? -1 : cell);
+ break;
+ case ROW:
+ itemp->setSelectedCell(-1);
+ break;
+ }
mLastSelected = itemp;
mSelectionChanged = true;
}
@@ -2672,7 +2820,7 @@ void LLScrollListCtrl::selectAll()
LLScrollListItem *itemp = *iter;
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ selectItem(itemp, -1, FALSE);
}
}
@@ -2801,6 +2949,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
LLScrollListCtrl *parent = info->mParentCtrl;
if (!parent) return;
+ if (!parent->mCanSort) return;
+
S32 column_index = info->mIndex;
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 43e1c0d707..0cc481b113 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
public LLCtrlListInterface, public LLCtrlScrollInterface
{
public:
+ typedef enum e_selection_type
+ {
+ ROW, // default
+ CELL, // does not support multi-selection
+ HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select
+ } ESelectionType;
+
+ struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames>
+ {
+ static void declareValues();
+ };
+
struct Contents : public LLInitParam::Block<Contents>
{
Multiple<LLScrollListColumn::Params> columns;
@@ -97,8 +109,11 @@ public:
// 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,
@@ -115,7 +130,8 @@ public:
// sort and search behavior
Optional<S32> search_column,
sort_column;
- Optional<bool> sort_ascending;
+ Optional<bool> sort_ascending,
+ can_sort; // whether user is allowed to sort
// colors
Optional<LLUIColor> fg_unselected_color,
@@ -432,7 +448,7 @@ private:
void updateLineHeightInsert(LLScrollListItem* item);
void reportInvalidInput();
BOOL isRepeatedChars(const LLWString& string) const;
- void selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
+ void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE);
void deselectItem(LLScrollListItem* itemp);
void commitIfChanged();
BOOL setSort(S32 column, BOOL ascending);
@@ -457,9 +473,11 @@ private:
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;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index df22c88afb..51c615dd00 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -40,6 +40,8 @@
LLScrollListItem::LLScrollListItem( const Params& p )
: mSelected(FALSE),
mHighlighted(FALSE),
+ mHoverIndex(-1),
+ mSelectedIndex(-1),
mEnabled(p.enabled),
mUserdata(p.userdata),
mItemValue(p.value)
@@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem()
mColumns.clear();
}
+void LLScrollListItem::setSelected(BOOL b)
+{
+ mSelected = b;
+ mSelectedIndex = -1;
+}
+
+void LLScrollListItem::setHighlighted(BOOL b)
+{
+ mHighlighted = b;
+ mHoverIndex = -1;
+}
+
+void LLScrollListItem::setHoverCell(S32 cell)
+{
+ mHoverIndex = cell;
+}
+
+void LLScrollListItem::setSelectedCell(S32 cell)
+{
+ mSelectedIndex = cell;
+}
+
void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
{
mColumns.push_back(LLScrollListCell::create(p));
@@ -120,12 +144,21 @@ std::string LLScrollListItem::getContentsCSV() const
}
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+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;
- gl_rect_2d( bg_rect, bg_color );
+ if (mSelectedIndex < 0 && getSelected())
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, select_color);
+ }
+ else if (mHoverIndex < 0)
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, hover_color);
+ }
S32 cur_x = rect.mLeft;
S32 num_cols = getNumColumns();
@@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
{
LLUI::translate((F32) cur_x, (F32) rect.mBottom);
+ if (mSelectedIndex == cur_col)
+ {
+ // select specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth(),
+ 0);
+ gl_rect_2d(highlight_rect, select_color);
+ }
+ else if (mHoverIndex == cur_col)
+ {
+ // highlight specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth() ,
+ 0);
+ gl_rect_2d(highlight_rect, hover_color);
+ }
+
cell->draw( fg_color, highlight_color );
}
LLUI::popMatrix();
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index 13655b5873..d2c3dd7721 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -77,15 +77,21 @@ public:
virtual ~LLScrollListItem();
- void setSelected( BOOL b ) { mSelected = b; }
+ void setSelected( BOOL b );
BOOL getSelected() const { return mSelected; }
void setEnabled( BOOL b ) { mEnabled = b; }
BOOL getEnabled() const { return mEnabled; }
- void setHighlighted( BOOL b ) { mHighlighted = b; }
+ 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; }
@@ -107,14 +113,21 @@ public:
std::string getContentsCSV() const;
- virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+ 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& );
private:
BOOL mSelected;
- BOOL mHighlighted;
+ BOOL mHighlighted;
+ S32 mHoverIndex;
+ S32 mSelectedIndex;
BOOL mEnabled;
void* mUserdata;
LLSD mItemValue;
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 3b89a8ca63..d80a434f22 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -479,6 +479,7 @@ void LLSliderCtrl::onTabInto()
{
mEditor->onTabInto();
}
+ LLF32UICtrl::onTabInto();
}
void LLSliderCtrl::reportInvalidData()
diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp
index 296ea09079..ebd8ca0923 100644
--- a/indra/llui/llspellcheck.cpp
+++ b/indra/llui/llspellcheck.cpp
@@ -49,8 +49,6 @@ LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal;
LLSpellChecker::LLSpellChecker()
: mHunspell(NULL)
{
- // Load initial dictionary information
- refreshDictionaryMap();
}
LLSpellChecker::~LLSpellChecker()
@@ -58,6 +56,12 @@ LLSpellChecker::~LLSpellChecker()
delete mHunspell;
}
+void LLSpellChecker::initSingleton()
+{
+ // Load initial dictionary information
+ refreshDictionaryMap();
+}
+
bool LLSpellChecker::checkSpelling(const std::string& word) const
{
if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) )
diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h
index f1964cc091..3da5e30955 100644
--- a/indra/llui/llspellcheck.h
+++ b/indra/llui/llspellcheck.h
@@ -47,6 +47,7 @@ public:
protected:
void addToDictFile(const std::string& dict_path, const std::string& word);
void initHunspell(const std::string& dict_language);
+ void initSingleton();
public:
typedef std::list<std::string> dict_list_t;
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ce3fc29d32..ee78b82429 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -442,7 +442,8 @@ void LLSpinCtrl::setAllowEdit(BOOL allow_edit)
void LLSpinCtrl::onTabInto()
{
- mEditor->onTabInto();
+ mEditor->onTabInto();
+ LLF32UICtrl::onTabInto();
}
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 6521b883f8..e6b43da8e5 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -220,6 +220,8 @@ LLTabContainer::Params::Params()
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")
@@ -259,6 +261,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
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);
@@ -280,6 +284,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mMinTabWidth = tabcntr_vert_tab_min_width;
}
+ if (p.tabs_flashing_color.isProvided())
+ {
+ mEnableTabsFlashing = true;
+ }
+
initButtons( );
}
@@ -1102,6 +1111,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
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)
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 6bf963313c..8f8cedb1b9 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -109,6 +109,12 @@ public:
* 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)
@@ -310,6 +316,8 @@ private:
bool mCustomIconCtrlUsed;
bool mOpenTabsOnDragAndDrop;
+ bool mEnableTabsFlashing;
+ LLUIColor mTabsFlashingColor;
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
};
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 83b851eed2..20bea7fe24 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1017,7 +1017,38 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
// handle triple click
if (!mTripleClickTimer.hasExpired())
{
- selectAll();
+ 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;
}
@@ -1148,7 +1179,7 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- if (width != getRect().getWidth() || height != getRect().getHeight())
+ if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape)
{
bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false;
@@ -2228,6 +2259,18 @@ void LLTextBase::needsReflow(S32 index)
mReflowIndex = llmin(mReflowIndex, index);
}
+S32 LLTextBase::removeFirstLine()
+{
+ if (!mLineInfoList.empty())
+ {
+ S32 length = getLineEnd(0);
+ deselect();
+ removeStringNoUndo(0, length);
+ return length;
+ }
+ return 0;
+}
+
void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params)
{
segment_vec_t segments;
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 8687e7aa2a..4e966b7cef 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -404,6 +404,7 @@ public:
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; }
// wide-char versions
void setWText(const LLWString& text);
@@ -432,6 +433,7 @@ public:
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);
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 0afd32f332..134afc005b 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -163,13 +163,13 @@ BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text
}
-void LLTextBox::reshapeToFitText()
+void LLTextBox::reshapeToFitText(BOOL called_from_parent)
{
reflow();
S32 width = getTextPixelWidth();
S32 height = getTextPixelHeight();
- reshape( width + 2 * mHPad, height + 2 * mVPad, FALSE );
+ reshape( width + 2 * mHPad, height + 2 * mVPad, called_from_parent );
}
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index 061d2dd23d..c3e3b61912 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -60,7 +60,7 @@ public:
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL );
- void reshapeToFitText();
+ void reshapeToFitText(BOOL called_from_parent = FALSE);
S32 getTextPixelWidth();
S32 getTextPixelHeight();
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index c98da0d410..544a76e8d5 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -721,8 +721,9 @@ void LLUICtrl::resetDirty()
}
// virtual
-void LLUICtrl::onTabInto()
+void LLUICtrl::onTabInto()
{
+ onUpdateScrollToChild(this);
}
// virtual
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 333d03f208..20dda54771 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -454,13 +454,17 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
}
//
-// LLUrlEntrySeconlifeURL Describes *secondlife.com/ *lindenlab.com/ and *tilia-inc.com/ urls to substitute icon 'hand.png' before link
+// 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)"
"|"
- "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?))"
+ "(http://([-\\w\\.]*\\.)?secondlifegrid\\.net)"
+ "|"
+ "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)"
+ "|"
+ "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?))"
"\\/\\S*",
boost::regex::perl|boost::regex::icase);
@@ -495,12 +499,14 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const
}
//
-// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com *lindenlab.com and *tilia-inc.com urls to substitute icon 'hand.png' before link
+// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com *lindenlab.com *secondlifegrid.net and *tilia-inc.com urls to substitute icon 'hand.png' before link
//
LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
{
- mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(?!\\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";
@@ -511,8 +517,7 @@ LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
//
-LLUrlEntryAgent::LLUrlEntryAgent() :
- mAvatarNameCacheConnection()
+LLUrlEntryAgent::LLUrlEntryAgent()
{
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
@@ -543,7 +548,15 @@ void LLUrlEntryAgent::callObservers(const std::string &id,
void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
- mAvatarNameCacheConnection.disconnect();
+ 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();
@@ -630,11 +643,17 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
}
else
{
- if (mAvatarNameCacheConnection.connected())
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id);
+ if (it != mAvatarNameCacheConnections.end())
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
}
- mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
+ mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2));
+
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -695,14 +714,21 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url)
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
//
-LLUrlEntryAgentName::LLUrlEntryAgentName() :
- mAvatarNameCacheConnection()
+LLUrlEntryAgentName::LLUrlEntryAgentName()
{}
void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
const LLAvatarName& av_name)
{
- mAvatarNameCacheConnection.disconnect();
+ 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
@@ -737,11 +763,17 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab
}
else
{
- if (mAvatarNameCacheConnection.connected())
+ avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id);
+ if (it != mAvatarNameCacheConnections.end())
{
- mAvatarNameCacheConnection.disconnect();
+ if (it->second.connected())
+ {
+ it->second.disconnect();
+ }
+ mAvatarNameCacheConnections.erase(it);
}
- mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
+ mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2));
+
addObserver(agent_id_string, url, cb);
return LLTrans::getString("LoadingData");
}
@@ -1475,4 +1507,43 @@ void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_de
callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null);
}
+//
+// LLUrlEntryEmail Describes an IPv6 address
+//
+LLUrlEntryIPv6::LLUrlEntryIPv6()
+ : 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");
+}
+
+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;
+
+ 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;
+
+ return boost::regex_replace(url, regex, "");
+}
+std::string LLUrlEntryIPv6::getUrl(const std::string &string) const
+{
+ return string;
+}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 78c149d9fd..4af1ab5096 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -212,10 +212,14 @@ public:
LLUrlEntryAgent();
~LLUrlEntryAgent()
{
- if (mAvatarNameCacheConnection.connected())
+ for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
{
- mAvatarNameCacheConnection.disconnect();
+ 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);
@@ -227,7 +231,9 @@ protected:
/*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);
- boost::signals2::connection mAvatarNameCacheConnection;
+
+ typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
+ avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
///
@@ -241,10 +247,14 @@ public:
LLUrlEntryAgentName();
~LLUrlEntryAgentName()
{
- if (mAvatarNameCacheConnection.connected())
+ for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
{
- mAvatarNameCacheConnection.disconnect();
+ 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;
@@ -253,7 +263,9 @@ protected:
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
private:
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
- boost::signals2::connection mAvatarNameCacheConnection;
+
+ typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
+ avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
@@ -513,5 +525,18 @@ public:
/*virtual*/ std::string getUrl(const std::string &string) const;
};
+///
+/// LLUrlEntryEmail Describes an IPv6 address
+///
+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;
+
+ std::string mHostPath;
+};
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index ba6fa1e2e9..321a0ec5b9 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -79,6 +79,7 @@ LLUrlRegistry::LLUrlRegistry()
mUrlEntrySLLabel = new LLUrlEntrySLLabel();
registerUrl(mUrlEntrySLLabel);
registerUrl(new LLUrlEntryEmail());
+ registerUrl(new LLUrlEntryIPv6());
}
LLUrlRegistry::~LLUrlRegistry()
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index bd213d594a..cd47e2ecea 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -646,6 +646,16 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
}
// virtual
+void LLView::onUpdateScrollToChild(const LLUICtrl * cntrl)
+{
+ LLView* parent_view = getParent();
+ if (parent_view)
+ {
+ parent_view->onUpdateScrollToChild(cntrl);
+ }
+}
+
+// virtual
void LLView::translate(S32 x, S32 y)
{
mRect.translate(x, y);
@@ -1392,7 +1402,9 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
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())
+ if (child_rect.getWidth() != viewp->getRect().getWidth()
+ || child_rect.getHeight() != viewp->getRect().getHeight()
+ || sForceReshape)
{
viewp->reshape(child_rect.getWidth(), child_rect.getHeight());
}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index db81900aaf..5c91c37d3c 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -301,6 +301,7 @@ public:
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); }
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 3c34fd269e..4a4fdb72e3 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -903,4 +903,38 @@ namespace tut
"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 ]",
+ "");
+ }
}