summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/lluictrl.cpp6
-rw-r--r--indra/llui/lluictrl.h4
-rw-r--r--indra/llui/llview.cpp650
-rw-r--r--indra/llui/llview.h58
-rw-r--r--indra/llui/llviewinject.cpp49
-rw-r--r--indra/llui/llviewinject.h56
7 files changed, 395 insertions, 430 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index b3b2f4ae56..0ab883cb70 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -112,6 +112,7 @@ set(llui_SOURCE_FILES
llurlmatch.cpp
llurlregistry.cpp
llviewborder.cpp
+ llviewinject.cpp
llviewmodel.cpp
llview.cpp
llviewquery.cpp
@@ -216,6 +217,7 @@ set(llui_HEADER_FILES
llurlmatch.h
llurlregistry.h
llviewborder.h
+ llviewinject.h
llviewmodel.h
llview.h
llviewquery.h
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index d58df5801b..9b9e2ddb55 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -1045,3 +1045,9 @@ boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal
if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
return mDoubleClickSignal->connect(cb);
}
+
+void LLUICtrl::addInfo(LLSD & info)
+{
+ LLView::addInfo(info);
+ info["value"] = getValue();
+}
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 09bed9b958..8a8b589e9c 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -301,7 +301,9 @@ protected:
static F32 sActiveControlTransparency;
static F32 sInactiveControlTransparency;
-
+
+ virtual void addInfo(LLSD & info);
+
private:
BOOL mIsChrome;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 60452b9ae4..3ddfb090c8 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -31,7 +31,10 @@
#include "llview.h"
#include <cassert>
+#include <sstream>
#include <boost/tokenizer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
#include "llrender.h"
#include "llevent.h"
@@ -44,6 +47,7 @@
#include "v3color.h"
#include "lluictrlfactory.h"
#include "lltooltip.h"
+#include "llsdutil.h"
// for ui edit hack
#include "llbutton.h"
@@ -66,6 +70,8 @@ S32 LLView::sLastLeftXML = S32_MIN;
S32 LLView::sLastBottomXML = S32_MIN;
std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack;
+LLView::DrilldownFunc LLView::sDrilldown =
+ boost::bind(&LLView::pointInView, _1, _2, _3, HIT_TEST_USE_BOUNDING_RECT);
//#if LL_DEBUG
BOOL LLView::sIsDrawing = FALSE;
@@ -346,13 +352,11 @@ void LLView::removeChild(LLView* child)
LLView::ctrl_list_t LLView::getCtrlList() const
{
ctrl_list_t controls;
- for(child_list_const_iter_t iter = mChildList.begin();
- iter != mChildList.end();
- iter++)
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- if((*iter)->isCtrl())
+ if(viewp->isCtrl())
{
- controls.push_back(static_cast<LLUICtrl*>(*iter));
+ controls.push_back(static_cast<LLUICtrl*>(viewp));
}
}
return controls;
@@ -428,6 +432,36 @@ BOOL LLView::isInEnabledChain() const
return enabled;
}
+static void buildPathname(std::ostream& out, const LLView* view)
+{
+ if (! (view && view->getParent()))
+ {
+ return; // Don't include root in the path.
+ }
+
+ buildPathname(out, view->getParent());
+
+ // Build pathname into ostream on the way back from recursion.
+ out << '/' << view->getName();
+}
+
+std::string LLView::getPathname() const
+{
+ std::ostringstream out;
+ buildPathname(out, this);
+ return out.str();
+}
+
+//static
+std::string LLView::getPathname(const LLView* view)
+{
+ if (! view)
+ {
+ return "NULL";
+ }
+ return view->getPathname();
+}
+
// virtual
BOOL LLView::canFocusChildren() const
{
@@ -574,9 +608,8 @@ void LLView::deleteAllChildren()
void LLView::setAllChildrenEnabled(BOOL b)
{
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- LLView* viewp = *child_it;
viewp->setEnabled(b);
}
}
@@ -602,9 +635,8 @@ void LLView::setVisible(BOOL visible)
// virtual
void LLView::handleVisibilityChange ( BOOL new_visibility )
{
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- LLView* viewp = *child_it;
// only views that are themselves visible will have their overall visibility affected by their ancestors
if (viewp->getVisible())
{
@@ -646,56 +678,178 @@ void LLView::onMouseLeave(S32 x, S32 y, MASK mask)
//llinfos << "Mouse left " << getName() << llendl;
}
+bool LLView::visibleAndContains(S32 local_x, S32 local_y)
+{
+ return sDrilldown(this, local_x, local_y)
+ && getVisible();
+}
+
+bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y)
+{
+ return visibleAndContains(local_x, local_y)
+ && getEnabled();
+}
+
+void LLView::logMouseEvent()
+{
+ if (sDebugMouseHandling)
+ {
+ sMouseHandlerMessage = std::string("/") + mName + sMouseHandlerMessage;
+ }
+}
+
+template <typename METHOD, typename CHARTYPE>
+LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& method,
+ CHARTYPE c, MASK mask)
+{
+ if ( getVisible() && getEnabled() )
+ {
+ BOOST_FOREACH(LLView* viewp, mChildList)
+ {
+ if ((viewp->*method)(c, mask, TRUE))
+ {
+ if (LLView::sDebugKeys)
+ {
+ llinfos << desc << " handled by " << viewp->getName() << llendl;
+ }
+ return viewp;
+ }
+ }
+ }
+ return NULL;
+}
+
+// XDATA might be MASK, or S32 clicks
+template <typename METHOD, typename XDATA>
+LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra)
+{
+ BOOST_FOREACH(LLView* viewp, mChildList)
+ {
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+
+ if (!viewp->visibleEnabledAndContains(local_x, local_y))
+ {
+ continue;
+ }
+
+ if ((viewp->*method)( local_x, local_y, extra )
+ || viewp->blockMouseEvent( local_x, local_y ))
+ {
+ viewp->logMouseEvent();
+ return viewp;
+ }
+ }
+ return NULL;
+}
LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if(!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible())
+ // Differs from childrenHandleMouseEvent() in that we want to offer
+ // tooltips even for disabled widgets.
+ if(!viewp->visibleAndContains(local_x, local_y))
{
continue;
}
- if (viewp->handleToolTip(local_x, local_y, mask) )
+ if (viewp->handleToolTip(local_x, local_y, mask)
+ || viewp->blockMouseEvent(local_x, local_y))
{
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
+ viewp->logMouseEvent();
+ return viewp;
+ }
+ }
+ return NULL;
+}
- handled_view = viewp;
- break;
+LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ // default to not accepting drag and drop, will be overridden by handler
+ *accept = ACCEPT_NO;
+
+ BOOST_FOREACH(LLView* viewp, mChildList)
+ {
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if( !viewp->visibleEnabledAndContains(local_x, local_y))
+ {
+ continue;
}
- if (viewp->blockMouseEvent(local_x, local_y))
+ // Differs from childrenHandleMouseEvent() simply in that this virtual
+ // method call diverges pretty radically from the usual (x, y, int).
+ if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
+ cargo_type,
+ cargo_data,
+ accept,
+ tooltip_msg)
+ || viewp->blockMouseEvent(local_x, local_y))
{
- handled_view = viewp;
- break;
+ return viewp;
}
}
- return handled_view;
+ return NULL;
}
+LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
+{
+ BOOST_FOREACH(LLView* viewp, mChildList)
+ {
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if(!viewp->visibleEnabledAndContains(local_x, local_y))
+ {
+ continue;
+ }
+
+ // This call differentiates this method from childrenHandleMouseEvent().
+ LLUI::sWindow->setCursor(viewp->getHoverCursor());
-LLView* LLView::childFromPoint(S32 x, S32 y)
+ if (viewp->handleHover(local_x, local_y, mask)
+ || viewp->blockMouseEvent(local_x, local_y))
+ {
+ viewp->logMouseEvent();
+ return viewp;
+ }
+ }
+ return NULL;
+}
+
+LLView* LLView::childFromPoint(S32 x, S32 y, bool recur)
{
- if (!getVisible() )
+ if (!getVisible())
return false;
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible() )
+ if (!viewp->visibleAndContains(local_x, local_y))
{
continue;
}
+ // Here we've found the first (frontmost) visible child at this level
+ // containing the specified point. Is the caller asking us to drill
+ // down and return the innermost leaf child at this point, or just the
+ // top-level child?
+ if (recur)
+ {
+ LLView* leaf(viewp->childFromPoint(local_x, local_y, recur));
+ // Maybe viewp is already a leaf LLView, or maybe it has children
+ // but this particular (x, y) point falls between them. If the
+ // recursive call returns non-NULL, great, use that; else just use
+ // viewp.
+ return leaf? leaf : viewp;
+ }
return viewp;
}
@@ -815,45 +969,6 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;
}
-LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
- BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- LLView* handled_view = NULL;
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if( !viewp->pointInView(local_x, local_y) ||
- !viewp->getVisible() ||
- !viewp->getEnabled())
- {
- continue;
- }
- if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
- cargo_type,
- cargo_data,
- accept,
- tooltip_msg))
- {
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(x, y))
- {
- *accept = ACCEPT_NO;
- handled_view = viewp;
- break;
- }
- }
- return handled_view;
-}
-
void LLView::onMouseCaptureLost()
{
}
@@ -903,391 +1018,57 @@ BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
}
-
LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
{
- LLView* handled_view = NULL;
- if (getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if (viewp->handleScrollWheel( local_x, local_y, clicks ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
-
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
-}
-
-LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
-{
- LLView* handled_view = NULL;
- if (getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if(!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if (viewp->handleHover(local_x, local_y, mask) )
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
-
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- LLUI::sWindow->setCursor(viewp->getHoverCursor());
-
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks);
}
// Called during downward traversal
LLView* LLView::childrenHandleKey(KEY key, MASK mask)
{
- LLView* handled_view = NULL;
-
- if ( getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if (viewp->handleKey(key, mask, TRUE))
- {
- if (LLView::sDebugKeys)
- {
- llinfos << "Key handled by " << viewp->getName() << llendl;
- }
- handled_view = viewp;
- break;
- }
- }
- }
-
- return handled_view;
+ return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask);
}
// Called during downward traversal
LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
{
- LLView* handled_view = NULL;
-
- if ( getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if (viewp->handleUnicodeChar(uni_char, TRUE))
- {
- if (LLView::sDebugKeys)
- {
- llinfos << "Unicode character handled by " << viewp->getName() << llendl;
- }
- handled_view = viewp;
- break;
- }
- }
- }
-
- return handled_view;
+ return childrenHandleCharEvent("Unicode character", &LLView::handleUnicodeCharWithDummyMask,
+ uni_char, MASK_NONE);
}
LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
-
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
-
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if(viewp->handleMouseDown( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if(viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleMouseDown, x, y, mask);
}
LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
-
- if (getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
-
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if (viewp->handleRightMouseDown( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
-
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleRightMouseDown, x, y, mask);
}
LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
-
- if (getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if(viewp->handleMiddleMouseDown( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleMiddleMouseDown, x, y, mask);
}
LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
-
- if (getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
-
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if (viewp->handleDoubleClick( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleDoubleClick, x, y, mask);
}
LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
- if( getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if (viewp->handleMouseUp( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
}
LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
- if( getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled() )
- {
- continue;
- }
-
- if(viewp->handleRightMouseUp( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if(viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleRightMouseUp, x, y, mask);
}
LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = NULL;
- if( getVisible() && getEnabled() )
- {
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y)
- || !viewp->getVisible()
- || !viewp->getEnabled())
- {
- continue;
- }
-
- if(viewp->handleMiddleMouseUp( local_x, local_y, mask ))
- {
- if (sDebugMouseHandling)
- {
- sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
- }
- handled_view = viewp;
- break;
- }
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
- }
- }
- return handled_view;
+ return childrenHandleMouseEvent(&LLView::handleMiddleMouseUp, x, y, mask);
}
void LLView::draw()
@@ -1460,9 +1241,8 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
mRect.mTop = getRect().mBottom + height;
// move child views according to reshape flags
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* viewp, mChildList)
{
- LLView* viewp = *child_it;
LLRect child_rect( viewp->mRect );
if (viewp->followsRight() && viewp->followsLeft())
@@ -1525,10 +1305,8 @@ LLRect LLView::calcBoundingRect()
{
LLRect local_bounding_rect = LLRect::null;
- child_list_const_iter_t child_it;
- for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* childp, mChildList)
{
- LLView* childp = *child_it;
// ignore invisible and "top" children when calculating bounding rect
// such as combobox popups
if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl())
@@ -1693,11 +1471,9 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
//richard: should we allow empty names?
//if(name.empty())
// return NULL;
- child_list_const_iter_t child_it;
// Look for direct children *first*
- for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* childp, mChildList)
{
- LLView* childp = *child_it;
llassert(childp);
if (childp->getName() == name)
{
@@ -1707,9 +1483,8 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
if (recurse)
{
// Look inside each child as well.
- for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* childp, mChildList)
{
- LLView* childp = *child_it;
llassert(childp);
LLView* viewp = childp->findChildView(name, recurse);
if ( viewp )
@@ -2850,9 +2625,9 @@ S32 LLView::notifyParent(const LLSD& info)
bool LLView::notifyChildren(const LLSD& info)
{
bool ret = false;
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ BOOST_FOREACH(LLView* childp, mChildList)
{
- ret |= (*child_it)->notifyChildren(info);
+ ret = ret || childp->notifyChildren(info);
}
return ret;
}
@@ -2872,3 +2647,24 @@ const LLViewDrawContext& LLViewDrawContext::getCurrentContext()
return *sDrawContextStack.back();
}
+
+LLSD LLView::getInfo(void)
+{
+ LLSD info;
+ addInfo(info);
+ return info;
+}
+
+void LLView::addInfo(LLSD & info)
+{
+ info["path"] = getPathname();
+ info["class"] = typeid(*this).name();
+ info["visible"] = getVisible();
+ info["visible_chain"] = isInVisibleChain();
+ info["enabled"] = getEnabled();
+ info["enabled_chain"] = isInEnabledChain();
+ info["available"] = isAvailable();
+ LLRect rect(calcScreenRect());
+ info["rect"] = LLSDMap("left", rect.mLeft)("top", rect.mTop)
+ ("right", rect.mRight)("bottom", rect.mBottom);
+}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 594a5eec6b..fe15307a5d 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -50,6 +50,8 @@
#include "llfocusmgr.h"
#include <list>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
class LLSD;
@@ -437,12 +439,15 @@ public:
/*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
/*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
- virtual LLView* childFromPoint(S32 x, S32 y);
+ virtual LLView* childFromPoint(S32 x, S32 y, bool recur=false);
// view-specific handlers
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+ std::string getPathname() const;
+ // static method handles NULL pointer too
+ static std::string getPathname(const LLView*);
template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const
{
@@ -511,11 +516,17 @@ public:
virtual S32 notify(const LLSD& info) { return 0;};
static const LLViewDrawContext& getDrawContext();
+
+ // Returns useful information about this ui widget.
+ LLSD getInfo(void);
protected:
void drawDebugRect();
void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
void drawChildren();
+ bool visibleAndContains(S32 local_x, S32 local_Y);
+ bool visibleEnabledAndContains(S32 local_x, S32 local_y);
+ void logMouseEvent();
LLView* childrenHandleKey(KEY key, MASK mask);
LLView* childrenHandleUnicodeChar(llwchar uni_char);
@@ -538,9 +549,24 @@ protected:
LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask);
ECursorType mHoverCursor;
-
+
+ virtual void addInfo(LLSD & info);
private:
+ template <typename METHOD, typename XDATA>
+ LLView* childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra);
+
+ template <typename METHOD, typename CHARTYPE>
+ LLView* childrenHandleCharEvent(const std::string& desc, const METHOD& method,
+ CHARTYPE c, MASK mask);
+
+ // adapter to blur distinction between handleKey() and handleUnicodeChar()
+ // for childrenHandleCharEvent()
+ BOOL handleUnicodeCharWithDummyMask(llwchar uni_char, MASK /* dummy */, BOOL from_parent)
+ {
+ return handleUnicodeChar(uni_char, from_parent);
+ }
+
LLView* mParentView;
child_list_t mChildList;
@@ -582,7 +608,35 @@ private:
LLView& getDefaultWidgetContainer() const;
+ // This allows special mouse-event targeting logic for testing.
+ typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc;
+ static DrilldownFunc sDrilldown;
+
public:
+ // This is the only public accessor to alter sDrilldown. This is not
+ // an accident. The intended usage pattern is like:
+ // {
+ // LLView::TemporaryDrilldownFunc scoped_func(myfunctor);
+ // // ... test with myfunctor ...
+ // } // exiting block restores original LLView::sDrilldown
+ class TemporaryDrilldownFunc: public boost::noncopyable
+ {
+ public:
+ TemporaryDrilldownFunc(const DrilldownFunc& func):
+ mOldDrilldown(sDrilldown)
+ {
+ sDrilldown = func;
+ }
+
+ ~TemporaryDrilldownFunc()
+ {
+ sDrilldown = mOldDrilldown;
+ }
+
+ private:
+ DrilldownFunc mOldDrilldown;
+ };
+
// Depth in view hierarchy during rendering
static S32 sDepth;
diff --git a/indra/llui/llviewinject.cpp b/indra/llui/llviewinject.cpp
new file mode 100644
index 0000000000..46c5839f8e
--- /dev/null
+++ b/indra/llui/llviewinject.cpp
@@ -0,0 +1,49 @@
+/**
+ * @file llviewinject.cpp
+ * @author Nat Goodspeed
+ * @date 2011-08-16
+ * @brief Implementation for llviewinject.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llviewinject.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+llview::TargetEvent::TargetEvent(LLView* view)
+{
+ // Walk up the view tree from target LLView to the root (NULL). If
+ // passed NULL, iterate 0 times.
+ for (; view; view = view->getParent())
+ {
+ // At each level, operator() is going to ask: for a particular parent
+ // LLView*, which of its children should I select? So for this view's
+ // parent, select this view.
+ mChildMap[view->getParent()] = view;
+ }
+}
+
+bool llview::TargetEvent::operator()(const LLView* view, S32 /*x*/, S32 /*y*/) const
+{
+ // We are being called to decide whether to direct an incoming mouse event
+ // to this child view. (Normal LLView processing is to check whether the
+ // incoming (x, y) is within the view.) Look up the parent to decide
+ // whether, for that parent, this is the previously-selected child.
+ ChildMap::const_iterator found(mChildMap.find(view->getParent()));
+ // If we're looking at a child whose parent isn't even in the map, never
+ // mind.
+ if (found == mChildMap.end())
+ {
+ return false;
+ }
+ // So, is this the predestined child for this parent?
+ return (view == found->second);
+}
diff --git a/indra/llui/llviewinject.h b/indra/llui/llviewinject.h
new file mode 100644
index 0000000000..0de3d155c4
--- /dev/null
+++ b/indra/llui/llviewinject.h
@@ -0,0 +1,56 @@
+/**
+ * @file llviewinject.h
+ * @author Nat Goodspeed
+ * @date 2011-08-16
+ * @brief Supplemental LLView functionality used for simulating UI events.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLVIEWINJECT_H)
+#define LL_LLVIEWINJECT_H
+
+#include "llview.h"
+#include <map>
+
+namespace llview
+{
+
+ /**
+ * TargetEvent is a callable with state, specifically intended for use as
+ * an LLView::TemporaryDrilldownFunc. Instantiate it with the desired
+ * target LLView*; pass it to a TemporaryDrilldownFunc instance;
+ * TargetEvent::operator() will then attempt to direct subsequent mouse
+ * events to the desired target LLView*. (This is an "attempt" because
+ * LLView will still balk unless the target LLView and every parent are
+ * visible and enabled.)
+ */
+ class TargetEvent
+ {
+ public:
+ /**
+ * Construct TargetEvent with the desired target LLView*. (See
+ * LLUI::resolvePath() to obtain an LLView* given a string pathname.)
+ * This sets up for operator().
+ */
+ TargetEvent(LLView* view);
+
+ /**
+ * This signature must match LLView::DrilldownFunc. When you install
+ * this TargetEvent instance using LLView::TemporaryDrilldownFunc,
+ * LLView will call this method to decide whether to propagate an
+ * incoming mouse event to the passed child LLView*.
+ */
+ bool operator()(const LLView*, S32 x, S32 y) const;
+
+ private:
+ // For a given parent LLView, identify which child to select.
+ typedef std::map<LLView*, LLView*> ChildMap;
+ ChildMap mChildMap;
+ };
+
+} // llview namespace
+
+#endif /* ! defined(LL_LLVIEWINJECT_H) */