summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorrjkroege@google.com <rjkroege@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 14:06:10 +0000
committerrjkroege@google.com <rjkroege@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 14:06:10 +0000
commitad84c8f53a2973e4d752de9fe8c52e3268a867e1 (patch)
treecb330cc04d3b0dd3a93eca847e367d794310653c /views
parent2229e8264e786f5265bf5c0a6265d5aa3dfaf713 (diff)
downloadchromium_src-ad84c8f53a2973e4d752de9fe8c52e3268a867e1.zip
chromium_src-ad84c8f53a2973e4d752de9fe8c52e3268a867e1.tar.gz
chromium_src-ad84c8f53a2973e4d752de9fe8c52e3268a867e1.tar.bz2
Added entry points to view/View to dispatch and process TouchEvents.
This change is part of a series of changes to bring TouchEvent processing to views. BUG=na TESTED=compiled with and without touchui Review URL: http://codereview.chromium.org/3192002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58823 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/event.h3
-rw-r--r--views/touchui/gesture_manager.cc62
-rw-r--r--views/touchui/gesture_manager.h54
-rw-r--r--views/view.cc16
-rw-r--r--views/view.h15
-rw-r--r--views/view_unittest.cc158
-rw-r--r--views/views.gyp8
-rw-r--r--views/widget/root_view.cc65
-rw-r--r--views/widget/root_view.h29
9 files changed, 401 insertions, 9 deletions
diff --git a/views/event.h b/views/event.h
index 14a6af7..f02bd1b 100644
--- a/views/event.h
+++ b/views/event.h
@@ -290,7 +290,8 @@ class TouchEvent : public LocatedEvent {
}
private:
- // The identity (typically finger) of the touch.
+ // The identity (typically finger) of the touch starting at 0 and incrementing
+ // for each separable additional touch that the hardware can detect.
const int touch_id_;
DISALLOW_COPY_AND_ASSIGN(TouchEvent);
diff --git a/views/touchui/gesture_manager.cc b/views/touchui/gesture_manager.cc
new file mode 100644
index 0000000..7123519
--- /dev/null
+++ b/views/touchui/gesture_manager.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2010 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 "views/touchui/gesture_manager.h"
+#ifndef NDEBUG
+#include <iostream>
+#endif
+
+#include "base/logging.h"
+#include "views/event.h"
+#include "views/view.h"
+
+namespace views {
+
+GestureManager::~GestureManager() {
+}
+
+GestureManager* GestureManager::Get() {
+ return Singleton<GestureManager>::get();
+}
+
+bool GestureManager::ProcessTouchEventForGesture(const TouchEvent& event,
+ View* source,
+ bool previouslyHandled) {
+ // TODO(rjkroege): A realistic version of the GestureManager will
+ // appear in a subsequent CL. This interim version permits verifying that the
+ // event distirbution code works by turning all touch inputs into
+ // mouse approximations.
+ bool handled = false;
+ if (event.GetType() == Event::ET_TOUCH_PRESSED) {
+ DLOG(INFO) << "GestureManager::ProcessTouchEventForGesture: " <<
+ "TouchPressed\n";
+ MouseEvent mouse_event(Event::ET_MOUSE_PRESSED, event.x(), event.y(),
+ event.GetFlags());
+ source->OnMousePressed(mouse_event);
+ handled = true;
+ } else if (event.GetType() == Event::ET_TOUCH_RELEASED) {
+ DLOG(INFO) << "GestureManager::ProcessTouchEventForGesture: " <<
+ "TouchReleased\n";
+ MouseEvent mouse_event(Event::ET_MOUSE_RELEASED, event.x(), event.y(),
+ event.GetFlags());
+ source->OnMouseReleased(mouse_event, false);
+ handled = true;
+ } else if (event.GetType() == Event::ET_TOUCH_MOVED) {
+ DLOG(INFO) << "GestureManager::ProcessTouchEventForGesture: " <<
+ "TouchMotion\n";
+ MouseEvent mouse_event(Event::ET_MOUSE_DRAGGED, event.x(), event.y(),
+ event.GetFlags());
+ source->OnMouseDragged(mouse_event);
+ handled = true;
+ } else {
+ DLOG(INFO) << "GestureManager::ProcessTouchEventForGesture: " <<
+ "unhandled event\n";
+ }
+ return handled;
+}
+
+GestureManager::GestureManager() {
+}
+
+} // namespace views
diff --git a/views/touchui/gesture_manager.h b/views/touchui/gesture_manager.h
new file mode 100644
index 0000000..2b905d3
--- /dev/null
+++ b/views/touchui/gesture_manager.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2010 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 VIEWS_TOUCHUI_GESTURE_MANAGER_H_
+#define VIEWS_TOUCHUI_GESTURE_MANAGER_H_
+#pragma once
+
+#include "base/singleton.h"
+
+namespace views {
+class View;
+class TouchEvent;
+
+
+// A GestureManager singleton detects gestures occurring in the
+// incoming feed of touch events across all of the RootViews in
+// the system. In response to a given touch event, the GestureManager
+// updates its internal state and optionally dispatches synthetic
+// events to the invoking view.
+//
+class GestureManager {
+ public:
+ virtual ~GestureManager();
+
+ static GestureManager* Get();
+
+ // Invoked for each touch event that could contribute to the current gesture.
+ // Takes the event and the View that originated it and which will also
+ // be the target of any generated synthetic event. Finally, handled
+ // specifies if the event was actually handled explicitly by a view so that
+ // GestureManager state can correctly reflect events that are handled
+ // already.
+ // Returns true if the event resulted in firing a synthetic event.
+ virtual bool ProcessTouchEventForGesture(const TouchEvent& event,
+ View* source,
+ bool previouslyHandled);
+
+ // TODO(rjkroege): Write the remainder of this class.
+ // It will appear in a subsequent CL.
+
+ protected:
+ GestureManager();
+
+ private:
+ friend struct DefaultSingletonTraits<GestureManager>;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureManager);
+};
+
+
+} // namespace views
+
+#endif // VIEWS_TOUCHUI_GESTURE_MANAGER_H_
diff --git a/views/view.cc b/views/view.cc
index 04dbc40..a4e7aa0 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -536,6 +536,15 @@ void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
// WARNING: we may have been deleted.
}
+#if defined(TOUCH_UI)
+bool View::ProcessTouchEvent(const TouchEvent& e) {
+ // TODO(rjkroege): Implement a grab scheme similar to as
+ // as is found in MousePressed.
+ const bool result = OnTouchEvent(e);
+ return result;
+}
+#endif
+
void View::AddChildView(View* v) {
AddChildView(static_cast<int>(child_views_.size()), v);
}
@@ -1289,6 +1298,13 @@ void View::OnMouseEntered(const MouseEvent& e) {
void View::OnMouseExited(const MouseEvent& e) {
}
+#if defined(TOUCH_UI)
+bool View::OnTouchEvent(const TouchEvent& event) {
+ DLOG(INFO) << "visited the OnTouchEvent";
+ return false;
+}
+#endif
+
void View::SetMouseHandler(View *new_mouse_handler) {
// It is valid for new_mouse_handler to be NULL
if (parent_)
diff --git a/views/view.h b/views/view.h
index 293c5c7..2504667 100644
--- a/views/view.h
+++ b/views/view.h
@@ -705,6 +705,12 @@ class View : public AcceleratorTarget {
// Default implementation does nothing. Override as needed.
virtual void OnMouseExited(const MouseEvent& event);
+#if defined(TOUCH_UI)
+ // This method is invoked for each touch event. Default implementation
+ // does nothing. Override as needed.
+ virtual bool OnTouchEvent(const TouchEvent& event);
+#endif
+
// Set the MouseHandler for a drag session.
//
// A drag session is a stream of mouse events starting
@@ -712,7 +718,7 @@ class View : public AcceleratorTarget {
// events and finishing with a MouseReleased event.
//
// This method should be only invoked while processing a
- // MouseDragged or MouseReleased event.
+ // MouseDragged or MousePressed event.
//
// All further mouse dragged and mouse up events will be sent
// the MouseHandler, even if it is reparented to another window.
@@ -1160,6 +1166,13 @@ class View : public AcceleratorTarget {
bool ProcessMouseDragged(const MouseEvent& e, DragInfo* drop_info);
void ProcessMouseReleased(const MouseEvent& e, bool canceled);
+#if defined(TOUCH_UI)
+ // RootView will invoke this with incoming TouchEvents. Returns the
+ // the result of OnTouchEvent: true if the event was handled by the
+ // callee.
+ bool ProcessTouchEvent(const TouchEvent& e);
+#endif
+
// Starts a drag and drop operation originating from this view. This invokes
// WriteDragData to write the data and GetDragOperations to determine the
// supported drag operations. When done, OnDragDone is invoked.
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
index a44ce6f..886f1f2 100644
--- a/views/view_unittest.cc
+++ b/views/view_unittest.cc
@@ -14,9 +14,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "views/background.h"
#include "views/controls/button/checkbox.h"
-#if defined(OS_WIN)
-#include "views/controls/button/native_button_win.h"
-#endif
#include "views/controls/native/native_view_host.h"
#include "views/controls/scroll_view.h"
#include "views/controls/textfield/textfield.h"
@@ -26,14 +23,19 @@
#include "views/view.h"
#include "views/views_delegate.h"
#include "views/widget/root_view.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+
#if defined(OS_WIN)
#include "views/widget/widget_win.h"
+#include "views/controls/button/native_button_win.h"
#elif defined(OS_LINUX)
#include "views/widget/widget_gtk.h"
#include "views/window/window_gtk.h"
#endif
-#include "views/window/dialog_delegate.h"
-#include "views/window/window.h"
+#if defined(TOUCH_UI)
+#include "views/touchui/gesture_manager.h"
+#endif
using namespace views;
@@ -155,6 +157,10 @@ class TestView : public View {
child_removed_ = false;
last_mouse_event_type_ = 0;
location_.SetPoint(0, 0);
+#if defined(TOUCH_UI)
+ last_touch_event_type_ = 0;
+ last_touch_event_was_handled_ = false;
+#endif
last_clip_.setEmpty();
accelerator_count_map_.clear();
}
@@ -165,6 +171,9 @@ class TestView : public View {
virtual bool OnMousePressed(const MouseEvent& event);
virtual bool OnMouseDragged(const MouseEvent& event);
virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+#if defined(TOUCH_UI)
+ virtual bool OnTouchEvent(const TouchEvent& event);
+#endif
virtual void Paint(gfx::Canvas* canvas);
virtual bool AcceleratorPressed(const Accelerator& accelerator);
@@ -183,6 +192,12 @@ class TestView : public View {
int last_mouse_event_type_;
gfx::Point location_;
+#if defined(TOUCH_UI)
+ // TouchEvent
+ int last_touch_event_type_;
+ bool last_touch_event_was_handled_;
+#endif
+
// Painting
SkRect last_clip_;
@@ -190,6 +205,31 @@ class TestView : public View {
std::map<Accelerator, int> accelerator_count_map_;
};
+#if defined(TOUCH_UI)
+// Mock instance of the GestureManager for testing.
+class MockGestureManager : public GestureManager {
+ public:
+ // Reset all test state
+ void Reset() {
+ last_touch_event_ = 0;
+ last_view_ = NULL;
+ previously_handled_flag_ = false;
+ }
+
+ bool previously_handled_flag_;
+ bool ProcessTouchEventForGesture(const TouchEvent& event,
+ View* source,
+ bool previouslyHandled);
+ MockGestureManager();
+
+ int last_touch_event_;
+ View *last_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockGestureManager);
+};
+
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// DidChangeBounds
////////////////////////////////////////////////////////////////////////////////
@@ -383,6 +423,114 @@ TEST_F(ViewTest, MouseEvent) {
window->CloseNow();
}
+#if defined(TOUCH_UI)
+////////////////////////////////////////////////////////////////////////////////
+// TouchEvent
+////////////////////////////////////////////////////////////////////////////////
+bool MockGestureManager::ProcessTouchEventForGesture(
+ const TouchEvent& event,
+ View* source,
+ bool previouslyHandled) {
+ last_touch_event_ = event.GetType();
+ last_view_ = source;
+ previously_handled_flag_ = previouslyHandled;
+ return true;
+}
+
+MockGestureManager::MockGestureManager() {
+}
+
+bool TestView::OnTouchEvent(const TouchEvent& event) {
+ last_touch_event_type_ = event.GetType();
+ location_.SetPoint(event.x(), event.y());
+ return last_touch_event_was_handled_;
+}
+
+TEST_F(ViewTest, TouchEvent) {
+ MockGestureManager* gm = new MockGestureManager();
+
+ TestView* v1 = new TestView();
+ v1->SetBounds(0, 0, 300, 300);
+
+ TestView* v2 = new TestView();
+ v2->SetBounds(100, 100, 100, 100);
+
+ scoped_ptr<Widget> window(CreateWidget());
+#if defined(OS_WIN)
+ // This code would need to be here when we support
+ // touch on windows?
+ WidgetWin* window_win = static_cast<WidgetWin*>(window.get());
+ window_win->set_delete_on_destroy(false);
+ window_win->set_window_style(WS_OVERLAPPEDWINDOW);
+ window_win->Init(NULL, gfx::Rect(50, 50, 650, 650));
+#endif
+ RootView* root = window->GetRootView();
+
+ root->AddChildView(v1);
+ root->SetGestureManager(gm);
+ v1->AddChildView(v2);
+
+ v1->Reset();
+ v2->Reset();
+ gm->Reset();
+
+ TouchEvent pressed(Event::ET_TOUCH_PRESSED,
+ 110,
+ 120,
+ 0, /* no flags */
+ 0 /* first finger touch */);
+ v2->last_touch_event_was_handled_ = true;
+ root->OnTouchEvent(pressed);
+
+ EXPECT_EQ(v2->last_touch_event_type_, Event::ET_TOUCH_PRESSED);
+ EXPECT_EQ(v2->location_.x(), 10);
+ EXPECT_EQ(v2->location_.y(), 20);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm->last_touch_event_, Event::ET_TOUCH_PRESSED);
+ EXPECT_EQ(gm->last_view_, root);
+ EXPECT_EQ(gm->previously_handled_flag_, true);
+
+ // Drag event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ TouchEvent dragged(Event::ET_TOUCH_MOVED,
+ 50,
+ 40,
+ 0, /* no flags */
+ 0 /* first finger touch */);
+ root->OnTouchEvent(dragged);
+ EXPECT_EQ(v2->last_touch_event_type_, Event::ET_TOUCH_MOVED);
+ EXPECT_EQ(v2->location_.x(), -50);
+ EXPECT_EQ(v2->location_.y(), -60);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm->last_touch_event_, Event::ET_TOUCH_MOVED);
+ EXPECT_EQ(gm->last_view_, root);
+ EXPECT_EQ(gm->previously_handled_flag_, true);
+
+ // Releasted event out of bounds. Should still go to v2
+ v1->Reset();
+ v2->Reset();
+ TouchEvent released(Event::ET_TOUCH_RELEASED, 0, 0, 0, 0 /* first finger */);
+ v2->last_touch_event_was_handled_ = true;
+ root->OnTouchEvent(released);
+ EXPECT_EQ(v2->last_touch_event_type_, Event::ET_TOUCH_RELEASED);
+ EXPECT_EQ(v2->location_.x(), -100);
+ EXPECT_EQ(v2->location_.y(), -100);
+ // Make sure v1 did not receive the event
+ EXPECT_EQ(v1->last_touch_event_type_, 0);
+
+ EXPECT_EQ(gm->last_touch_event_, Event::ET_TOUCH_RELEASED);
+ EXPECT_EQ(gm->last_view_, root);
+ EXPECT_EQ(gm->previously_handled_flag_, true);
+
+ window->CloseNow();
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// Painting
////////////////////////////////////////////////////////////////////////////////
diff --git a/views/views.gyp b/views/views.gyp
index 8c437a6..ef8ba07 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -31,6 +31,9 @@
['include', '/win/'],
['include', '/win_[^/]*\\.cc$'],
]}],
+ ['touchui==0', {'sources/': [
+ ['exclude', 'touchui/'],
+ ]}],
],
},
'targets': [
@@ -260,6 +263,8 @@
'screen_gtk.cc',
'screen_win.cc',
'standard_layout.h',
+ 'touchui/gesture_manager.h',
+ 'touchui/gesture_manager.cc',
'view.cc',
'view.h',
'view_constants.cc',
@@ -359,6 +364,9 @@
'widget/widget_win.cc',
],
}],
+ ['touchui==1', {
+ 'defines': ['TOUCH_UI=1'],
+ }],
['OS=="win"', {
'sources!': [
'controls/slider/slider.cc',
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
index 20464cc..8b8f896 100644
--- a/views/widget/root_view.cc
+++ b/views/widget/root_view.cc
@@ -16,6 +16,10 @@
#include "views/widget/widget.h"
#include "views/window/window.h"
+#if defined(TOUCH_UI)
+#include "views/touchui/gesture_manager.h"
+#endif
+
#if defined(OS_LINUX)
#include "views/widget/widget_gtk.h"
#endif // defined(OS_LINUX)
@@ -76,6 +80,11 @@ RootView::RootView(Widget* widget)
focus_traversable_parent_(NULL),
focus_traversable_parent_view_(NULL),
drag_view_(NULL)
+#if defined(TOUCH_UI)
+ ,
+ gesture_manager_(GestureManager::Get()),
+ touch_pressed_handler_(NULL)
+#endif
#ifndef NDEBUG
,
is_processing_paint_(false)
@@ -289,6 +298,62 @@ void RootView::SetFocusOnMousePressed(bool f) {
focus_on_mouse_pressed_ = f;
}
+#if defined(TOUCH_UI)
+bool RootView::OnTouchEvent(const TouchEvent& e) {
+ // If touch_pressed_handler_ is non null, we are currently processing
+ // a touch down on the screen situation. In that case we send the
+ // event to touch_pressed_handler_
+
+ if (touch_pressed_handler_) {
+ TouchEvent touch_event(e, this, touch_pressed_handler_);
+ touch_pressed_handler_->ProcessTouchEvent(touch_event);
+ gesture_manager_->ProcessTouchEventForGesture(e, this, true);
+ return true;
+ }
+
+ bool handled = false;
+ // Walk up the tree until we find a view that wants the touch event.
+ for (touch_pressed_handler_ = GetViewForPoint(e.location());
+ touch_pressed_handler_ && (touch_pressed_handler_ != this);
+ touch_pressed_handler_ = touch_pressed_handler_->GetParent()) {
+ if (!touch_pressed_handler_->IsEnabled()) {
+ // Disabled views eat events but are treated as not handled by the
+ // the GestureManager.
+ handled = false;
+ break;
+ }
+
+ // See if this view wants to handle the touch
+ TouchEvent touch_event(e, this, touch_pressed_handler_);
+ handled = touch_pressed_handler_->ProcessTouchEvent(touch_event);
+
+ // The view could have removed itself from the tree when handling
+ // OnTouchEvent(). So handle as per OnMousePressed. NB: we
+ // assume that the RootView itself cannot be so removed.
+ //
+ // NOTE: Don't return true here, because we don't want the frame to
+ // forward future events to us when there's no handler.
+ if (!touch_pressed_handler_)
+ break;
+
+ // If the view handled the event, leave touch_pressed_handler_ set and
+ // return true, which will cause subsequent drag/release events to get
+ // forwarded to that view.
+ if (handled) {
+ gesture_manager_->ProcessTouchEventForGesture(e, this, handled);
+ return true;
+ }
+ }
+
+ // Reset touch_pressed_handler_ to indicate that no processing is occurring.
+ touch_pressed_handler_ = NULL;
+
+ // Give the touch event to the gesture manager.
+ gesture_manager_->ProcessTouchEventForGesture(e, this, handled);
+ return handled;
+}
+#endif
+
bool RootView::OnMousePressed(const MouseEvent& e) {
// This function does not normally handle non-client messages except for
// non-client double-clicks. Actually, all double-clicks are special as the
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
index c749bc8..91c1672 100644
--- a/views/widget/root_view.h
+++ b/views/widget/root_view.h
@@ -22,6 +22,10 @@ namespace views {
class PaintTask;
class Widget;
+#if defined(TOUCH_UI)
+class GestureManager;
+#endif
+
/////////////////////////////////////////////////////////////////////////////
//
// RootView class
@@ -93,6 +97,9 @@ class RootView : public View,
virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
virtual void OnMouseMoved(const MouseEvent& e);
virtual void SetMouseHandler(View* new_mouse_handler);
+#if defined(TOUCH_UI)
+ virtual bool OnTouchEvent(const TouchEvent& e);
+#endif
// Invoked By the Widget if the mouse drag is interrupted by
// the system. Invokes OnMouseReleased with a value of true for canceled.
@@ -175,6 +182,12 @@ class RootView : public View,
// Accessibility accessors/mutators, overridden from View.
virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+#if defined(TOUCH_UI) && defined(UNIT_TEST)
+ // For unit testing purposes, we use this method to set a mock
+ // GestureManager
+ void SetGestureManager(GestureManager* g) { gesture_manager_ = g; }
+#endif
+
protected:
// Overridden to properly reset our event propagation member
@@ -189,6 +202,12 @@ class RootView : public View,
friend class View;
friend class PaintTask;
+#if defined(TOUCH_UI)
+ // Required so the GestureManager can call the Process* entry points
+ // with synthetic events as necessary.
+ friend class GestureManager;
+#endif
+
RootView();
// Convert a point to our current mouse handler. Returns false if the
@@ -321,14 +340,20 @@ class RootView : public View,
// view the drag started from.
View* drag_view_;
+#if defined(TOUCH_UI)
+ // The gesture_manager_ for this.
+ GestureManager* gesture_manager_;
+
+ // The view currently handling touch events.
+ View *touch_pressed_handler_;
+#endif
+
#ifndef NDEBUG
// True if we're currently processing paint.
bool is_processing_paint_;
#endif
-
DISALLOW_COPY_AND_ASSIGN(RootView);
};
-
} // namespace views
#endif // VIEWS_WIDGET_ROOT_VIEW_H_