athena: Add support for fling-scroll in overview mode.
Install an animation-observer in the compositor when a fling happens, and use a FlingCurve (which implements the same fling-curve used for fling-scrolling web-pages) to progress the fling at each animation step in the compositor. BUG=398117 R=mukai@chromium.org, sky@chromium.org Review URL: https://codereview.chromium.org/436213002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287783 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
athena
ui/events
@@ -15,6 +15,7 @@
|
|||||||
'../ui/accessibility/accessibility.gyp:ax_gen',
|
'../ui/accessibility/accessibility.gyp:ax_gen',
|
||||||
'../ui/app_list/app_list.gyp:app_list',
|
'../ui/app_list/app_list.gyp:app_list',
|
||||||
'../ui/aura/aura.gyp:aura',
|
'../ui/aura/aura.gyp:aura',
|
||||||
|
'../ui/events/events.gyp:events_base',
|
||||||
'../ui/strings/ui_strings.gyp:ui_strings',
|
'../ui/strings/ui_strings.gyp:ui_strings',
|
||||||
'../ui/views/views.gyp:views',
|
'../ui/views/views.gyp:views',
|
||||||
],
|
],
|
||||||
|
@@ -14,8 +14,13 @@
|
|||||||
#include "ui/aura/window_delegate.h"
|
#include "ui/aura/window_delegate.h"
|
||||||
#include "ui/aura/window_property.h"
|
#include "ui/aura/window_property.h"
|
||||||
#include "ui/aura/window_targeter.h"
|
#include "ui/aura/window_targeter.h"
|
||||||
|
#include "ui/aura/window_tree_host.h"
|
||||||
|
#include "ui/compositor/compositor.h"
|
||||||
|
#include "ui/compositor/compositor_animation_observer.h"
|
||||||
#include "ui/compositor/scoped_layer_animation_settings.h"
|
#include "ui/compositor/scoped_layer_animation_settings.h"
|
||||||
#include "ui/events/event_handler.h"
|
#include "ui/events/event_handler.h"
|
||||||
|
#include "ui/events/gestures/fling_curve.h"
|
||||||
|
#include "ui/gfx/frame_time.h"
|
||||||
#include "ui/gfx/transform.h"
|
#include "ui/gfx/transform.h"
|
||||||
#include "ui/wm/core/shadow.h"
|
#include "ui/wm/core/shadow.h"
|
||||||
|
|
||||||
@@ -93,7 +98,8 @@ class StaticWindowTargeter : public aura::WindowTargeter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class WindowOverviewModeImpl : public WindowOverviewMode,
|
class WindowOverviewModeImpl : public WindowOverviewMode,
|
||||||
public ui::EventHandler {
|
public ui::EventHandler,
|
||||||
|
public ui::CompositorAnimationObserver {
|
||||||
public:
|
public:
|
||||||
WindowOverviewModeImpl(aura::Window* container,
|
WindowOverviewModeImpl(aura::Window* container,
|
||||||
WindowOverviewModeDelegate* delegate)
|
WindowOverviewModeDelegate* delegate)
|
||||||
@@ -113,7 +119,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
|||||||
|
|
||||||
virtual ~WindowOverviewModeImpl() {
|
virtual ~WindowOverviewModeImpl() {
|
||||||
container_->set_target_handler(container_->delegate());
|
container_->set_target_handler(container_->delegate());
|
||||||
|
RemoveAnimationObserver();
|
||||||
const aura::Window::Windows& windows = container_->children();
|
const aura::Window::Windows& windows = container_->children();
|
||||||
for (aura::Window::Windows::const_iterator iter = windows.begin();
|
for (aura::Window::Windows::const_iterator iter = windows.begin();
|
||||||
iter != windows.end();
|
iter != windows.end();
|
||||||
@@ -287,6 +293,24 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
|||||||
return container_->bounds().height() * kScrollableFraction;
|
return container_->bounds().height() * kScrollableFraction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreateFlingerFor(const ui::GestureEvent& event) {
|
||||||
|
gfx::Vector2dF velocity(event.details().velocity_x(),
|
||||||
|
event.details().velocity_y());
|
||||||
|
fling_.reset(new ui::FlingCurve(velocity, gfx::FrameTime::Now()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddAnimationObserver() {
|
||||||
|
ui::Compositor* compositor = container_->GetHost()->compositor();
|
||||||
|
if (!compositor->HasAnimationObserver(this))
|
||||||
|
compositor->AddAnimationObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveAnimationObserver() {
|
||||||
|
ui::Compositor* compositor = container_->GetHost()->compositor();
|
||||||
|
if (compositor->HasAnimationObserver(this))
|
||||||
|
compositor->RemoveAnimationObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
// ui::EventHandler:
|
// ui::EventHandler:
|
||||||
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
|
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
|
||||||
if (mouse->type() == ui::ET_MOUSE_PRESSED) {
|
if (mouse->type() == ui::ET_MOUSE_PRESSED) {
|
||||||
@@ -314,12 +338,36 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
|||||||
}
|
}
|
||||||
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
|
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
|
||||||
DoScroll(gesture->details().scroll_y());
|
DoScroll(gesture->details().scroll_y());
|
||||||
|
gesture->SetHandled();
|
||||||
|
} else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
|
||||||
|
CreateFlingerFor(*gesture);
|
||||||
|
AddAnimationObserver();
|
||||||
|
gesture->SetHandled();
|
||||||
|
} else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN && fling_) {
|
||||||
|
fling_.reset();
|
||||||
|
RemoveAnimationObserver();
|
||||||
|
gesture->SetHandled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ui::CompositorAnimationObserver:
|
||||||
|
virtual void OnAnimationStep(base::TimeTicks timestamp) OVERRIDE {
|
||||||
|
CHECK(fling_);
|
||||||
|
if (fling_->start_timestamp() > timestamp)
|
||||||
|
return;
|
||||||
|
gfx::Vector2dF scroll = fling_->GetScrollAmountAtTime(timestamp);
|
||||||
|
if (scroll.IsZero()) {
|
||||||
|
fling_.reset();
|
||||||
|
RemoveAnimationObserver();
|
||||||
|
} else {
|
||||||
|
DoScroll(scroll.y());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aura::Window* container_;
|
aura::Window* container_;
|
||||||
WindowOverviewModeDelegate* delegate_;
|
WindowOverviewModeDelegate* delegate_;
|
||||||
scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
|
scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
|
||||||
|
scoped_ptr<ui::FlingCurve> fling_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
|
DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
|
||||||
};
|
};
|
||||||
|
@@ -46,6 +46,8 @@
|
|||||||
'events_base_export.h',
|
'events_base_export.h',
|
||||||
'gesture_event_details.cc',
|
'gesture_event_details.cc',
|
||||||
'gesture_event_details.h',
|
'gesture_event_details.h',
|
||||||
|
'gestures/fling_curve.cc',
|
||||||
|
'gestures/fling_curve.h',
|
||||||
'gestures/gesture_configuration.cc',
|
'gestures/gesture_configuration.cc',
|
||||||
'gestures/gesture_configuration.h',
|
'gestures/gesture_configuration.h',
|
||||||
'keycodes/keyboard_code_conversion.cc',
|
'keycodes/keyboard_code_conversion.cc',
|
||||||
@@ -316,6 +318,7 @@
|
|||||||
'event_processor_unittest.cc',
|
'event_processor_unittest.cc',
|
||||||
'event_rewriter_unittest.cc',
|
'event_rewriter_unittest.cc',
|
||||||
'event_unittest.cc',
|
'event_unittest.cc',
|
||||||
|
'gestures/fling_curve_unittest.cc',
|
||||||
'gestures/motion_event_aura_unittest.cc',
|
'gestures/motion_event_aura_unittest.cc',
|
||||||
'gestures/velocity_calculator_unittest.cc',
|
'gestures/velocity_calculator_unittest.cc',
|
||||||
'gesture_detection/bitset_32_unittest.cc',
|
'gesture_detection/bitset_32_unittest.cc',
|
||||||
|
80
ui/events/gestures/fling_curve.cc
Normal file
80
ui/events/gestures/fling_curve.cc
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// 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/events/gestures/fling_curve.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const float kDefaultAlpha = -5.70762e+03f;
|
||||||
|
const float kDefaultBeta = 1.72e+02f;
|
||||||
|
const float kDefaultGamma = 3.7e+00f;
|
||||||
|
|
||||||
|
inline double GetPositionAtTime(double t) {
|
||||||
|
return kDefaultAlpha * exp(-kDefaultGamma * t) - kDefaultBeta * t -
|
||||||
|
kDefaultAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double GetVelocityAtTime(double t) {
|
||||||
|
return -kDefaultAlpha * kDefaultGamma * exp(-kDefaultGamma * t) -
|
||||||
|
kDefaultBeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double GetTimeAtVelocity(double v) {
|
||||||
|
return -log((v + kDefaultBeta) / (-kDefaultAlpha * kDefaultGamma)) /
|
||||||
|
kDefaultGamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
FlingCurve::FlingCurve(const gfx::Vector2dF& velocity,
|
||||||
|
base::TimeTicks start_timestamp)
|
||||||
|
: curve_duration_(GetTimeAtVelocity(0)),
|
||||||
|
start_timestamp_(start_timestamp),
|
||||||
|
time_offset_(0),
|
||||||
|
position_offset_(0) {
|
||||||
|
float max_start_velocity = std::max(fabs(velocity.x()), fabs(velocity.y()));
|
||||||
|
if (max_start_velocity > GetVelocityAtTime(0))
|
||||||
|
max_start_velocity = GetVelocityAtTime(0);
|
||||||
|
CHECK_GT(max_start_velocity, 0);
|
||||||
|
|
||||||
|
displacement_ratio_ = gfx::Vector2dF(velocity.x() / max_start_velocity,
|
||||||
|
velocity.y() / max_start_velocity);
|
||||||
|
time_offset_ = GetTimeAtVelocity(max_start_velocity);
|
||||||
|
position_offset_ = GetPositionAtTime(time_offset_);
|
||||||
|
last_timestamp_ = start_timestamp_ + base::TimeDelta::FromSecondsD(
|
||||||
|
curve_duration_ - time_offset_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlingCurve::~FlingCurve() {
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Vector2dF FlingCurve::GetScrollAmountAtTime(base::TimeTicks current) {
|
||||||
|
if (current < start_timestamp_)
|
||||||
|
return gfx::Vector2dF();
|
||||||
|
|
||||||
|
float displacement = 0;
|
||||||
|
if (current < last_timestamp_) {
|
||||||
|
float time = time_offset_ + (current - start_timestamp_).InSecondsF();
|
||||||
|
CHECK_LT(time, curve_duration_);
|
||||||
|
displacement = GetPositionAtTime(time) - position_offset_;
|
||||||
|
} else {
|
||||||
|
displacement = GetPositionAtTime(curve_duration_) - position_offset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Vector2dF scroll(displacement * displacement_ratio_.x(),
|
||||||
|
displacement * displacement_ratio_.y());
|
||||||
|
gfx::Vector2dF scroll_increment(scroll.x() - cumulative_scroll_.x(),
|
||||||
|
scroll.y() - cumulative_scroll_.y());
|
||||||
|
cumulative_scroll_ = scroll;
|
||||||
|
return scroll_increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui
|
40
ui/events/gestures/fling_curve.h
Normal file
40
ui/events/gestures/fling_curve.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// 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_EVENTS_GESTURES_FLING_CURVE_H_
|
||||||
|
#define UI_EVENTS_GESTURES_FLING_CURVE_H_
|
||||||
|
|
||||||
|
#include "base/time/time.h"
|
||||||
|
#include "ui/events/events_base_export.h"
|
||||||
|
#include "ui/gfx/geometry/point_f.h"
|
||||||
|
#include "ui/gfx/geometry/vector2d_f.h"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
// FlingCurve can be used to scroll a UI element suitable for touch screen-based
|
||||||
|
// flings.
|
||||||
|
class EVENTS_BASE_EXPORT FlingCurve {
|
||||||
|
public:
|
||||||
|
FlingCurve(const gfx::Vector2dF& velocity, base::TimeTicks start_timestamp);
|
||||||
|
~FlingCurve();
|
||||||
|
|
||||||
|
gfx::Vector2dF GetScrollAmountAtTime(base::TimeTicks current_timestamp);
|
||||||
|
base::TimeTicks start_timestamp() const { return start_timestamp_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const float curve_duration_;
|
||||||
|
const base::TimeTicks start_timestamp_;
|
||||||
|
|
||||||
|
gfx::Vector2dF displacement_ratio_;
|
||||||
|
gfx::Vector2dF cumulative_scroll_;
|
||||||
|
base::TimeTicks last_timestamp_;
|
||||||
|
float time_offset_;
|
||||||
|
float position_offset_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FlingCurve);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
|
||||||
|
#endif // UI_EVENTS_GESTURES_FLING_CURVE_H_
|
36
ui/events/gestures/fling_curve_unittest.cc
Normal file
36
ui/events/gestures/fling_curve_unittest.cc
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// 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/events/gestures/fling_curve.h"
|
||||||
|
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
#include "ui/gfx/frame_time.h"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
TEST(FlingCurveTest, Basic) {
|
||||||
|
const gfx::Vector2dF velocity(0, 5000);
|
||||||
|
base::TimeTicks now = gfx::FrameTime::Now();
|
||||||
|
FlingCurve curve(velocity, now);
|
||||||
|
|
||||||
|
gfx::Vector2dF scroll =
|
||||||
|
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromMilliseconds(20));
|
||||||
|
EXPECT_EQ(0, scroll.x());
|
||||||
|
EXPECT_NEAR(scroll.y(), 96, 1);
|
||||||
|
|
||||||
|
scroll =
|
||||||
|
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromMilliseconds(250));
|
||||||
|
EXPECT_EQ(0, scroll.x());
|
||||||
|
EXPECT_NEAR(scroll.y(), 705, 1);
|
||||||
|
|
||||||
|
scroll =
|
||||||
|
curve.GetScrollAmountAtTime(now + base::TimeDelta::FromSeconds(10));
|
||||||
|
EXPECT_EQ(0, scroll.x());
|
||||||
|
EXPECT_NEAR(scroll.y(), 392, 1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(curve.GetScrollAmountAtTime(
|
||||||
|
now + base::TimeDelta::FromSeconds(20)).IsZero());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui
|
Reference in New Issue
Block a user