summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llflatlistview.cpp30
-rw-r--r--indra/llui/llflatlistview.h2
-rw-r--r--indra/llui/llfloater.cpp2
-rw-r--r--indra/llui/lllayoutstack.cpp2
-rw-r--r--indra/llui/llmenugl.cpp2
-rw-r--r--indra/llui/llmultislider.cpp48
-rw-r--r--indra/llui/llmultislider.h32
-rw-r--r--indra/llui/llmultisliderctrl.cpp4
-rw-r--r--indra/llui/llmultisliderctrl.h2
-rw-r--r--indra/llui/llnotificationslistener.cpp269
-rw-r--r--indra/llui/llnotificationslistener.h20
-rw-r--r--indra/llui/llpanel.cpp4
-rw-r--r--indra/llui/llradiogroup.cpp4
-rw-r--r--indra/llui/llscrolllistcell.cpp2
-rw-r--r--indra/llui/llspinctrl.cpp20
-rw-r--r--indra/llui/lltabcontainer.cpp8
-rw-r--r--indra/llui/lltextbase.cpp23
-rw-r--r--indra/llui/lltextbase.h2
-rw-r--r--indra/llui/llui.cpp16
-rw-r--r--indra/llui/lluictrlfactory.h3
-rw-r--r--indra/llui/llurlentry.cpp4
-rw-r--r--indra/llui/llurlregistry.cpp20
-rw-r--r--indra/llui/llurlregistry.h4
-rw-r--r--indra/llui/llview.cpp24
-rw-r--r--indra/llui/llview.h8
25 files changed, 478 insertions, 77 deletions
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 64a4824a17..7b7a3139a4 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -530,7 +530,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 +540,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 +560,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 +574,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 +697,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()));
}
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index ba824ff2df..26e84a6fe1 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -359,6 +359,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 f7fd2dbdfe..d7a692ec9b 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2717,7 +2717,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
}
params.from_xui = true;
- setupParams(params, parent);
+ applyXUILayout(params, parent);
initFromParams(params);
initFloater(params);
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 5e15fa3919..7d8c102750 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -247,7 +247,7 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
}
p.from_xui = true;
- setupParams(p, parent);
+ applyXUILayout(p, parent);
LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
if (parent && layout_stackp)
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index c42ae040d6..202ed04fbc 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3905,7 +3905,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 7323323d8c..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 );
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..629964c322 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,227 @@ 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)
+ {
+ // Try connecting at the front of the 'changed' signal. That way
+ // we shouldn't get starved by preceding listeners.
+ channelptr->connectAtFrontChanged(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;
+ 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;
+ 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);
+ }
+ }
+ return false; // let other listeners get same notification
+}
+
+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 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 738a96f730..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);
@@ -542,7 +542,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
}
params.from_xui = true;
- setupParams(params, parent);
+ applyXUILayout(params, parent);
{
LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
initFromParams(params);
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 997b9c13f8..4087b484aa 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -116,6 +116,10 @@ void LLRadioGroup::initFromParams(const Params& p)
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);
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/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 83e2e3db50..327dd01612 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -266,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;
}
@@ -1019,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 );
}
}
@@ -1747,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);
}
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index cb0907a771..e54032ac5e 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -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)
@@ -1932,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 )
@@ -2001,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)
{
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index a1f8ba39ae..c91578b637 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -180,6 +180,8 @@ public:
void changePage( S32 delta );
void changeLine( S32 delta );
+ bool scrolledToStart();
+ bool scrolledToEnd();
const LLFontGL* getDefaultFont() const { return mDefaultFont; }
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 728ed4e7aa..d0ed3b6fca 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -2047,12 +2047,16 @@ namespace LLInitParam
void TypedParam<LLRect>::setBlockFromValue()
{
- left = mData.mValue.mLeft;
- right = mData.mValue.mRight;
- bottom = mData.mValue.mBottom;
- top = mData.mValue.mTop;
- width.setProvided(false);
- height.setProvided(false);
+ // 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)
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 6788f29ba9..b1fa6add67 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -184,8 +184,6 @@ public:
{
T* widget = NULL;
- T::setupParams(params, parent);
-
if (!params.validateBlock())
{
llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
@@ -310,6 +308,7 @@ fail:
// Apply layout transformations, usually munging rect
params.from_xui = true;
+ T::applyXUILayout(params, parent);
T* widget = createWidget<T>(params, parent);
typedef typename T::child_registry_t registry_t;
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 7350457274..983f0a2d49 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,7 +201,7 @@ 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*)",
+ mPattern = boost::regex("(\\bwww\\.\\S+\\.\\S+|\\b[^ \t\n\r\f\v:/]+.com\\S*|\\b[^ \t\n\r\f\v:/]+.net\\S*|\\b[^ \t\n\r\f\v:/]+.edu\\S*|\\b[^ \t\n\r\f\v:/]+.org\\S*)",
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 a8d8626e49..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,7 +2489,7 @@ 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;
@@ -2509,7 +2509,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
LLRect last_rect = parent->getLocalRect();
bool layout_topleft = (p.layout() == "topleft");
- if (layout_topleft && p.from_xui)
+ if (layout_topleft)
{
//invert top to bottom
if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
@@ -2535,10 +2535,10 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
p.rect.right.setProvided(false); // recalculate the right
}
}
- else if (p.from_xui) // only do negative coordinate magic for XUI
+ 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)
{
@@ -2556,15 +2556,15 @@ void LLView::setupParams(LLView::Params& p, LLView* parent)
p.rect.top.setProvided(false); // recalculate the top
}
}
- else if (p.from_xui)
+ 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;
}
@@ -2663,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