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.master
parent
a548fd52e3
commit
f7a6ed85e4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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) */
|
||||
Loading…
Reference in New Issue