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/app_list/app_list.gyp:app_list',
|
||||
'../ui/aura/aura.gyp:aura',
|
||||
'../ui/events/events.gyp:events_base',
|
||||
'../ui/strings/ui_strings.gyp:ui_strings',
|
||||
'../ui/views/views.gyp:views',
|
||||
],
|
||||
|
@ -14,8 +14,13 @@
|
||||
#include "ui/aura/window_delegate.h"
|
||||
#include "ui/aura/window_property.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/events/event_handler.h"
|
||||
#include "ui/events/gestures/fling_curve.h"
|
||||
#include "ui/gfx/frame_time.h"
|
||||
#include "ui/gfx/transform.h"
|
||||
#include "ui/wm/core/shadow.h"
|
||||
|
||||
@ -93,7 +98,8 @@ class StaticWindowTargeter : public aura::WindowTargeter {
|
||||
};
|
||||
|
||||
class WindowOverviewModeImpl : public WindowOverviewMode,
|
||||
public ui::EventHandler {
|
||||
public ui::EventHandler,
|
||||
public ui::CompositorAnimationObserver {
|
||||
public:
|
||||
WindowOverviewModeImpl(aura::Window* container,
|
||||
WindowOverviewModeDelegate* delegate)
|
||||
@ -113,7 +119,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
||||
|
||||
virtual ~WindowOverviewModeImpl() {
|
||||
container_->set_target_handler(container_->delegate());
|
||||
|
||||
RemoveAnimationObserver();
|
||||
const aura::Window::Windows& windows = container_->children();
|
||||
for (aura::Window::Windows::const_iterator iter = windows.begin();
|
||||
iter != windows.end();
|
||||
@ -287,6 +293,24 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
||||
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:
|
||||
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
|
||||
if (mouse->type() == ui::ET_MOUSE_PRESSED) {
|
||||
@ -314,12 +338,36 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
|
||||
}
|
||||
} else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
|
||||
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_;
|
||||
WindowOverviewModeDelegate* delegate_;
|
||||
scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
|
||||
scoped_ptr<ui::FlingCurve> fling_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
|
||||
};
|
||||
|
@ -46,6 +46,8 @@
|
||||
'events_base_export.h',
|
||||
'gesture_event_details.cc',
|
||||
'gesture_event_details.h',
|
||||
'gestures/fling_curve.cc',
|
||||
'gestures/fling_curve.h',
|
||||
'gestures/gesture_configuration.cc',
|
||||
'gestures/gesture_configuration.h',
|
||||
'keycodes/keyboard_code_conversion.cc',
|
||||
@ -316,6 +318,7 @@
|
||||
'event_processor_unittest.cc',
|
||||
'event_rewriter_unittest.cc',
|
||||
'event_unittest.cc',
|
||||
'gestures/fling_curve_unittest.cc',
|
||||
'gestures/motion_event_aura_unittest.cc',
|
||||
'gestures/velocity_calculator_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