Split View Mode: Support for the 2-finger bezel scroll.

Implementing the BezelController class responsible for detecting bezel gestures.
Adding the bare skeleton of the SplitViewController class which is going to be
responsible for the split view mode.

BUG=383421

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285166 0039d316-1c4b-4281-b951-d872f2087c98
parent 39cd5ec5
......@@ -64,6 +64,10 @@
'screen/screen_manager_impl.cc',
'wm/public/window_manager.h',
'wm/public/window_manager_observer.h',
'wm/bezel_controller.cc',
'wm/bezel_controller.h',
'wm/split_view_controller.cc',
'wm/split_view_controller.h',
'wm/window_manager_impl.cc',
'wm/window_overview_mode.cc',
'wm/window_overview_mode.h',
......
// 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 "athena/wm/bezel_controller.h"
#include "ui/aura/window.h"
#include "ui/events/event_handler.h"
namespace athena {
namespace {
// Using bezel swipes, the first touch that is registered is usually within
// 5-10 pixels from the edge, but sometimes as far as 29 pixels away.
// So setting this width fairly high for now.
const float kBezelWidth = 20.0f;
const float kScrollPositionNone = -100;
bool ShouldProcessGesture(ui::EventType event_type) {
return event_type == ui::ET_GESTURE_SCROLL_UPDATE ||
event_type == ui::ET_GESTURE_SCROLL_BEGIN ||
event_type == ui::ET_GESTURE_BEGIN ||
event_type == ui::ET_GESTURE_END;
}
} // namespace
BezelController::BezelController(aura::Window* container)
: container_(container),
state_(NONE),
scroll_bezel_(BEZEL_NONE),
scroll_target_(NULL),
left_right_delegate_(NULL) {
}
float BezelController::GetDistance(const gfx::PointF& position,
BezelController::Bezel bezel) {
DCHECK(bezel == BEZEL_LEFT || bezel == BEZEL_RIGHT);
return bezel == BEZEL_LEFT
? position.x()
: position.x() - container_->GetBoundsInScreen().width();
}
void BezelController::SetState(BezelController::State state,
const gfx::PointF& scroll_position) {
if (!left_right_delegate_ || state == state_)
return;
if (state == BEZEL_SCROLLING_TWO_FINGERS) {
float delta = GetDistance(scroll_position, scroll_bezel_);
left_right_delegate_->ScrollBegin(scroll_bezel_, delta);
} else if (state_ == BEZEL_SCROLLING_TWO_FINGERS) {
left_right_delegate_->ScrollEnd();
}
state_ = state;
if (state == NONE) {
scroll_bezel_ = BEZEL_NONE;
scroll_target_ = NULL;
}
}
// Only implemented for LEFT and RIGHT bezels ATM.
BezelController::Bezel BezelController::GetBezel(const gfx::PointF& location) {
if (location.x() < kBezelWidth) {
return BEZEL_LEFT;
} else if (location.x() >
container_->GetBoundsInScreen().width() - kBezelWidth) {
return BEZEL_RIGHT;
} else {
return BEZEL_NONE;
}
}
void BezelController::OnGestureEvent(ui::GestureEvent* event) {
// TODO (mfomitchev): Currently we aren't retargetting or consuming any of the
// touch events. This means that content can prevent the generation of gesture
// events and two-finger scroll won't work. Possible solution to this problem
// is hosting our own gesture recognizer or retargetting touch events at the
// bezel.
if (!left_right_delegate_)
return;
ui::EventType type = event->type();
if (!ShouldProcessGesture(type))
return;
if (scroll_target_ && event->target() != scroll_target_)
return;
const gfx::PointF& event_location = event->location_f();
const ui::GestureEventDetails& event_details = event->details();
int num_touch_points = event_details.touch_points();
if (type == ui::ET_GESTURE_BEGIN) {
if (num_touch_points > 2) {
SetState(IGNORE_CURRENT_SCROLL,
gfx::Point(kScrollPositionNone, kScrollPositionNone));
return;
}
BezelController::Bezel event_bezel = GetBezel(event->location_f());
switch (state_) {
case NONE:
scroll_bezel_ = event_bezel;
scroll_target_ = event->target();
if (event_bezel != BEZEL_LEFT && event_bezel != BEZEL_RIGHT) {
SetState(IGNORE_CURRENT_SCROLL,
gfx::Point(kScrollPositionNone, kScrollPositionNone));
} else {
SetState(BEZEL_GESTURE_STARTED, event_location);
}
break;
case IGNORE_CURRENT_SCROLL:
break;
case BEZEL_GESTURE_STARTED:
case BEZEL_SCROLLING_ONE_FINGER:
DCHECK_EQ(num_touch_points, 2);
DCHECK(scroll_target_);
DCHECK_NE(scroll_bezel_, BEZEL_NONE);
if (event_bezel != scroll_bezel_) {
SetState(IGNORE_CURRENT_SCROLL,
gfx::Point(kScrollPositionNone, kScrollPositionNone));
return;
}
if (state_ == BEZEL_SCROLLING_ONE_FINGER)
SetState(BEZEL_SCROLLING_TWO_FINGERS, event_location);
break;
case BEZEL_SCROLLING_TWO_FINGERS:
// Should've exited above
NOTREACHED();
break;
}
} else if (type == ui::ET_GESTURE_END) {
if (state_ == NONE)
return;
CHECK(scroll_target_);
if (num_touch_points == 1) {
SetState(NONE, gfx::Point(kScrollPositionNone, kScrollPositionNone));
} else {
SetState(IGNORE_CURRENT_SCROLL,
gfx::Point(kScrollPositionNone, kScrollPositionNone));
}
} else if (type == ui::ET_GESTURE_SCROLL_BEGIN) {
DCHECK(state_ == IGNORE_CURRENT_SCROLL || state_ == BEZEL_GESTURE_STARTED);
if (state_ != BEZEL_GESTURE_STARTED)
return;
if (num_touch_points == 1) {
SetState(BEZEL_SCROLLING_ONE_FINGER, event_location);
return;
}
DCHECK_EQ(num_touch_points, 2);
SetState(BEZEL_SCROLLING_TWO_FINGERS, event_location);
if (left_right_delegate_->CanScroll())
event->SetHandled();
} else if (type == ui::ET_GESTURE_SCROLL_UPDATE) {
if (state_ != BEZEL_SCROLLING_TWO_FINGERS)
return;
float scroll_delta = GetDistance(event_location, scroll_bezel_);
left_right_delegate_->ScrollUpdate(scroll_delta);
if (left_right_delegate_->CanScroll())
event->SetHandled();
}
}
} // namespace athena
// 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 ATHENA_WM_BEZEL_CONTROLLER_H_
#define ATHENA_WM_BEZEL_CONTROLLER_H_
#include "ui/events/event_handler.h"
namespace aura {
class Window;
}
namespace gfx {
class PointF;
}
namespace ui {
class EventTarget;
}
namespace athena {
// Responsible for detecting bezel gestures and notifying the delegate(s)
// subscribed to them.
class BezelController : public ui::EventHandler {
public:
enum Bezel { BEZEL_NONE, BEZEL_LEFT, BEZEL_RIGHT, BEZEL_TOP, BEZEL_BOTTOM };
// Responsible for handling scroll gestures initiated from the bezel.
// Two touch points are need to perform the bezel scroll gesture from
// the left and right bezel.
class ScrollDelegate {
public:
virtual ~ScrollDelegate() {}
// Beginning of a bezel scroll gesture started from the |bezel|.
virtual void ScrollBegin(Bezel bezel, float delta) = 0;
// End of the current bezel scroll
virtual void ScrollEnd() = 0;
// Update of the scroll position for the currently active bezel scroll.
virtual void ScrollUpdate(float delta) = 0;
// Should return false if the delegate isn't going to react to the scroll
// events.
virtual bool CanScroll() = 0;
};
explicit BezelController(aura::Window* container);
virtual ~BezelController() {}
// Set the delegate to handle the gestures from left and right bezels.
// Two touch points are need to perform the bezel scroll gesture from
// the left and right bezel.
void set_left_right_delegate(ScrollDelegate* delegate) {
left_right_delegate_ = delegate;
}
private:
enum State {
NONE,
IGNORE_CURRENT_SCROLL,
BEZEL_GESTURE_STARTED,
BEZEL_SCROLLING_ONE_FINGER,
BEZEL_SCROLLING_TWO_FINGERS,
};
// Calculates the distance from |position| to the |bezel|.
float GetDistance(const gfx::PointF& position, Bezel bezel);
// |scroll_position| only needs to be passed in the scrolling state
void SetState(State state, const gfx::PointF& scroll_position);
// Returns the bezel corresponding to the |location| or BEZEL_NONE if the
// location is outside of the bezel area.
Bezel GetBezel(const gfx::PointF& location);
// ui::EventHandler overrides
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
aura::Window* container_;
State state_;
// The bezel where the currently active scroll was started.
Bezel scroll_bezel_;
// The target of the bezel scroll gesture. Used to filter out other gestures
// when the bezel scroll is in progress.
ui::EventTarget* scroll_target_;
// Responsible for handling gestures started from the left and right bezels.
// Not owned.
ScrollDelegate* left_right_delegate_;
DISALLOW_COPY_AND_ASSIGN(BezelController);
};
} // namespace athena
#endif // ATHENA_WM_BEZEL_CONTROLLER_H_
// 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 "athena/wm/split_view_controller.h"
#include "ui/aura/window.h"
#include "ui/events/event_handler.h"
namespace athena {
SplitViewController::SplitViewController() {
}
SplitViewController::~SplitViewController() {
}
void SplitViewController::ScrollBegin(BezelController::Bezel bezel,
float delta) {
}
void SplitViewController::ScrollEnd() {
}
void SplitViewController::ScrollUpdate(float delta) {
}
bool SplitViewController::CanScroll() {
return false;
}
} // namespace athena
// 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 ATHENA_WM_SPLIT_VIEW_CONTROLLER_H_
#define ATHENA_WM_SPLIT_VIEW_CONTROLLER_H_
#include "athena/wm/bezel_controller.h"
#include "base/memory/scoped_ptr.h"
namespace athena {
// Responsible for entering split view mode, exiting from split view mode, and
// laying out the windows in split view mode.
class SplitViewController : public BezelController::ScrollDelegate {
public:
SplitViewController();
virtual ~SplitViewController();
private:
// BezelController::ScrollDelegate overrides.
virtual void ScrollBegin(BezelController::Bezel bezel, float delta) OVERRIDE;
virtual void ScrollEnd() OVERRIDE;
virtual void ScrollUpdate(float delta) OVERRIDE;
virtual bool CanScroll() OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(SplitViewController);
};
} // namespace athena
#endif // ATHENA_WM_SPLIT_VIEW_CONTROLLER_H_
......@@ -6,7 +6,9 @@
#include "athena/input/public/accelerator_manager.h"
#include "athena/screen/public/screen_manager.h"
#include "athena/wm/bezel_controller.h"
#include "athena/wm/public/window_manager_observer.h"
#include "athena/wm/split_view_controller.h"
#include "athena/wm/window_overview_mode.h"
#include "base/logging.h"
#include "base/observer_list.h"
......@@ -94,6 +96,8 @@ class WindowManagerImpl : public WindowManager,
scoped_ptr<aura::Window> container_;
scoped_ptr<WindowOverviewMode> overview_;
scoped_ptr<BezelController> bezel_controller_;
scoped_ptr<SplitViewController> split_view_controller_;
ObserverList<WindowManagerObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(WindowManagerImpl);
......@@ -135,13 +139,19 @@ WindowManagerImpl::WindowManagerImpl() {
container_.reset(ScreenManager::Get()->CreateDefaultContainer(params));
container_->SetLayoutManager(new AthenaContainerLayoutManager);
container_->AddObserver(this);
bezel_controller_.reset(new BezelController(container_.get()));
split_view_controller_.reset(new SplitViewController());
bezel_controller_->set_left_right_delegate(split_view_controller_.get());
container_->AddPreTargetHandler(bezel_controller_.get());
instance = this;
InstallAccelerators();
}
WindowManagerImpl::~WindowManagerImpl() {
if (container_)
if (container_) {
container_->RemoveObserver(this);
container_->RemovePreTargetHandler(bezel_controller_.get());
}
container_.reset();
instance = NULL;
}
......
......@@ -302,11 +302,12 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
} // namespace
// static
scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create(
aura::Window* window,
aura::Window* container,
WindowOverviewModeDelegate* delegate) {
return scoped_ptr<WindowOverviewMode>(
new WindowOverviewModeImpl(window, delegate));
new WindowOverviewModeImpl(container, delegate));
}
} // namespace athena
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