Commit a7b4a883 authored by tdanderson's avatar tdanderson Committed by Commit bot

Support targeting for gestures in ViewTargeter

Move the gesture event targeting logic from
RootView::DispatchGestureEvent() into ViewTargeter's
overrides of FindTargetForEvent() and
FindNextBestTarget().

BUG=404224
TEST=ViewTargeterTest.ViewTargeterForGestureEvents

Review URL: https://codereview.chromium.org/481433006

Cr-Commit-Position: refs/heads/master@{#292321}
parent 672ae20a
...@@ -39,6 +39,9 @@ ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root, ...@@ -39,6 +39,9 @@ ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root,
*static_cast<ui::ScrollEvent*>(event)); *static_cast<ui::ScrollEvent*>(event));
} }
if (event->IsGestureEvent())
return FindTargetForGestureEvent(view, *(event->AsGestureEvent()));
NOTREACHED() << "ViewTargeter does not yet support this event type."; NOTREACHED() << "ViewTargeter does not yet support this event type.";
return NULL; return NULL;
} }
...@@ -46,6 +49,14 @@ ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root, ...@@ -46,6 +49,14 @@ ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root,
ui::EventTarget* ViewTargeter::FindNextBestTarget( ui::EventTarget* ViewTargeter::FindNextBestTarget(
ui::EventTarget* previous_target, ui::EventTarget* previous_target,
ui::Event* event) { ui::Event* event) {
if (!previous_target)
return NULL;
if (event->IsGestureEvent()) {
return FindNextBestTargetForGestureEvent(previous_target,
*(event->AsGestureEvent()));
}
return previous_target->GetParentTarget(); return previous_target->GetParentTarget();
} }
...@@ -75,4 +86,22 @@ View* ViewTargeter::FindTargetForScrollEvent(View* root, ...@@ -75,4 +86,22 @@ View* ViewTargeter::FindTargetForScrollEvent(View* root,
return root->GetEffectiveViewTargeter()->TargetForRect(root, rect); return root->GetEffectiveViewTargeter()->TargetForRect(root, rect);
} }
View* ViewTargeter::FindTargetForGestureEvent(View* root,
const ui::GestureEvent& gesture) {
// TODO(tdanderson): The only code path that performs targeting for gestures
// uses the ViewTargeter installed on the RootView (i.e.,
// a RootViewTargeter). Provide a default implementation
// here if we need to be able to perform gesture targeting
// starting at an arbitrary node in a Views tree.
NOTREACHED();
return NULL;
}
ui::EventTarget* ViewTargeter::FindNextBestTargetForGestureEvent(
ui::EventTarget* previous_target,
const ui::GestureEvent& gesture) {
NOTREACHED();
return NULL;
}
} // namespace views } // namespace views
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
namespace views { namespace views {
namespace internal {
class RootView;
} // namespace internal
class View; class View;
class ViewTargeterDelegate; class ViewTargeterDelegate;
...@@ -40,9 +44,19 @@ class VIEWS_EXPORT ViewTargeter : public ui::EventTargeter { ...@@ -40,9 +44,19 @@ class VIEWS_EXPORT ViewTargeter : public ui::EventTargeter {
const ui::LocatedEvent& event) const OVERRIDE; const ui::LocatedEvent& event) const OVERRIDE;
private: private:
// TODO(tdanderson): Un-friend RootView once RootView::DispatchGestureEvent()
// has been removed.
friend class internal::RootView;
View* FindTargetForKeyEvent(View* root, const ui::KeyEvent& key); View* FindTargetForKeyEvent(View* root, const ui::KeyEvent& key);
View* FindTargetForScrollEvent(View* root, const ui::ScrollEvent& scroll); View* FindTargetForScrollEvent(View* root, const ui::ScrollEvent& scroll);
virtual View* FindTargetForGestureEvent(View* root,
const ui::GestureEvent& gesture);
virtual ui::EventTarget* FindNextBestTargetForGestureEvent(
ui::EventTarget* previous_target,
const ui::GestureEvent& gesture);
// ViewTargeter does not own the |delegate_|, but |delegate_| must // ViewTargeter does not own the |delegate_|, but |delegate_| must
// outlive the targeter. // outlive the targeter.
ViewTargeterDelegate* delegate_; ViewTargeterDelegate* delegate_;
......
...@@ -76,7 +76,26 @@ class TestMaskedView : public View, public MaskedTargeterDelegate { ...@@ -76,7 +76,26 @@ class TestMaskedView : public View, public MaskedTargeterDelegate {
namespace test { namespace test {
typedef ViewsTestBase ViewTargeterTest; // TODO(tdanderson): Clean up this test suite by moving common code/state into
// ViewTargeterTest and overriding SetUp(), TearDown(), etc.
// See crbug.com/355680.
class ViewTargeterTest : public ViewsTestBase {
public:
ViewTargeterTest() {}
virtual ~ViewTargeterTest() {}
void SetGestureHandler(internal::RootView* root_view, View* handler) {
root_view->gesture_handler_ = handler;
}
void SetAllowGestureEventRetargeting(internal::RootView* root_view,
bool allow) {
root_view->allow_gesture_event_retargeting_ = allow;
}
private:
DISALLOW_COPY_AND_ASSIGN(ViewTargeterTest);
};
namespace { namespace {
...@@ -117,9 +136,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) { ...@@ -117,9 +136,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) {
internal::RootView* root_view = internal::RootView* root_view =
static_cast<internal::RootView*>(widget.GetRootView()); static_cast<internal::RootView*>(widget.GetRootView());
ViewTargeter* view_targeter = new ViewTargeter(root_view); ui::EventTargeter* targeter = root_view->targeter();
ui::EventTargeter* targeter = view_targeter;
root_view->SetEventTargeter(make_scoped_ptr(view_targeter));
ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE); ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE);
...@@ -166,9 +183,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) { ...@@ -166,9 +183,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) {
internal::RootView* root_view = internal::RootView* root_view =
static_cast<internal::RootView*>(widget.GetRootView()); static_cast<internal::RootView*>(widget.GetRootView());
ViewTargeter* view_targeter = new ViewTargeter(root_view); ui::EventTargeter* targeter = root_view->targeter();
ui::EventTargeter* targeter = view_targeter;
root_view->SetEventTargeter(make_scoped_ptr(view_targeter));
// The event falls within the bounds of |child| and |content| but not // The event falls within the bounds of |child| and |content| but not
// |grandchild|, so |child| should be the initial target for the event. // |grandchild|, so |child| should be the initial target for the event.
...@@ -208,6 +223,94 @@ TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) { ...@@ -208,6 +223,94 @@ TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) {
EXPECT_EQ(content, static_cast<View*>(current_target)); EXPECT_EQ(content, static_cast<View*>(current_target));
} }
// Convenience to make constructing a GestureEvent simpler.
class GestureEventForTest : public ui::GestureEvent {
public:
GestureEventForTest(ui::EventType type, int x, int y)
: GestureEvent(x,
y,
0,
base::TimeDelta(),
ui::GestureEventDetails(type, 0.0f, 0.0f)) {}
GestureEventForTest(ui::GestureEventDetails details, int x, int y)
: GestureEvent(x, y, 0, base::TimeDelta(), details) {}
};
// Verifies that the the functions ViewTargeter::FindTargetForEvent()
// and ViewTargeter::FindNextBestTarget() are implemented correctly
// for gesture events.
TEST_F(ViewTargeterTest, ViewTargeterForGestureEvents) {
Widget widget;
Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.bounds = gfx::Rect(0, 0, 200, 200);
widget.Init(init_params);
// The coordinates used for SetBounds() are in the parent coordinate space.
View* content = new View;
content->SetBounds(0, 0, 100, 100);
View* child = new View;
child->SetBounds(50, 50, 20, 20);
View* grandchild = new View;
grandchild->SetBounds(0, 0, 5, 5);
widget.SetContentsView(content);
content->AddChildView(child);
child->AddChildView(grandchild);
internal::RootView* root_view =
static_cast<internal::RootView*>(widget.GetRootView());
ui::EventTargeter* targeter = root_view->targeter();
// Define a GESTURE_TAP and a GESTURE_SCROLL_BEGIN.
gfx::Rect bounding_box(gfx::Point(46, 46), gfx::Size(8, 8));
gfx::Point center_point(bounding_box.CenterPoint());
ui::GestureEventDetails details(ui::ET_GESTURE_TAP, 0.0f, 0.0f);
details.set_bounding_box(bounding_box);
GestureEventForTest tap(details, center_point.x(), center_point.y());
details = ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0.0f, 0.0f);
details.set_bounding_box(bounding_box);
GestureEventForTest scroll_begin(details, center_point.x(), center_point.y());
// Assume that the view currently handling gestures has been set as
// |grandchild| by a previous gesture event. Thus subsequent gesture events
// should be initially targeted to |grandchild|, and re-targeting should
// be prohibited for all gesture event types except for GESTURE_SCROLL_BEGIN
// (which should be re-targeted to the parent of |grandchild|).
SetAllowGestureEventRetargeting(root_view, false);
SetGestureHandler(root_view, grandchild);
EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap));
EXPECT_EQ(NULL, targeter->FindNextBestTarget(grandchild, &tap));
EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin));
EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin));
// Assume that the view currently handling gestures is still set as
// |grandchild|, but this was not done by a previous gesture. Thus we are
// in the process of finding the View to which subsequent gestures will be
// dispatched, so all gesture events should be re-targeted up the ancestor
// chain.
SetAllowGestureEventRetargeting(root_view, true);
EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &tap));
EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin));
// Assume that the default gesture handler was set by the previous gesture,
// but that this handler is currently NULL. No gesture events should be
// re-targeted in this case (regardless of the view that is passed in to
// FindNextBestTarget() as the previous target).
SetGestureHandler(root_view, NULL);
SetAllowGestureEventRetargeting(root_view, false);
EXPECT_EQ(NULL, targeter->FindNextBestTarget(child, &tap));
EXPECT_EQ(NULL, targeter->FindNextBestTarget(NULL, &tap));
EXPECT_EQ(NULL, targeter->FindNextBestTarget(content, &scroll_begin));
// If no default gesture handler is currently set, targeting should be
// performed using the location of the gesture event.
SetAllowGestureEventRetargeting(root_view, true);
EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap));
EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin));
}
// Tests that the functions ViewTargeterDelegate::DoesIntersectRect() // Tests that the functions ViewTargeterDelegate::DoesIntersectRect()
// and MaskedTargeterDelegate::DoesIntersectRect() work as intended when // and MaskedTargeterDelegate::DoesIntersectRect() work as intended when
// called on views which are derived from ViewTargeterDelegate. // called on views which are derived from ViewTargeterDelegate.
...@@ -222,8 +325,7 @@ TEST_F(ViewTargeterTest, DoesIntersectRect) { ...@@ -222,8 +325,7 @@ TEST_F(ViewTargeterTest, DoesIntersectRect) {
internal::RootView* root_view = internal::RootView* root_view =
static_cast<internal::RootView*>(widget.GetRootView()); static_cast<internal::RootView*>(widget.GetRootView());
ViewTargeter* view_targeter = new ViewTargeter(root_view); ViewTargeter* view_targeter = root_view->targeter();
root_view->SetEventTargeter(make_scoped_ptr(view_targeter));
// The coordinates used for SetBounds() are in the parent coordinate space. // The coordinates used for SetBounds() are in the parent coordinate space.
TestingView v2; TestingView v2;
......
...@@ -292,6 +292,8 @@ ...@@ -292,6 +292,8 @@
'widget/drop_helper.h', 'widget/drop_helper.h',
'widget/root_view.cc', 'widget/root_view.cc',
'widget/root_view.h', 'widget/root_view.h',
'widget/root_view_targeter.cc',
'widget/root_view_targeter.h',
'widget/monitor_win.cc', 'widget/monitor_win.cc',
'widget/monitor_win.h', 'widget/monitor_win.h',
'widget/native_widget.h', 'widget/native_widget.h',
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "ui/views/focus/view_storage.h" #include "ui/views/focus/view_storage.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/view_targeter.h" #include "ui/views/view_targeter.h"
#include "ui/views/views_switches.h" #include "ui/views/widget/root_view_targeter.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
...@@ -159,6 +159,7 @@ RootView::RootView(Widget* widget) ...@@ -159,6 +159,7 @@ RootView::RootView(Widget* widget)
last_mouse_event_x_(-1), last_mouse_event_x_(-1),
last_mouse_event_y_(-1), last_mouse_event_y_(-1),
gesture_handler_(NULL), gesture_handler_(NULL),
allow_gesture_event_retargeting_(true),
pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)), pre_dispatch_handler_(new internal::PreEventDispatchHandler(this)),
post_dispatch_handler_(new internal::PostEventDispatchHandler), post_dispatch_handler_(new internal::PostEventDispatchHandler),
focus_search_(this, false, false), focus_search_(this, false, false),
...@@ -168,7 +169,7 @@ RootView::RootView(Widget* widget) ...@@ -168,7 +169,7 @@ RootView::RootView(Widget* widget)
old_dispatch_target_(NULL) { old_dispatch_target_(NULL) {
AddPreTargetHandler(pre_dispatch_handler_.get()); AddPreTargetHandler(pre_dispatch_handler_.get());
AddPostTargetHandler(post_dispatch_handler_.get()); AddPostTargetHandler(post_dispatch_handler_.get());
SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter(this))); SetEventTargeter(scoped_ptr<ViewTargeter>(new RootViewTargeter(this, this)));
} }
RootView::~RootView() { RootView::~RootView() {
...@@ -284,6 +285,11 @@ ui::EventDispatchDetails RootView::OnEventFromSource(ui::Event* event) { ...@@ -284,6 +285,11 @@ ui::EventDispatchDetails RootView::OnEventFromSource(ui::Event* event) {
return DispatchDetails(); return DispatchDetails();
} }
// If |gesture_handler_| is non-null (as a result of dispatching a previous
// gesture event), then |gesture_event| should be dispatched only to
// |gesture_handler_|.
allow_gesture_event_retargeting_ = gesture_handler_ ? false : true;
DispatchGestureEvent(gesture_event); DispatchGestureEvent(gesture_event);
return DispatchDetails(); return DispatchDetails();
} }
...@@ -679,9 +685,9 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) { ...@@ -679,9 +685,9 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
// process scroll-gesture events. In such case, we allow the event to // process scroll-gesture events. In such case, we allow the event to
// bubble up. |gesture_handler_| is changed to its nearest ancestor // bubble up. |gesture_handler_| is changed to its nearest ancestor
// that handles scroll-gesture events. // that handles scroll-gesture events.
for (gesture_handler_ = gesture_handler_->parent(); gesture_handler_ = static_cast<View*>(
gesture_handler_ && gesture_handler_ != this; targeter()->FindNextBestTarget(gesture_handler_, event));
gesture_handler_ = gesture_handler_->parent()) { while (gesture_handler_ && gesture_handler_ != this) {
ui::GestureEvent gesture_event(*event, ui::GestureEvent gesture_event(*event,
static_cast<View*>(this), static_cast<View*>(this),
gesture_handler_); gesture_handler_);
...@@ -697,6 +703,8 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) { ...@@ -697,6 +703,8 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
dispatch_details.target_destroyed) { dispatch_details.target_destroyed) {
return; return;
} }
gesture_handler_ = static_cast<View*>(
targeter()->FindNextBestTarget(gesture_handler_, event));
} }
gesture_handler_ = NULL; gesture_handler_ = NULL;
} }
...@@ -704,23 +712,10 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) { ...@@ -704,23 +712,10 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
return; return;
} }
View* gesture_handler = NULL;
if (views::switches::IsRectBasedTargetingEnabled() &&
!event->details().bounding_box().IsEmpty()) {
// TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
// once crbug.com/313392 is resolved.
gfx::Rect touch_rect(event->details().bounding_box());
touch_rect.set_origin(event->location());
touch_rect.Offset(-touch_rect.width() / 2, -touch_rect.height() / 2);
gesture_handler = GetEventHandlerForRect(touch_rect);
} else {
gesture_handler = GetEventHandlerForPoint(event->location());
}
// Walk up the tree until we find a view that wants the gesture event. // Walk up the tree until we find a view that wants the gesture event.
for (gesture_handler_ = gesture_handler; gesture_handler_ =
gesture_handler_ && (gesture_handler_ != this); static_cast<View*>(targeter()->FindTargetForEvent(this, event));
gesture_handler_ = gesture_handler_->parent()) { while (gesture_handler_ && gesture_handler_ != this) {
// Disabled views are permitted to be targets of gesture events, but // Disabled views are permitted to be targets of gesture events, but
// gesture events should never actually be dispatched to them. // gesture events should never actually be dispatched to them.
if (!gesture_handler_->enabled()) { if (!gesture_handler_->enabled()) {
...@@ -765,6 +760,8 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) { ...@@ -765,6 +760,8 @@ void RootView::DispatchGestureEvent(ui::GestureEvent* event) {
// The gesture event wasn't processed. Go up the view hierarchy and // The gesture event wasn't processed. Go up the view hierarchy and
// dispatch the gesture event. // dispatch the gesture event.
gesture_handler_ = static_cast<View*>(
targeter()->FindNextBestTarget(gesture_handler_, event));
} }
gesture_handler_ = NULL; gesture_handler_ = NULL;
......
...@@ -17,9 +17,11 @@ ...@@ -17,9 +17,11 @@
namespace views { namespace views {
namespace test { namespace test {
class ViewTargeterTest;
class WidgetTest; class WidgetTest;
} }
class RootViewTargeter;
class Widget; class Widget;
// This is a views-internal API and should not be used externally. // This is a views-internal API and should not be used externally.
...@@ -122,8 +124,10 @@ class VIEWS_EXPORT RootView : public View, ...@@ -122,8 +124,10 @@ class VIEWS_EXPORT RootView : public View,
virtual View::DragInfo* GetDragInfo() OVERRIDE; virtual View::DragInfo* GetDragInfo() OVERRIDE;
private: private:
friend class ::views::RootViewTargeter;
friend class ::views::View; friend class ::views::View;
friend class ::views::Widget; friend class ::views::Widget;
friend class ::views::test::ViewTargeterTest;
friend class ::views::test::WidgetTest; friend class ::views::test::WidgetTest;
// Input --------------------------------------------------------------------- // Input ---------------------------------------------------------------------
...@@ -168,6 +172,9 @@ class VIEWS_EXPORT RootView : public View, ...@@ -168,6 +172,9 @@ class VIEWS_EXPORT RootView : public View,
// Input --------------------------------------------------------------------- // Input ---------------------------------------------------------------------
// TODO(tdanderson): Consider moving the input-related members into
// ViewTargeter / RootViewTargeter.
// The view currently handing down - drag - up // The view currently handing down - drag - up
View* mouse_pressed_handler_; View* mouse_pressed_handler_;
...@@ -187,10 +194,13 @@ class VIEWS_EXPORT RootView : public View, ...@@ -187,10 +194,13 @@ class VIEWS_EXPORT RootView : public View,
int last_mouse_event_x_; int last_mouse_event_x_;
int last_mouse_event_y_; int last_mouse_event_y_;
// The view currently handling gesture events. When set, this handler receives // The View currently handling gesture events.
// all gesture events.
View* gesture_handler_; View* gesture_handler_;
// If true, then gesture events received from Widget are permitted to be
// re-targeted and re-dispatched while they remain unhandled.
bool allow_gesture_event_retargeting_;
scoped_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_; scoped_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_;
scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_; scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/widget/root_view_targeter.h"
#include "ui/views/view.h"
#include "ui/views/view_targeter_delegate.h"
#include "ui/views/views_switches.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
namespace views {
RootViewTargeter::RootViewTargeter(ViewTargeterDelegate* delegate,
internal::RootView* root_view)
: ViewTargeter(delegate), root_view_(root_view) {
}
RootViewTargeter::~RootViewTargeter() {
}
View* RootViewTargeter::FindTargetForGestureEvent(
View* root,
const ui::GestureEvent& gesture) {
CHECK_EQ(root, root_view_);
// Return the default gesture handler if one is already set.
if (root_view_->gesture_handler_) {
CHECK(!root_view_->allow_gesture_event_retargeting_);
return root_view_->gesture_handler_;
}
// If rect-based targeting is enabled, use the gesture's bounding box to
// determine the target. Otherwise use the center point of the gesture's
// bounding box to determine the target.
gfx::Rect rect(gesture.location(), gfx::Size(1, 1));
if (views::switches::IsRectBasedTargetingEnabled() &&
!gesture.details().bounding_box().IsEmpty()) {
// TODO(tdanderson): Pass in the bounding box to GetEventHandlerForRect()
// once crbug.com/313392 is resolved.
rect.set_size(gesture.details().bounding_box().size());
rect.Offset(-rect.width() / 2, -rect.height() / 2);
}
return root->GetEffectiveViewTargeter()->TargetForRect(root, rect);
}
ui::EventTarget* RootViewTargeter::FindNextBestTargetForGestureEvent(
ui::EventTarget* previous_target,
const ui::GestureEvent& gesture) {
// GESTURE_SCROLL_BEGIN events are always permitted to be re-targeted, even
// if |allow_gesture_event_retargeting_| is false.
if (!root_view_->allow_gesture_event_retargeting_ &&
gesture.type() != ui::ET_GESTURE_SCROLL_BEGIN) {
return NULL;
}
// If |gesture_handler_| is NULL, it is either because the view was removed
// from the tree by the previous dispatch of |gesture| or because |gesture| is
// the GESTURE_END event corresponding to the removal of the last touch
// point. In either case, no further re-targeting of |gesture| should be
// permitted.
if (!root_view_->gesture_handler_)
return NULL;
return previous_target->GetParentTarget();
}
} // namespace views
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_WIDGET_ROOT_VIEW_TARGETER_H_
#define UI_VIEWS_WIDGET_ROOT_VIEW_TARGETER_H_
#include "ui/views/view_targeter.h"
#include "ui/views/views_export.h"
namespace views {
namespace internal {
class RootView;
} // namespace internal
class View;
class ViewTargeterDelegate;
// A derived class of ViewTargeter that defines targeting logic for cases
// needing to access the members of RootView. For example, when determining the
// target of a gesture event, we need to know if a previous gesture has already
// established the View to which all subsequent gestures should be targeted.
class VIEWS_EXPORT RootViewTargeter : public ViewTargeter {
public:
RootViewTargeter(ViewTargeterDelegate* delegate,
internal::RootView* root_view);
virtual ~RootViewTargeter();
private:
// ViewTargeter:
virtual View* FindTargetForGestureEvent(
View* root,
const ui::GestureEvent& gesture) OVERRIDE;
virtual ui::EventTarget* FindNextBestTargetForGestureEvent(
ui::EventTarget* previous_target,
const ui::GestureEvent& gesture) OVERRIDE;
// A pointer to the RootView on which |this| is installed.
internal::RootView* root_view_;
DISALLOW_COPY_AND_ASSIGN(RootViewTargeter);
};
} // namespace views
#endif // UI_VIEWS_WIDGET_ROOT_VIEW_TARGETER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment