summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llconsole.cpp6
-rw-r--r--indra/llui/lldockablefloater.cpp1
-rw-r--r--indra/llui/lldockablefloater.h21
-rw-r--r--indra/llui/lldockcontrol.cpp26
-rw-r--r--indra/llui/llflatlistview.cpp118
-rw-r--r--indra/llui/llflatlistview.h15
-rw-r--r--indra/llui/llfloater.cpp8
-rw-r--r--indra/llui/lllayoutstack.cpp13
-rw-r--r--indra/llui/lllayoutstack.h6
-rw-r--r--indra/llui/llmenugl.cpp42
-rw-r--r--indra/llui/llmultislider.cpp48
-rw-r--r--indra/llui/llmultislider.h32
-rw-r--r--indra/llui/llmultisliderctrl.cpp8
-rw-r--r--indra/llui/llmultisliderctrl.h2
-rw-r--r--indra/llui/llnotificationslistener.cpp277
-rw-r--r--indra/llui/llnotificationslistener.h20
-rw-r--r--indra/llui/llpanel.cpp5
-rw-r--r--indra/llui/llradiogroup.cpp109
-rw-r--r--indra/llui/llradiogroup.h47
-rw-r--r--indra/llui/llscrolllistcell.cpp2
-rw-r--r--indra/llui/llsearcheditor.h14
-rw-r--r--indra/llui/llspinctrl.cpp20
-rw-r--r--indra/llui/lltabcontainer.cpp21
-rw-r--r--indra/llui/lltabcontainer.h9
-rw-r--r--indra/llui/lltextbase.cpp86
-rw-r--r--indra/llui/lltextbase.h4
-rw-r--r--indra/llui/llui.cpp85
-rw-r--r--indra/llui/llui.h12
-rw-r--r--indra/llui/lluictrlfactory.cpp11
-rw-r--r--indra/llui/lluictrlfactory.h69
-rw-r--r--indra/llui/lluiimage.cpp23
-rw-r--r--indra/llui/lluiimage.h3
-rw-r--r--indra/llui/llurlentry.cpp9
-rw-r--r--indra/llui/llurlregistry.cpp20
-rw-r--r--indra/llui/llurlregistry.h4
-rw-r--r--indra/llui/llview.cpp23
-rw-r--r--indra/llui/llview.h8
37 files changed, 951 insertions, 276 deletions
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index fa0abd55d0..c9090d388d 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -392,4 +392,10 @@ void LLConsole::addLine(const LLWString& wline, F32 size, const LLColor4 &color)
Paragraph paragraph(wline, color, mTimer.getElapsedTimeF32(), mFont, (F32)getRect().getWidth() );
mParagraphs.push_back ( paragraph );
+
+ // 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/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index 63faf44f9d..6a5b475134 100644
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -54,6 +54,7 @@ void LLDockableFloater::init(LLDockableFloater* thiz)
LLDockableFloater::LLDockableFloater(LLDockControl* dockControl,
const LLSD& key, const Params& params) :
LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true)
+ , mOverlapsScreenChannel(false)
{
init(this);
}
diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h
index 2c339f4a3f..ae4f99e205 100644
--- a/indra/llui/lldockablefloater.h
+++ b/indra/llui/lldockablefloater.h
@@ -50,6 +50,16 @@ 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());
virtual ~LLDockableFloater();
@@ -85,6 +95,15 @@ public:
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; }
private:
/**
* Provides unique of dockable floater.
@@ -105,6 +124,8 @@ private:
* non exclusively.
*/
bool mUniqueDocking;
+
+ bool mOverlapsScreenChannel;
};
#endif /* LL_DOCKABLEFLOATER_H */
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index 456a2925a3..1c3c8449c5 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -182,6 +182,14 @@ void LLDockControl::moveDockable()
LLRect rootRect;
mGetAllowedRectCallback(rootRect);
+ bool unique_docking = false;
+ LLDockableFloater* dockable_floater =
+ dynamic_cast<LLDockableFloater*> (mDockableFloater);
+ if (dockable_floater != NULL)
+ {
+ unique_docking = dockable_floater->getUniqueDocking();
+ }
+
LLRect dockableRect = mDockableFloater->calcScreenRect();
S32 x = 0;
S32 y = 0;
@@ -208,7 +216,13 @@ void LLDockControl::moveDockable()
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
- y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
+ y = dockRect.mTop + dockableRect.getHeight();
+ // unique docking used with dock tongue, so add tongue height o the Y coordinate
+ if (unique_docking)
+ {
+ y += mDockTongue->getHeight();
+ }
+
// check is dockable inside root view rect
if (x < rootRect.mLeft)
{
@@ -273,7 +287,15 @@ void LLDockControl::forceRecalculatePosition()
void LLDockControl::drawToungue()
{
- if (mEnabled)
+ bool unique_docking = false;
+ LLDockableFloater* dockable_floater =
+ dynamic_cast<LLDockableFloater*> (mDockableFloater);
+ if (dockable_floater != NULL)
+ {
+ unique_docking = dockable_floater->getUniqueDocking();
+ }
+
+ if (mEnabled && unique_docking)
{
mDockTongue->draw(mDockTongueX, mDockTongueY);
}
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 64a4824a17..3754d155cf 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -66,7 +66,7 @@ const LLRect& LLFlatListView::getItemsRect() const
return mItemsPanel->getRect();
}
-bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/)
+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;
@@ -97,8 +97,11 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
// Children don't accept the focus
item->setTabStop(false);
- rearrangeItems();
- notifyParentItemsRectChanged();
+ if (rearrange)
+ {
+ rearrangeItems();
+ notifyParentItemsRectChanged();
+ }
return true;
}
@@ -530,7 +533,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
if ( !selectNextItemPair(true, reset_selection) && reset_selection)
{
// If case we are in accordion tab notify parent to go to the previous accordion
- notifyParent(LLSD().with("action","select_prev"));
+ if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed
+ resetSelection();
}
break;
}
@@ -539,7 +543,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
if ( !selectNextItemPair(false, reset_selection) && reset_selection)
{
// If case we are in accordion tab notify parent to go to the next accordion
- notifyParent(LLSD().with("action","select_next"));
+ if( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed
+ resetSelection();
}
break;
}
@@ -558,6 +563,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() )
{
+ ensureSelectedVisible();
+ /*
LLRect visible_rc = getVisibleContentRect();
LLRect selected_rc = getLastSelectedItemRect();
@@ -570,7 +577,8 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
// 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()));
+ notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));*/
+
handled = TRUE;
}
@@ -692,11 +700,30 @@ LLRect LLFlatListView::getSelectedItemsRect()
void LLFlatListView::selectFirstItem ()
{
selectItemPair(mItemPairs.front(), true);
+ ensureSelectedVisible();
}
void LLFlatListView::selectLastItem ()
{
selectItemPair(mItemPairs.back(), true);
+ ensureSelectedVisible();
+}
+
+void LLFlatListView::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()));
}
@@ -956,7 +983,86 @@ S32 LLFlatListView::notify(const LLSD& info)
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.
+ for (pairs_iterator_t
+ iter = mItemPairs.begin(),
+ iter_end = mItemPairs.end();
+ iter != iter_end; ++iter)
+ {
+ LLPanel* pItem = (*iter)->first;
+ if (1 == pItem->notify(action))
+ {
+ selectItemPair((*iter), false);
+ mItemsPanel->removeChild(pItem);
+ detached_items.push_back(pItem);
+ }
+ }
+ 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
+ for (pairs_iterator_t
+ iter = mItemPairs.begin(),
+ iter_end = mItemPairs.end();
+ iter != iter_end; ++iter)
+ {
+ (*iter)->first = NULL;
+ delete *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
+ {
+ for (std::vector<LLPanel*>::const_iterator
+ detached_iter = detached_items.begin(),
+ detached_iter_end = detached_items.end();
+ detached_iter != detached_iter_end; ++detached_iter)
+ {
+ LLPanel* pDetachedItem = *detached_iter;
+ for (pairs_iterator_t
+ iter = mItemPairs.begin(),
+ iter_end = mItemPairs.end();
+ iter != iter_end; ++iter)
+ {
+ item_pair_t* item_pair = *iter;
+ if (item_pair->first == pDetachedItem)
+ {
+ mItemPairs.erase(iter);
+ item_pair->first = NULL;
+ delete item_pair;
+ break;
+ }
+ }
+ }
+ rearrangeItems();
+ }
+ notifyParentItemsRectChanged();
+ }
+}
+
//EOF
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index ba824ff2df..5999e79f61 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -124,6 +124,8 @@ public:
/** Returns full rect of child panel */
const LLRect& getItemsRect() const;
+ LLRect getRequiredRect() { return getItemsRect(); }
+
/** Returns distance between items */
const S32 getItemsPad() { return mItemPad; }
@@ -131,7 +133,7 @@ public:
* 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);
+ 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.
@@ -269,6 +271,15 @@ public:
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
@@ -359,6 +370,8 @@ protected:
LLRect getSelectedItemsRect();
+ void ensureSelectedVisible();
+
private:
void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;}
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 5fd707fea3..845203b420 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2148,6 +2148,11 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
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);
+ }
}
}
@@ -2716,7 +2721,8 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
params.rect.left.set(0);
}
- setupParams(params, parent);
+ params.from_xui = true;
+ applyXUILayout(params, parent);
initFromParams(params);
initFloater(params);
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 1fb618adee..1aaba88c49 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -246,7 +246,8 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
output_node, output_params, &default_params);
}
- setupParams(p, parent);
+ p.from_xui = true;
+ applyXUILayout(p, parent);
LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
if (parent && layout_stackp)
@@ -413,6 +414,16 @@ void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL au
}
}
+void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)
+{
+ LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+
+ if (panel)
+ {
+ panel->mUserResize = user_resize;
+ }
+}
+
bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp)
{
LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index abd5436018..cde383b047 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -45,9 +45,8 @@ public:
{
Optional<std::string> orientation;
Optional<S32> border_size;
- Optional<bool> animate;
- Optional<bool> clip;
- // mMinWidth and mMinHeight are calculated, not set in XML
+ Optional<bool> animate,
+ clip;
Params();
};
@@ -81,6 +80,7 @@ public:
S32 getNumPanels() { return mPanels.size(); }
void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize);
+ void setPanelUserResize(const std::string& panel_name, BOOL user_resize);
/**
* Gets minimal width and/or height of the specified by name panel.
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index fd5c2b7fef..2648cbf08d 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -23,7 +23,7 @@
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
- *
+ *
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
@@ -97,7 +97,7 @@ const U32 SEPARATOR_HEIGHT_PIXELS = 8;
const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;
const S32 MENU_ITEM_PADDING = 4;
-const std::string BOOLEAN_TRUE_PREFIX( "X" );
+const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK
const std::string BRANCH_SUFFIX( ">" );
const std::string ARROW_UP ("^^^^^^^");
const std::string ARROW_DOWN("vvvvvvv");
@@ -1208,22 +1208,41 @@ void LLMenuItemBranchGL::openMenu()
branch->arrange();
- LLRect rect = branch->getRect();
+ 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());
- rect.setLeftTopAndSize( left, top,
- rect.getWidth(), rect.getHeight() );
+ branch_rect.setLeftTopAndSize( left, top,
+ branch_rect.getWidth(), branch_rect.getHeight() );
if (branch->getCanTearOff())
{
- rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
+ 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
+ delta_y = branch_rect.getHeight() - getRect().getHeight();
}
- branch->setRect( rect );
- branch->translateIntoRectWithExclusion( menu_region_rect, getMenu()->getRect(), FALSE );
+
+ 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);
@@ -3610,6 +3629,11 @@ public:
LLContextMenuBranch(const Params&);
+ virtual ~LLContextMenuBranch()
+ {
+ delete mBranch;
+ }
+
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -3905,7 +3929,7 @@ BOOL LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
item = LLUICtrlFactory::create<LLContextMenuBranch>(p);
LLMenuGL::sMenuContainer->addChild(item->getBranch());
- item->setFont( LLFontGL::getFontSansSerifSmall() );
+ item->setFont( LLFontGL::getFontSansSerif() );
return append( item );
}
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index 1891bca36c..aea7c5f87c 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -50,6 +50,12 @@ const F32 FLOAT_THRESHOLD = 0.00001f;
S32 LLMultiSlider::mNameCounter = 0;
+LLMultiSlider::SliderParams::SliderParams()
+: name("name"),
+ value("value", 0.f)
+{
+}
+
LLMultiSlider::Params::Params()
: max_sliders("max_sliders", 1),
allow_overlap("allow_overlap", false),
@@ -63,7 +69,8 @@ LLMultiSlider::Params::Params()
triangle_color("triangle_color"),
mouse_down_callback("mouse_down_callback"),
mouse_up_callback("mouse_up_callback"),
- thumb_width("thumb_width")
+ thumb_width("thumb_width"),
+ sliders("slider")
{
name = "multi_slider_bar";
mouse_opaque(true);
@@ -99,6 +106,20 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
{
setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
}
+
+ 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);
+ }
+ }
}
LLMultiSlider::~LLMultiSlider()
@@ -230,6 +251,30 @@ const std::string& LLMultiSlider::addSlider(F32 val)
return mCurSlider;
}
+void LLMultiSlider::addSlider(F32 val, const std::string& name)
+{
+ F32 initVal = val;
+
+ if(mValue.size() >= mMaxNumSliders) {
+ return;
+ }
+
+ bool foundOne = findUnusedValue(initVal);
+ if(!foundOne) {
+ return;
+ }
+
+ // add a new thumb rect
+ mThumbRects[name] = LLRect( 0, getRect().getHeight(), mThumbWidth, 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);
+}
+
bool LLMultiSlider::findUnusedValue(F32& initVal)
{
bool firstTry = true;
@@ -572,7 +617,6 @@ void LLMultiSlider::draw()
LLF32UICtrl::draw();
}
-
boost::signals2::connection LLMultiSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb )
{
if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h
index f8e43a0470..88576da85b 100644
--- a/indra/llui/llmultislider.h
+++ b/indra/llui/llmultislider.h
@@ -41,6 +41,13 @@ 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;
@@ -60,6 +67,7 @@ public:
mouse_up_callback;
Optional<S32> thumb_width;
+ Multiple<SliderParams> sliders;
Params();
};
@@ -68,13 +76,13 @@ protected:
friend class LLUICtrlFactory;
public:
virtual ~LLMultiSlider();
- void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
- F32 getSliderValue(const std::string& name) const;
+ void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
+ F32 getSliderValue(const std::string& name) const;
- const std::string& getCurSlider() const { return mCurSlider; }
- F32 getCurSliderValue() const { return getSliderValue(mCurSlider); }
- void setCurSlider(const std::string& name);
- 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 setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); }
/*virtual*/ void setValue(const LLSD& value);
/*virtual*/ LLSD getValue() const { return mValue; }
@@ -82,12 +90,13 @@ public:
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);
+ bool findUnusedValue(F32& initVal);
const std::string& addSlider();
const std::string& addSlider(F32 val);
- void deleteSlider(const std::string& name);
- void deleteCurSlider() { deleteSlider(mCurSlider); }
- void clear();
+ void addSlider(F32 val, const std::string& name);
+ void deleteSlider(const std::string& name);
+ void deleteCurSlider() { deleteSlider(mCurSlider); }
+ void clear();
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -109,7 +118,8 @@ protected:
LLRect mDragStartThumbRect;
S32 mThumbWidth;
- std::map<std::string, LLRect> mThumbRects;
+ std::map<std::string, LLRect>
+ mThumbRects;
LLUIColor mTrackColor;
LLUIColor mThumbOutlineColor;
LLUIColor mThumbCenterColor;
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 87938c19d4..f4434a0f78 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -65,7 +65,8 @@ LLMultiSliderCtrl::Params::Params()
text_color("text_color"),
text_disabled_color("text_disabled_color"),
mouse_down_callback("mouse_down_callback"),
- mouse_up_callback("mouse_up_callback")
+ mouse_up_callback("mouse_up_callback"),
+ sliders("slider")
{
mouse_opaque = true;
}
@@ -161,6 +162,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
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 );
@@ -328,7 +330,7 @@ void LLMultiSliderCtrl::updateText()
// static
void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
{
- LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl);
+ LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
if (!ctrl)
return;
@@ -369,7 +371,7 @@ void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
// static
void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata)
{
- LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl);
+ LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
if (!self)
return;
diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h
index 16d07541f2..e8366d09c2 100644
--- a/indra/llui/llmultisliderctrl.h
+++ b/indra/llui/llmultisliderctrl.h
@@ -69,6 +69,8 @@ public:
Optional<CommitCallbackParam> mouse_down_callback,
mouse_up_callback;
+ Multiple<LLMultiSlider::SliderParams> sliders;
+
Params();
};
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index fe4fbe7510..ee6ec0f88f 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -10,10 +10,10 @@
*/
#include "linden_common.h"
-
#include "llnotificationslistener.h"
-
#include "llnotifications.h"
+#include "llsd.h"
+#include "llui.h"
LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
LLEventAPI("LLNotifications",
@@ -24,6 +24,47 @@ LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications
"Add a notification with specified [\"name\"], [\"substitutions\"] and [\"payload\"].\n"
"If optional [\"reply\"] specified, arrange to send user response on that LLEventPump.",
&LLNotificationsListener::requestAdd);
+ add("listChannels",
+ "Post to [\"reply\"] a map of info on existing channels",
+ &LLNotificationsListener::listChannels,
+ LLSD().with("reply", LLSD()));
+ add("listChannelNotifications",
+ "Post to [\"reply\"] an array of info on notifications in channel [\"channel\"]",
+ &LLNotificationsListener::listChannelNotifications,
+ LLSD().with("reply", LLSD()).with("channel", LLSD()));
+ add("respond",
+ "Respond to notification [\"uuid\"] with data in [\"response\"]",
+ &LLNotificationsListener::respond,
+ LLSD().with("uuid", LLSD()));
+ add("cancel",
+ "Cancel notification [\"uuid\"]",
+ &LLNotificationsListener::cancel,
+ LLSD().with("uuid", LLSD()));
+ add("ignore",
+ "Ignore future notification [\"name\"]\n"
+ "(from <notification name= > in notifications.xml)\n"
+ "according to boolean [\"ignore\"].\n"
+ "If [\"name\"] is omitted or undefined, [un]ignore all future notifications.\n"
+ "Note that ignored notifications are not forwarded unless intercepted before\n"
+ "the \"Ignore\" channel.",
+ &LLNotificationsListener::ignore);
+ add("forward",
+ "Forward to [\"pump\"] future notifications on channel [\"channel\"]\n"
+ "according to boolean [\"forward\"]. When enabled, only types matching\n"
+ "[\"types\"] are forwarded, as follows:\n"
+ "omitted or undefined: forward all notifications\n"
+ "string: forward only the specific named [sig]type\n"
+ "array of string: forward any notification matching any named [sig]type.\n"
+ "When boolean [\"respond\"] is true, we auto-respond to each forwarded\n"
+ "notification.",
+ &LLNotificationsListener::forward,
+ LLSD().with("channel", LLSD()));
+}
+
+// This is here in the .cpp file so we don't need the definition of class
+// Forwarder in the header file.
+LLNotificationsListener::~LLNotificationsListener()
+{
}
void LLNotificationsListener::requestAdd(const LLSD& event_data) const
@@ -57,3 +98,235 @@ void LLNotificationsListener::NotificationResponder(const std::string& reply_pum
reponse_event["response"] = response;
LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
}
+
+void LLNotificationsListener::listChannels(const LLSD& params) const
+{
+ LLReqID reqID(params);
+ LLSD response(reqID.makeResponse());
+ for (LLNotifications::ChannelMap::const_iterator cmi(mNotifications.mChannels.begin()),
+ cmend(mNotifications.mChannels.end());
+ cmi != cmend; ++cmi)
+ {
+ LLSD channelInfo;
+ channelInfo["parent"] = cmi->second->getParentChannelName();
+ response[cmi->first] = channelInfo;
+ }
+ LLEventPumps::instance().obtain(params["reply"]).post(response);
+}
+
+void LLNotificationsListener::listChannelNotifications(const LLSD& params) const
+{
+ LLReqID reqID(params);
+ LLSD response(reqID.makeResponse());
+ LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"]));
+ if (channel)
+ {
+ LLSD notifications(LLSD::emptyArray());
+ for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end());
+ ni != nend; ++ni)
+ {
+ notifications.append(asLLSD(*ni));
+ }
+ response["notifications"] = notifications;
+ }
+ LLEventPumps::instance().obtain(params["reply"]).post(response);
+}
+
+void LLNotificationsListener::respond(const LLSD& params) const
+{
+ LLNotificationPtr notification(mNotifications.find(params["uuid"]));
+ if (notification)
+ {
+ notification->respond(params["response"]);
+ }
+}
+
+void LLNotificationsListener::cancel(const LLSD& params) const
+{
+ LLNotificationPtr notification(mNotifications.find(params["uuid"]));
+ if (notification)
+ {
+ mNotifications.cancel(notification);
+ }
+}
+
+void LLNotificationsListener::ignore(const LLSD& params) const
+{
+ // Calling a method named "ignore", but omitting its "ignore" Boolean
+ // argument, should by default cause something to be ignored. Explicitly
+ // pass ["ignore"] = false to cancel ignore.
+ bool ignore = true;
+ if (params.has("ignore"))
+ {
+ ignore = params["ignore"].asBoolean();
+ }
+ // This method can be used to affect either a single notification name or
+ // all future notifications. The two use substantially different mechanisms.
+ if (params["name"].isDefined())
+ {
+ // ["name"] was passed: ignore just that notification
+ LLUI::sSettingGroups["ignores"]->setBOOL(params["name"], ignore);
+ }
+ else
+ {
+ // no ["name"]: ignore all future notifications
+ mNotifications.setIgnoreAllNotifications(ignore);
+ }
+}
+
+class LLNotificationsListener::Forwarder: public LLEventTrackable
+{
+ LOG_CLASS(LLNotificationsListener::Forwarder);
+public:
+ Forwarder(LLNotifications& llnotifications, const std::string& channel):
+ mNotifications(llnotifications),
+ mRespond(false)
+ {
+ // Connect to the specified channel on construction. Because
+ // LLEventTrackable is a base, we should automatically disconnect when
+ // destroyed.
+ LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
+ if (channelptr)
+ {
+ // Insert our processing as a "passed filter" listener. This way
+ // we get to run before all the "changed" listeners, and we get to
+ // swipe it (hide it from the other listeners) if desired.
+ channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1));
+ }
+ }
+
+ void setPumpName(const std::string& name) { mPumpName = name; }
+ void setTypes(const LLSD& types) { mTypes = types; }
+ void setRespond(bool respond) { mRespond = respond; }
+
+private:
+ bool handle(const LLSD& notification) const;
+ bool matchType(const LLSD& filter, const std::string& type) const;
+
+ LLNotifications& mNotifications;
+ std::string mPumpName;
+ LLSD mTypes;
+ bool mRespond;
+};
+
+void LLNotificationsListener::forward(const LLSD& params)
+{
+ std::string channel(params["channel"]);
+ // First decide whether we're supposed to start forwarding or stop it.
+ // Default to true.
+ bool forward = true;
+ if (params.has("forward"))
+ {
+ forward = params["forward"].asBoolean();
+ }
+ if (! forward)
+ {
+ // This is a request to stop forwarding notifications on the specified
+ // channel. The rest of the params don't matter.
+ // Because mForwarders contains scoped_ptrs, erasing the map entry
+ // DOES delete the heap Forwarder object. Because Forwarder derives
+ // from LLEventTrackable, destroying it disconnects it from the
+ // channel.
+ mForwarders.erase(channel);
+ return;
+ }
+ // From here on, we know we're being asked to start (or modify) forwarding
+ // on the specified channel. Find or create an appropriate Forwarder.
+ ForwarderMap::iterator
+ entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first);
+ if (! entry->second)
+ {
+ entry->second.reset(new Forwarder(mNotifications, channel));
+ }
+ // Now, whether this Forwarder is brand-new or not, update it with the new
+ // request info.
+ Forwarder& fwd(*entry->second);
+ fwd.setPumpName(params["pump"]);
+ fwd.setTypes(params["types"]);
+ fwd.setRespond(params["respond"]);
+}
+
+bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const
+{
+ LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL;
+ if (notification["sigtype"].asString() == "delete")
+ {
+ LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL;
+ // let other listeners see the "delete" operation
+ return false;
+ }
+ LLNotificationPtr note(mNotifications.find(notification["id"]));
+ if (! note)
+ {
+ LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL;
+ return false;
+ }
+ if (! matchType(mTypes, note->getType()))
+ {
+ LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL;
+ // We're not supposed to intercept this particular notification. Let
+ // other listeners process it.
+ return false;
+ }
+ LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL;
+ // This is a notification we care about. Forward it through specified
+ // LLEventPump.
+ LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note));
+ // Are we also being asked to auto-respond?
+ if (mRespond)
+ {
+ LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL;
+ note->respond(LLSD::emptyMap());
+ // Did that succeed in removing the notification? Only cancel() if
+ // it's still around -- otherwise we get an LL_ERRS crash!
+ note = mNotifications.find(notification["id"]);
+ if (note)
+ {
+ LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL;
+ mNotifications.cancel(note);
+ }
+ }
+ // If we've auto-responded to this notification, then it's going to be
+ // deleted. Other listeners would get the change operation, try to look it
+ // up and be baffled by lookup failure. So when we auto-respond, suppress
+ // this notification: don't pass it to other listeners.
+ return mRespond;
+}
+
+bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const
+{
+ // Decide whether this notification matches filter:
+ // undefined: forward all notifications
+ if (filter.isUndefined())
+ {
+ return true;
+ }
+ // array of string: forward any notification matching any named type
+ if (filter.isArray())
+ {
+ for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray());
+ ti != tend; ++ti)
+ {
+ if (ti->asString() == type)
+ {
+ return true;
+ }
+ }
+ // Didn't match any entry in the array
+ return false;
+ }
+ // string: forward only the specific named type
+ return (filter.asString() == type);
+}
+
+LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note)
+{
+ LLSD notificationInfo(note->asLLSD());
+ // For some reason the following aren't included in LLNotification::asLLSD().
+ notificationInfo["summary"] = note->summarize();
+ notificationInfo["id"] = note->id();
+ notificationInfo["type"] = note->getType();
+ notificationInfo["message"] = note->getMessage();
+ notificationInfo["label"] = note->getLabel();
+ return notificationInfo;
+}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
index 9b405d7b4b..de208b57f0 100644
--- a/indra/llui/llnotificationslistener.h
+++ b/indra/llui/llnotificationslistener.h
@@ -13,6 +13,10 @@
#define LL_LLNOTIFICATIONSLISTENER_H
#include "lleventapi.h"
+#include "llnotificationptr.h"
+#include <boost/shared_ptr.hpp>
+#include <map>
+#include <string>
class LLNotifications;
class LLSD;
@@ -21,13 +25,27 @@ class LLNotificationsListener : public LLEventAPI
{
public:
LLNotificationsListener(LLNotifications & notifications);
+ ~LLNotificationsListener();
+private:
void requestAdd(LLSD const & event_data) const;
-private:
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;
+ void respond(const LLSD& params) const;
+ void cancel(const LLSD& params) const;
+ void ignore(const LLSD& params) const;
+ void forward(const LLSD& params);
+
+ static LLSD asLLSD(LLNotificationPtr);
+
+ class Forwarder;
+ typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
+ ForwarderMap mForwarders;
LLNotifications & mNotifications;
};
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index de2b43bf13..db32882438 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -452,7 +452,7 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
parseFollowsFlags(p);
setToolTip(p.tool_tip());
- setSaveToXML(p.from_xui);
+ setFromXUI(p.from_xui);
mHoverCursor = getCursorFromString(p.hover_cursor);
@@ -541,7 +541,8 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
output_node, output_params, &default_params);
}
- setupParams(params, parent);
+ params.from_xui = true;
+ applyXUILayout(params, parent);
{
LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
initFromParams(params);
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 86bd2f05ce..4087b484aa 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -43,15 +43,43 @@
#include "llui.h"
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
+#include "llsdutil.h"
static LLDefaultChildRegistry::Register<LLRadioGroup> r1("radio_group");
-static RadioGroupRegistry::Register<LLRadioCtrl> register_radio_ctrl("radio_item");
+/*
+ * 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
+{
+public:
+ typedef LLRadioGroup::ItemParams Params;
+ /*virtual*/ ~LLRadioCtrl();
+ /*virtual*/ void setValue(const LLSD& value);
+
+ /*virtual*/ BOOL postBuild();
+
+ LLSD getPayload() { return mPayload; }
+ // 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;
+
+ 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()
-: has_border("draw_border")
+: has_border("draw_border"),
+ items("item")
{
+ addSynonym(items, "radio_item");
+
name = "radio_group";
mouse_opaque = true;
follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;
@@ -76,6 +104,29 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
}
}
+void LLRadioGroup::initFromParams(const Params& p)
+{
+ LLUICtrl::initFromParams(p);
+ for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
+ it != p.items().end();
+ ++it)
+ {
+ LLRadioGroup::ItemParams item_params(*it);
+
+ item_params.font.setIfNotProvided(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);
+ }
+}
+
+
LLRadioGroup::~LLRadioGroup()
{
}
@@ -141,7 +192,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
{
- if (index < 0 || index >= (S32)mRadioButtons.size())
+ if (index < 0 || (S32)mRadioButtons.size() <= index )
{
return FALSE;
}
@@ -170,7 +221,7 @@ BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
if (!from_event)
{
- setControlValue(getSelectedIndex());
+ setControlValue(getValue());
}
return TRUE;
@@ -235,27 +286,6 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask)
return handled;
}
-
-// When adding a child button, we need to ensure that the radio
-// group gets a message when the button is clicked.
-
-/*virtual*/
-bool LLRadioGroup::addChild(LLView* view, S32 tab_group)
-{
- bool res = LLView::addChild(view, tab_group);
- if (res)
- {
- LLRadioCtrl* radio_ctrl = dynamic_cast<LLRadioCtrl*>(view);
- if (radio_ctrl)
- {
- radio_ctrl->setFont(mFont);
- radio_ctrl->setCommitCallback(boost::bind(&LLRadioGroup::onClickButton, this, _1));
- mRadioButtons.push_back(radio_ctrl);
- }
- }
- return res;
-}
-
BOOL LLRadioGroup::handleMouseDown(S32 x, S32 y, MASK mask)
{
// grab focus preemptively, before child button takes mousecapture
@@ -302,13 +332,12 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
void LLRadioGroup::setValue( const LLSD& value )
{
- std::string value_name = value.asString();
int idx = 0;
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
LLRadioCtrl* radio = *iter;
- if (radio->getName() == value_name)
+ if (radio->getPayload().asString() == value.asString())
{
setSelectedIndex(idx);
idx = -1;
@@ -325,7 +354,7 @@ void LLRadioGroup::setValue( const LLSD& value )
}
else
{
- llwarns << "LLRadioGroup::setValue: value not found: " << value_name << llendl;
+ llwarns << "LLRadioGroup::setValue: value not found: " << value.asString() << llendl;
}
}
}
@@ -337,7 +366,7 @@ LLSD LLRadioGroup::getValue() const
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
- if (idx == index) return LLSD((*iter)->getName());
+ if (idx == index) return LLSD((*iter)->getPayload());
++idx;
}
return LLSD();
@@ -357,11 +386,10 @@ LLUUID LLRadioGroup::getCurrentID() const
BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected)
{
S32 idx = 0;
- std::string value_string = value.asString();
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
- if((*iter)->getName() == value_string)
+ if((*iter)->getPayload().asString() == value.asString())
{
setSelectedIndex(idx);
return TRUE;
@@ -380,11 +408,10 @@ LLSD LLRadioGroup::getSelectedValue()
BOOL LLRadioGroup::isSelected(const LLSD& value) const
{
S32 idx = 0;
- std::string value_string = value.asString();
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
- if((*iter)->getName() == value_string)
+ if((*iter)->getPayload().asString() == value.asString())
{
if (idx == mSelectedIndex)
{
@@ -406,9 +433,21 @@ BOOL LLRadioGroup::operateOnAll(EOperation op)
return FALSE;
}
-LLRadioCtrl::LLRadioCtrl(const LLRadioCtrl::Params& p)
- : LLCheckBoxCtrl(p)
+LLRadioGroup::ItemParams::ItemParams()
+: value("value")
{
+ addSynonym(value, "initial_value");
+}
+
+LLRadioCtrl::LLRadioCtrl(const LLRadioGroup::ItemParams& p)
+: LLCheckBoxCtrl(p),
+ mPayload(p.value)
+{
+ // use name as default "Value" for backwards compatibility
+ if (!p.value.isProvided())
+ {
+ mPayload = p.name();
+ }
}
BOOL LLRadioCtrl::postBuild()
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 1e9b5115f8..b178bb36ca 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -37,35 +37,6 @@
#include "llcheckboxctrl.h"
#include "llctrlselectioninterface.h"
-
-/*
- * 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
-{
-public:
- struct Params : public LLInitParam::Block<Params, LLCheckBoxCtrl::Params>
- {};
-
- /*virtual*/ ~LLRadioCtrl();
- /*virtual*/ void setValue(const LLSD& value);
-
- /*virtual*/ BOOL postBuild();
-
- // Ensure label is in an attribute, not the contents
- static void setupParamsForExport(Params& p, LLView* parent);
-
-protected:
- LLRadioCtrl(const Params& p);
- friend class LLUICtrlFactory;
-};
-
-
-struct RadioGroupRegistry : public LLChildRegistry<RadioGroupRegistry>
-{};
-
/*
* An invisible view containing multiple mutually exclusive toggling
* buttons (usually radio buttons). Automatically handles the mutex
@@ -76,25 +47,31 @@ class LLRadioGroup
{
public:
+ struct ItemParams : public LLInitParam::Block<ItemParams, LLCheckBoxCtrl::Params>
+ {
+ Optional<LLSD> value;
+ ItemParams();
+ };
+
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
- Optional<bool> has_border;
+ Optional<bool> has_border;
+ Multiple<ItemParams, AtLeast<1> > items;
Params();
};
- // my valid children are stored in this registry
- typedef RadioGroupRegistry child_registry_t;
-
protected:
LLRadioGroup(const Params&);
friend class LLUICtrlFactory;
public:
+
+ /*virtual*/ void initFromParams(const Params&);
+
virtual ~LLRadioGroup();
virtual BOOL postBuild();
- virtual bool addChild(LLView* view, S32 tab_group = 0);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleKeyHere(KEY key, MASK mask);
@@ -134,7 +111,7 @@ public:
private:
const LLFontGL* mFont;
S32 mSelectedIndex;
- typedef std::vector<LLRadioCtrl*> button_list_t;
+ typedef std::vector<class LLRadioCtrl*> button_list_t;
button_list_t mRadioButtons;
BOOL mHasBorder;
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 544352176a..7238d903a3 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -353,7 +353,7 @@ LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p)
{
LLCheckBoxCtrl::Params checkbox_p;
checkbox_p.name("checkbox");
- checkbox_p.rect.left(0).bottom(0).width(p.width).height(p.width);
+ checkbox_p.rect = LLRect(0, p.width, p.width, 0);
checkbox_p.enabled(p.enabled);
checkbox_p.initial_value(p.value());
diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h
index bd2d595174..714aca9337 100644
--- a/indra/llui/llsearcheditor.h
+++ b/indra/llui/llsearcheditor.h
@@ -50,15 +50,17 @@ 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;
+ Optional<LLButton::Params> search_button,
+ clear_button;
+ Optional<bool> search_button_visible,
+ clear_button_visible;
Optional<commit_callback_t> keystroke_callback;
Params()
- : search_button("search_button")
- , search_button_visible("search_button_visible")
- , clear_button("clear_button")
- , clear_button_visible("clear_button_visible")
+ : search_button("search_button"),
+ search_button_visible("search_button_visible"),
+ clear_button("clear_button"),
+ clear_button_visible("clear_button_visible")
{
name = "search_editor";
}
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index d6d46654d5..20a1ab7af3 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -75,10 +75,8 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
- S32 top = getRect().getHeight();
- S32 bottom = top - 2 * spinctrl_btn_height;
- S32 centered_top = top;
- S32 centered_bottom = bottom;
+ 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));
@@ -105,25 +103,15 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
// Spin buttons
LLButton::Params up_button_params(p.up_button);
- up_button_params.rect
- .left(btn_left)
- .top(top)
- .right(btn_right)
- .height(spinctrl_btn_height);
+ up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
addChild(mUpBtn);
- LLRect down_rect( btn_left, top - spinctrl_btn_height, btn_right, bottom );
-
LLButton::Params down_button_params(p.down_button);
- down_button_params.rect
- .left(btn_left)
- .right(btn_right)
- .bottom(bottom)
- .height(spinctrl_btn_height);
+ down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 2d9106923e..327dd01612 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -120,6 +120,8 @@ LLTabContainer::Params::Params()
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),
tab_padding_right("tab_padding_right"),
@@ -145,6 +147,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
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 ),
@@ -262,8 +266,6 @@ bool LLTabContainer::addChild(LLView* view, S32 tab_group)
if (panelp)
{
- panelp->setSaveToXML(TRUE);
-
addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL));
return true;
}
@@ -906,7 +908,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
if (placeholder)
{
- btn_rect.translate(0, -3); // *TODO: make configurable
+ btn_rect.translate(0, -6); // *TODO: make configurable
LLTextBox::Params params;
params.name(trimmed_label);
params.rect(btn_rect);
@@ -933,6 +935,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.image_selected(mMiddleTabParams.tab_left_image_selected);
p.scale_image(true);
p.font_halign = mFontHalign;
+ p.pad_bottom( mLabelPadBottom );
p.tab_stop(false);
p.label_shadow(false);
if (indent)
@@ -956,8 +959,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.tab_stop(false);
p.label_shadow(false);
// Try to squeeze in a bit more text
- p.pad_left(4);
+ p.pad_left( mLabelPadLeft );
p.pad_right(2);
+ p.pad_bottom( mLabelPadBottom );
p.font_halign = mFontHalign;
p.follows.flags = FOLLOWS_LEFT;
p.follows.flags = FOLLOWS_LEFT;
@@ -1013,12 +1017,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
{
if (textbox)
{
- textbox->setSaveToXML(false);
addChild( textbox, 0 );
}
if (btn)
{
- btn->setSaveToXML(false);
addChild( btn, 0 );
}
}
@@ -1741,24 +1743,20 @@ void LLTabContainer::initButtons()
}
}
- mPrevArrowBtn->setSaveToXML(false);
mPrevArrowBtn->setTabStop(FALSE);
addChild(mPrevArrowBtn);
- mNextArrowBtn->setSaveToXML(false);
mNextArrowBtn->setTabStop(FALSE);
addChild(mNextArrowBtn);
if (mJumpPrevArrowBtn)
{
- mJumpPrevArrowBtn->setSaveToXML(false);
mJumpPrevArrowBtn->setTabStop(FALSE);
addChild(mJumpPrevArrowBtn);
}
if (mJumpNextArrowBtn)
{
- mJumpNextArrowBtn->setSaveToXML(false);
mJumpNextArrowBtn->setTabStop(FALSE);
addChild(mJumpNextArrowBtn);
}
@@ -1897,6 +1895,3 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y)
}
}
}
-
-
-
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index be9c6c7d06..5d0f194bf9 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -79,7 +79,9 @@ public:
Optional<S32> tab_width,
tab_min_width,
tab_max_width,
- tab_height;
+ tab_height,
+ label_pad_bottom,
+ label_pad_left;
Optional<bool> hide_tabs;
Optional<S32> tab_padding_right;
@@ -261,6 +263,11 @@ private:
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;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 1f120a1483..7447a984ac 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -842,7 +842,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask)
{
// Did we just click on a link?
if (cur_segment->getStyle()
- && cur_segment->getStyle()->isLink())
+ && cur_segment->getStyle()->isLink())
{
// *TODO: send URL here?
mURLClickSignal(this, LLSD() );
@@ -962,7 +962,10 @@ void LLTextBase::draw()
reflow();
// then update scroll position, as cursor may have moved
- updateScrollFromCursor();
+ if (!mReadOnly)
+ {
+ updateScrollFromCursor();
+ }
LLRect doc_rect;
if (mScroller)
@@ -1137,6 +1140,11 @@ void LLTextBase::reflow(S32 start_index)
// grow line height as necessary based on reported height of this segment
line_height = llmax(line_height, segment_height);
remaining_pixels -= segment_width;
+ if (remaining_pixels < 0)
+ {
+ // getNumChars() and getDimensions() should return consistent results
+ remaining_pixels = 0;
+ }
seg_offset += character_count;
@@ -1469,7 +1477,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
}
}
-void LLTextBase::setText(const LLStringExplicit &utf8str ,const LLStyle::Params& input_params)
+void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params)
{
// clear out the existing text and segments
getViewModel()->setDisplay(LLWStringUtil::null);
@@ -1927,11 +1935,19 @@ void LLTextBase::endOfLine()
void LLTextBase::startOfDoc()
{
setCursorPos(0);
+ if (mScroller)
+ {
+ mScroller->goToTop();
+ }
}
void LLTextBase::endOfDoc()
{
setCursorPos(getLength());
+ if (mScroller)
+ {
+ mScroller->goToBottom();
+ }
}
void LLTextBase::changePage( S32 delta )
@@ -1996,6 +2012,16 @@ void LLTextBase::changeLine( S32 delta )
setCursorPos(new_cursor_pos, true);
}
+bool LLTextBase::scrolledToStart()
+{
+ return mScroller->isAtTop();
+}
+
+bool LLTextBase::scrolledToEnd()
+{
+ return mScroller->isAtBottom();
+}
+
bool LLTextBase::setCursor(S32 row, S32 column)
{
@@ -2294,14 +2320,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 end = llmin( selection_start, seg_end );
S32 length = end - start;
font->render(text, start,
- rect.mLeft, rect.mTop,
- color,
- LLFontGL::LEFT, LLFontGL::TOP,
- 0,
- mStyle->getShadowType(),
- length, rect.getWidth(),
- &right_x,
- mEditor.getUseEllipses());
+ rect.mLeft, rect.mTop,
+ color,
+ LLFontGL::LEFT, LLFontGL::TOP,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length, rect.getWidth(),
+ &right_x,
+ mEditor.getUseEllipses());
}
rect.mLeft = (S32)ceil(right_x);
@@ -2313,14 +2339,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 length = end - start;
font->render(text, start,
- rect.mLeft, rect.mTop,
- LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ),
- LLFontGL::LEFT, LLFontGL::TOP,
- 0,
- LLFontGL::NO_SHADOW,
- length, rect.getWidth(),
- &right_x,
- mEditor.getUseEllipses());
+ rect.mLeft, rect.mTop,
+ LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ),
+ LLFontGL::LEFT, LLFontGL::TOP,
+ LLFontGL::NORMAL,
+ LLFontGL::NO_SHADOW,
+ length, rect.getWidth(),
+ &right_x,
+ mEditor.getUseEllipses());
}
rect.mLeft = (S32)ceil(right_x);
if( selection_end < seg_end )
@@ -2330,14 +2356,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 end = seg_end;
S32 length = end - start;
font->render(text, start,
- rect.mLeft, rect.mTop,
- color,
- LLFontGL::LEFT, LLFontGL::TOP,
- 0,
- mStyle->getShadowType(),
- length, rect.getWidth(),
- &right_x,
- mEditor.getUseEllipses());
+ rect.mLeft, rect.mTop,
+ color,
+ LLFontGL::LEFT, LLFontGL::TOP,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length, rect.getWidth(),
+ &right_x,
+ mEditor.getUseEllipses());
}
return right_x;
}
@@ -2464,6 +2490,12 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
{
LLWString text = mEditor.getWText();
+ LLUIImagePtr image = mStyle->getImage();
+ if( image.notNull())
+ {
+ num_pixels -= image->getWidth();
+ }
+
// search for newline and if found, truncate there
S32 last_char = mStart + segment_offset;
for (; last_char != mEnd; ++last_char)
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index a1f8ba39ae..038b9eaa62 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -180,8 +180,11 @@ public:
void changePage( S32 delta );
void changeLine( S32 delta );
+ bool scrolledToStart();
+ bool scrolledToEnd();
const LLFontGL* getDefaultFont() const { return mDefaultFont; }
+ LLStyle::Params getDefaultStyle();
public:
// Fired when a URL link is clicked
@@ -254,7 +257,6 @@ protected:
LLTextBase(const Params &p);
virtual ~LLTextBase();
void initFromParams(const Params& p);
- LLStyle::Params getDefaultStyle();
virtual void onValueChange(S32 start, S32 end);
// draw methods
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 6603887905..d0ed3b6fca 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1896,17 +1896,27 @@ namespace LLInitParam
control("")
{}
- LLUIColor TypedParam<LLUIColor>::getValueFromBlock() const
+ void TypedParam<LLUIColor>::setValueFromBlock() const
{
if (control.isProvided())
{
- return LLUIColorTable::instance().getColor(control);
+ mData.mValue = LLUIColorTable::instance().getColor(control);
}
else
{
- return LLColor4(red, green, blue, alpha);
+ mData.mValue = LLColor4(red, green, blue, alpha);
}
}
+
+ void TypedParam<LLUIColor>::setBlockFromValue()
+ {
+ LLColor4 color = mData.mValue.get();
+ red = color.mV[VRED];
+ green = color.mV[VGREEN];
+ blue = color.mV[VBLUE];
+ alpha = color.mV[VALPHA];
+ control.set("", false);
+ }
void TypeValues<LLUIColor>::declareValues()
{
@@ -1932,28 +1942,33 @@ namespace LLInitParam
addSynonym(name, "");
}
- const LLFontGL* TypedParam<const LLFontGL*>::getValueFromBlock() const
+ void TypedParam<const LLFontGL*>::setValueFromBlock() const
{
- if (name.isProvided())
+ const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
+ if (res_fontp)
{
- const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
- if (res_fontp)
- {
- return res_fontp;
- }
+ mData.mValue = res_fontp;
+ return;
+ }
- U8 fontstyle = 0;
- fontstyle = LLFontGL::getStyleFromString(style());
- LLFontDescriptor desc(name(), size(), fontstyle);
- const LLFontGL* fontp = LLFontGL::getFont(desc);
- if (fontp)
- {
- return fontp;
- }
+ U8 fontstyle = 0;
+ fontstyle = LLFontGL::getStyleFromString(style());
+ LLFontDescriptor desc(name(), size(), fontstyle);
+ const LLFontGL* fontp = LLFontGL::getFont(desc);
+ if (fontp)
+ {
+ mData.mValue = fontp;
+ }
+ }
+
+ void TypedParam<const LLFontGL*>::setBlockFromValue()
+ {
+ if (mData.mValue)
+ {
+ name = LLFontGL::nameFromFont(mData.mValue);
+ size = LLFontGL::sizeFromFont(mData.mValue);
+ style = LLFontGL::getStringFromStyle(mData.mValue->getFontDesc().getStyle());
}
-
- // default to current value
- return mData.mValue;
}
TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
@@ -1966,7 +1981,7 @@ namespace LLInitParam
height("height")
{}
- LLRect TypedParam<LLRect>::getValueFromBlock() const
+ void TypedParam<LLRect>::setValueFromBlock() const
{
LLRect rect;
@@ -2027,7 +2042,21 @@ namespace LLInitParam
rect.mBottom = bottom;
rect.mTop = top;
}
- return rect;
+ mData.mValue = rect;
+ }
+
+ void TypedParam<LLRect>::setBlockFromValue()
+ {
+ // because of the ambiguity in specifying a rect by position and/or dimensions
+ // we clear the "provided" flag so that values from xui/etc have priority
+ // over those calculated from the rect object
+
+ left.set(mData.mValue.mLeft, false);
+ right.set(mData.mValue.mRight, false);
+ bottom.set(mData.mValue.mBottom, false);
+ top.set(mData.mValue.mTop, false);
+ width.set(mData.mValue.getWidth(), false);
+ height.set(mData.mValue.getHeight(), false);
}
TypedParam<LLCoordGL>::TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
@@ -2037,9 +2066,15 @@ namespace LLInitParam
{
}
- LLCoordGL TypedParam<LLCoordGL>::getValueFromBlock() const
+ void TypedParam<LLCoordGL>::setValueFromBlock() const
+ {
+ mData.mValue.set(x, y);
+ }
+
+ void TypedParam<LLCoordGL>::setBlockFromValue()
{
- return LLCoordGL(x, y);
+ x = mData.mValue.mX;
+ y = mData.mValue.mY;
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 5ec07f1941..5840e76f5c 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -379,7 +379,8 @@ namespace LLInitParam
TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- LLRect getValueFromBlock() const;
+ void setValueFromBlock() const;
+ void setBlockFromValue();
};
template<>
@@ -401,7 +402,8 @@ namespace LLInitParam
Optional<std::string> control;
TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- LLUIColor getValueFromBlock() const;
+ void setValueFromBlock() const;
+ void setBlockFromValue();
};
// provide a better default for Optional<const LLFontGL*> than NULL
@@ -429,7 +431,8 @@ namespace LLInitParam
style;
TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- const LLFontGL* getValueFromBlock() const;
+ void setValueFromBlock() const;
+ void setBlockFromValue();
};
template<>
@@ -467,7 +470,8 @@ namespace LLInitParam
y;
TypedParam(BlockDescriptor& descriptor, const char* name, LLCoordGL value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
- LLCoordGL getValueFromBlock() const;
+ void setValueFromBlock() const;
+ void setBlockFromValue();
};
}
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index f9e134e1e5..27237800d4 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -105,9 +105,12 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
}
}
+static LLFastTimer::DeclareTimer FTM_CREATE_CHILDREN("Create XUI Children");
+
//static
void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
{
+ LLFastTimer ft(FTM_CREATE_CHILDREN);
if (node.isNull()) return;
for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
@@ -393,7 +396,7 @@ BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& na
//static
void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)
{
- if (tab_group < 0) tab_group = parent->getLastTabGroup();
+ if (tab_group == S32_MAX) tab_group = parent->getLastTabGroup();
parent->addChild(view, tab_group);
}
@@ -454,9 +457,3 @@ const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_ty
return LLWidgetNameRegistry::instance().getValue(widget_type);
}
-// static
-void LLUICtrlFactory::connect(LLView* parent, LLView* child)
-{
- parent->addChild(child);
-}
-
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 55d7d745eb..b1fa6add67 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -180,34 +180,52 @@ public:
void popFactoryFunctions();
template<typename T>
- static T* create(typename T::Params& params, LLView* parent = NULL)
+ static T* createWidget(typename T::Params& params, LLView* parent = NULL)
{
- //#pragma message("Generating LLUICtrlFactory::create")
- params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
- //S32 foo = "test";
+ T* widget = NULL;
if (!params.validateBlock())
{
llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+ //return NULL;
+ }
+
+ {
+ LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
+ widget = new T(params);
+ }
+ {
+ LLFastTimer timer(FTM_INIT_FROM_PARAMS);
+ widget->initFromParams(params);
}
- T* widget = new T(params);
- widget->initFromParams(params);
+
if (parent)
{
- connect(parent, widget);
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
+ setCtrlParent(widget, parent, tab_group);
}
return widget;
}
- // fix for gcc template instantiation annoyance
- static void connect(LLView* parent, LLView* child);
-
+ template<typename T>
+ static T* create(typename T::Params& params, LLView* parent = NULL)
+ {
+ params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
+
+ T* widget = createWidget<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, LLXMLNodePtr output_node = NULL)
{
- //#pragma message("Generating LLUICtrlFactory::createFromFile")
T* widget = NULL;
std::string skinned_filename = findSkinnedFilename(filename);
@@ -272,7 +290,6 @@ fail:
{
LLFastTimer timer(FTM_WIDGET_SETUP);
- //#pragma message("Generating LLUICtrlFactory::defaultBuilder")
typename T::Params params(getDefaultParams<T>());
LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
@@ -290,36 +307,18 @@ fail:
}
// Apply layout transformations, usually munging rect
- T::setupParams(params, parent);
-
- if (!params.validateBlock())
- {
- llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
- }
- T* widget;
- {
- LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
- widget = new T(params);
- }
- {
- LLFastTimer timer(FTM_INIT_FROM_PARAMS);
- widget->initFromParams(params);
- }
+ params.from_xui = true;
+ T::applyXUILayout(params, parent);
+ T* widget = createWidget<T>(params, parent);
- if (parent)
- {
- S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
- setCtrlParent(widget, parent, tab_group);
- }
-
typedef typename T::child_registry_t registry_t;
createChildren(widget, node, registry_t::instance(), output_node);
- if (!widget->postBuild())
+ if (widget && !widget->postBuild())
{
delete widget;
- return NULL;
+ widget = NULL;
}
return widget;
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
index f941f391eb..966d919dc7 100644
--- a/indra/llui/lluiimage.cpp
+++ b/indra/llui/lluiimage.cpp
@@ -161,22 +161,33 @@ void LLUIImage::onImageLoaded()
namespace LLInitParam
{
- LLUIImage* TypedParam<LLUIImage*>::getValueFromBlock() const
+ void TypedParam<LLUIImage*>::setValueFromBlock() const
{
// The keyword "none" is specifically requesting a null image
// do not default to current value. Used to overwrite template images.
if (name() == "none")
{
- return NULL;
+ mData.mValue = NULL;
+ return;
}
LLUIImage* imagep = LLUI::getUIImage(name());
- if (!imagep)
+ if (imagep)
{
- // default to current value
- imagep = mData.mValue;
+ mData.mValue = imagep;
+ }
+ }
+
+ void TypedParam<LLUIImage*>::setBlockFromValue()
+ {
+ if (mData.mValue == NULL)
+ {
+ name = "none";
+ }
+ else
+ {
+ name = mData.mValue->getName();
}
- return imagep;
}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index 5fa9610ab2..bdfc44262d 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -111,7 +111,8 @@ namespace LLInitParam
{
}
- LLUIImage* getValueFromBlock() const;
+ void setValueFromBlock() const;
+ void setBlockFromValue();
};
// Need custom comparison function for our test app, which only loads
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 7350457274..99eb992ddd 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -80,7 +80,7 @@ std::string LLUrlEntryBase::escapeUrl(const std::string &url) const
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
- "-._~!$?&()*+,@:;=/%";
+ "-._~!$?&()*+,@:;=/%#";
std::sort(no_escape_chars.begin(), no_escape_chars.end());
initialized = true;
@@ -201,8 +201,11 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string)
//
LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol()
{
- mPattern = boost::regex("(\\bwww\\.\\S+\\.\\S+|\\S+.com\\S*|\\S+.net\\S*|\\S+.edu\\S*|\\S+.org\\S*)",
- boost::regex::perl|boost::regex::icase);
+ mPattern = boost::regex("("
+ "\\bwww\\.\\S+\\.\\S+" // www.FOO.BAR
+ "|\\b[^ \t\n\r\f\v:/]+.(?:com|net|edu|org)[^[:space:][:alnum:]]*$" // FOO.net
+ ")",
+ boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
}
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index afcff0d409..ad5c0911f8 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -223,3 +223,23 @@ bool LLUrlRegistry::hasUrl(const LLWString &text)
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;
+}
+
+bool LLUrlRegistry::isUrl(const LLWString &text)
+{
+ LLUrlMatch match;
+ if (findUrl(text, match))
+ {
+ return (match.getStart() == 0 && match.getEnd() >= text.size()-1);
+ }
+ return false;
+}
diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h
index d7800d8cfc..399ee0a988 100644
--- a/indra/llui/llurlregistry.h
+++ b/indra/llui/llurlregistry.h
@@ -85,6 +85,10 @@ public:
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);
+
private:
LLUrlRegistry();
friend class LLSingleton<LLUrlRegistry>;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 8917e4b813..f1b08c380b 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -126,7 +126,7 @@ LLView::LLView(const LLView::Params& p)
: mName(p.name),
mParentView(NULL),
mReshapeFlags(FOLLOWS_NONE),
- mSaveToXML(p.from_xui),
+ mFromXUI(p.from_xui),
mIsFocusRoot(FALSE),
mLastVisible(FALSE),
mNextInsertionOrdinal(0),
@@ -2479,7 +2479,7 @@ static bool get_last_child_rect(LLView* parent, LLRect *rect)
for (;itor != parent->getChildList()->end(); ++itor)
{
LLView *last_view = (*itor);
- if (last_view->getSaveToXML())
+ if (last_view->getFromXUI())
{
*rect = last_view->getRect();
return true;
@@ -2489,13 +2489,11 @@ static bool get_last_child_rect(LLView* parent, LLRect *rect)
}
//static
-void LLView::setupParams(LLView::Params& p, LLView* parent)
+void LLView::applyXUILayout(LLView::Params& p, LLView* parent)
{
const S32 VPAD = 4;
const S32 MIN_WIDGET_HEIGHT = 10;
- p.from_xui(true);
-
// *NOTE: This will confuse export of floater/panel coordinates unless
// the default is also "topleft". JC
if (p.layout().empty() && parent)
@@ -2503,6 +2501,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
p.layout = parent->getLayout();
}
+
if (parent)
{
LLRect parent_rect = parent->getLocalRect();
@@ -2518,7 +2517,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
}
// convert negative or centered coordinates to parent relative values
- // Note: some of this logic matches the logic in TypedParam<LLRect>::getValueFromBlock()
+ // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock()
if (p.center_horiz)
{
@@ -2538,8 +2537,8 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
}
else
{
- if (p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
- if (p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
+ if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
+ if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
}
if (p.center_vert)
{
@@ -2559,13 +2558,13 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
}
else
{
- if (p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
- if (p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
+ if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
+ if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
}
// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
- if (!p.rect.height.isProvided() && !p.rect.top.isProvided())
+ if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0)
{
p.rect.height = MIN_WIDGET_HEIGHT;
}
@@ -2664,7 +2663,7 @@ 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::setupParams(final, parent);
+ LLView::applyXUILayout(final, parent);
// Must actually extract the rectangle to get consistent
// right = left+width, top = bottom+height
LLRect final_rect = final.rect;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index f8460f5361..c4d7313743 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -395,8 +395,8 @@ public:
void parseFollowsFlags(const LLView::Params& params);
// Some widgets, like close box buttons, don't need to be saved
- BOOL getSaveToXML() const { return mSaveToXML; }
- void setSaveToXML(BOOL b) { mSaveToXML = b; }
+ BOOL getFromXUI() const { return mFromXUI; }
+ void setFromXUI(BOOL b) { mFromXUI = b; }
typedef enum e_hit_test_type
{
@@ -498,7 +498,7 @@ public:
// Set up params after XML load before calling new(),
// usually to adjust layout.
- static void setupParams(Params& p, LLView* parent);
+ static void applyXUILayout(Params& p, LLView* parent);
// For re-export of floaters and panels, convert the coordinate system
// to be top-left based.
@@ -573,7 +573,7 @@ private:
LLUIString mToolTipMsg; // isNull() is true if none.
U8 mSoundFlags;
- BOOL mSaveToXML;
+ BOOL mFromXUI;
BOOL mIsFocusRoot;
BOOL mUseBoundingRect; // hit test against bounding rectangle that includes all child elements