diff options
| author | Nat Goodspeed <nat@lindenlab.com> | 2011-08-25 14:40:53 -0400 | 
|---|---|---|
| committer | Nat Goodspeed <nat@lindenlab.com> | 2011-08-25 14:40:53 -0400 | 
| commit | f7a6ed85e40f53e5e28868bf34ac4dbc9bb204fb (patch) | |
| tree | fde2bf8e6ec58b8dcad11ee5ca996359c98219a9 /indra/llui | |
| parent | a548fd52e3c938614f213ae7f2b1aa9cbf05b23f (diff) | |
CHOP-763: Add LLView::TemporaryDrilldownFunc to support UI injection.
Instead of unconditionally calling LLView::pointInView(),
LLView::visibleAndContains() now consults a class-static boost::function
called sDrilldown -- which is initialized to LLView::pointInView().
Introduce LLView::TemporaryDrilldownFunc, instantiated with a callable whose
signature is compatible with LLView::pointInView(). This replaces sDrilldown,
but only for the life of the TemporaryDrilldownFunc object.
Introduce llview::TargetEvent, an object intended to serve as a
TemporaryDrilldownFunc callable. Construct it with a desired target LLView*
and pass it to TemporaryDrilldownFunc. When called with each candidate child
LLView*, instead of selecting the one containing the particular (x, y) point,
it selects the one that will lead to the ultimate desired target LLView*.
Add optional 'recur' param to LLView::childFromPoint(); default is current
one-level behavior. But when you pass recur=true, it should return the
frontmost visible leaf LLView containing the passed (x, y) point.
Diffstat (limited to 'indra/llui')
| -rw-r--r-- | indra/llui/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llui/llview.cpp | 18 | ||||
| -rw-r--r-- | indra/llui/llview.h | 31 | ||||
| -rw-r--r-- | indra/llui/llviewinject.cpp | 49 | ||||
| -rw-r--r-- | indra/llui/llviewinject.h | 56 | 
5 files changed, 152 insertions, 4 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 0bbdcfd6ff..9419f24809 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -111,6 +111,7 @@ set(llui_SOURCE_FILES      llurlmatch.cpp      llurlregistry.cpp      llviewborder.cpp +    llviewinject.cpp      llviewmodel.cpp      llview.cpp      llviewquery.cpp @@ -214,6 +215,7 @@ set(llui_HEADER_FILES      llurlmatch.h      llurlregistry.h      llviewborder.h +    llviewinject.h      llviewmodel.h      llview.h      llviewquery.h diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 6d0bd4d520..56b09791a4 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -33,6 +33,7 @@  #include <cassert>  #include <boost/tokenizer.hpp>  #include <boost/foreach.hpp> +#include <boost/bind.hpp>  #include "llrender.h"  #include "llevent.h" @@ -67,6 +68,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; @@ -645,7 +648,7 @@ void LLView::onMouseLeave(S32 x, S32 y, MASK mask)  bool LLView::visibleAndContains(S32 local_x, S32 local_y)  { -	return pointInView(local_x, local_y) +	return sDrilldown(this, local_x, local_y)  		&& getVisible();  } @@ -789,10 +792,11 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)  	return NULL;  } -LLView*	LLView::childFromPoint(S32 x, S32 y) +LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)  { -	if (!getVisible()  ) +	if (!getVisible())  		return false; +  	BOOST_FOREACH(LLView* viewp, mChildList)  	{  		S32 local_x = x - viewp->getRect().mLeft; @@ -801,6 +805,14 @@ LLView*	LLView::childFromPoint(S32 x, S32 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) +		{ +			return viewp->childFromPoint(local_x, local_y, recur); +		}  		return viewp;  	} diff --git a/indra/llui/llview.h b/indra/llui/llview.h index daea46d330..67634938fb 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -50,6 +50,7 @@  #include "llfocusmgr.h"  #include <list> +#include <boost/function.hpp>  class LLSD; @@ -437,7 +438,7 @@ 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); @@ -599,7 +600,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: +		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) */ | 
