summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/views/animation/scroll_animator.cc82
-rw-r--r--ui/views/animation/scroll_animator.h63
-rw-r--r--ui/views/controls/menu/menu_controller.cc8
-rw-r--r--ui/views/controls/menu/menu_controller.h2
-rw-r--r--ui/views/controls/menu/menu_host_root_view.cc10
-rw-r--r--ui/views/controls/menu/menu_host_root_view.h3
-rw-r--r--ui/views/controls/menu/submenu_view.cc42
-rw-r--r--ui/views/controls/menu/submenu_view.h15
-rw-r--r--ui/views/views.gyp2
9 files changed, 221 insertions, 6 deletions
diff --git a/ui/views/animation/scroll_animator.cc b/ui/views/animation/scroll_animator.cc
new file mode 100644
index 0000000..1e484a3
--- /dev/null
+++ b/ui/views/animation/scroll_animator.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 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/animation/scroll_animator.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "ui/base/animation/slide_animation.h"
+
+namespace {
+const float kDefaultAcceleration = -1500.0f; // in pixels per second^2
+
+// Assumes that d0 == 0.0f
+float GetPosition(float v0, float a, float t) {
+ float max_t = -v0 / a;
+ if (t > max_t)
+ t = max_t;
+ return t * (v0 + 0.5f * a * t);
+}
+
+float GetDelta(float v0, float a, float t1, float t2) {
+ return GetPosition(v0, a, t2) - GetPosition(v0, a, t1);
+}
+
+} // namespace
+
+namespace views {
+
+ScrollAnimator::ScrollAnimator(ScrollDelegate* delegate)
+ : delegate_(delegate),
+ velocity_x_(0.0f),
+ velocity_y_(0.0f),
+ last_t_(0.0f),
+ duration_(0.0f),
+ acceleration_(kDefaultAcceleration) {
+ DCHECK(delegate);
+}
+
+ScrollAnimator::~ScrollAnimator() {
+ Stop();
+}
+
+void ScrollAnimator::Start(float velocity_x, float velocity_y) {
+ if (acceleration_ >= 0.0f)
+ acceleration_ = kDefaultAcceleration;
+ float v = std::max(fabs(velocity_x), fabs(velocity_y));
+ last_t_ = 0.0f;
+ velocity_x_ = velocity_x;
+ velocity_y_ = velocity_y;
+ duration_ = -v / acceleration_; // in seconds
+ animation_.reset(new ui::SlideAnimation(this));
+ animation_->SetSlideDuration(static_cast<int>(duration_ * 1000));
+ animation_->Show();
+}
+
+void ScrollAnimator::Stop() {
+ velocity_x_ = velocity_y_ = last_t_ = duration_ = 0.0f;
+ animation_.reset();
+}
+
+void ScrollAnimator::AnimationEnded(const ui::Animation* animation) {
+ Stop();
+}
+
+void ScrollAnimator::AnimationProgressed(const ui::Animation* animation) {
+ float t = static_cast<float>(animation->GetCurrentValue()) * duration_;
+ float a_x = velocity_x_ > 0 ? acceleration_ : -acceleration_;
+ float a_y = velocity_y_ > 0 ? acceleration_ : -acceleration_;
+ float dx = GetDelta(velocity_x_, a_x, last_t_, t);
+ float dy = GetDelta(velocity_y_, a_y, last_t_, t);
+ last_t_ = t;
+ delegate_->OnScroll(dx, dy);
+}
+
+void ScrollAnimator::AnimationCanceled(const ui::Animation* animation) {
+ Stop();
+}
+
+} // namespace views
diff --git a/ui/views/animation/scroll_animator.h b/ui/views/animation/scroll_animator.h
new file mode 100644
index 0000000..6c3eb6d
--- /dev/null
+++ b/ui/views/animation/scroll_animator.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 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_ANIMATION_SCROLL_ANIMATOR_H_
+#define UI_VIEWS_ANIMATION_SCROLL_ANIMATOR_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "ui/views/views_export.h"
+
+namespace ui {
+class SlideAnimation;
+}
+
+namespace views {
+
+class VIEWS_EXPORT ScrollDelegate {
+ public:
+ virtual void OnScroll(float dx, float dy) = 0;
+
+ protected:
+ ~ScrollDelegate() {}
+};
+
+class VIEWS_EXPORT ScrollAnimator : public ui::AnimationDelegate {
+ public:
+ // The ScrollAnimator does not own the delegate. Uses default acceleration.
+ explicit ScrollAnimator(ScrollDelegate* delegate);
+ virtual ~ScrollAnimator();
+
+ // Use this if you would prefer different acceleration than the default.
+ void set_acceleration(float acceleration) { acceleration_ = acceleration; }
+
+ void Start(float velocity_x, float velocity_y);
+ void Stop();
+
+ bool is_scrolling() const { return animation_.get(); }
+
+ private:
+ // Implementation of ui::AnimationDelegate.
+ virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
+ virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
+ virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE;
+
+ ScrollDelegate* delegate_;
+
+ float velocity_x_;
+ float velocity_y_;
+ float last_t_;
+ float duration_;
+ float acceleration_;
+
+ scoped_ptr<ui::SlideAnimation> animation_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollAnimator);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ANIMATION_SCROLL_ANIMATOR_H_
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 3408d2f..2e26a6e 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -623,6 +623,14 @@ bool MenuController::OnMouseWheel(SubmenuView* source,
}
#endif
+ui::GestureStatus MenuController::OnGestureEvent(SubmenuView* source,
+ const GestureEvent& event) {
+ MenuPart part = GetMenuPart(source, event.location());
+ if (!part.submenu)
+ return ui::GESTURE_STATUS_UNKNOWN;
+ return part.submenu->OnGestureEvent(event);
+}
+
bool MenuController::GetDropFormats(
SubmenuView* source,
int* formats,
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index ceabd3b..e467bcd 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -104,6 +104,8 @@ class VIEWS_EXPORT MenuController : public MessageLoop::Dispatcher {
#if defined(OS_LINUX)
bool OnMouseWheel(SubmenuView* source, const MouseWheelEvent& event);
#endif
+ ui::GestureStatus OnGestureEvent(SubmenuView* source,
+ const GestureEvent& event);
bool GetDropFormats(
SubmenuView* source,
diff --git a/ui/views/controls/menu/menu_host_root_view.cc b/ui/views/controls/menu/menu_host_root_view.cc
index 44ed97f..56086ea 100644
--- a/ui/views/controls/menu/menu_host_root_view.cc
+++ b/ui/views/controls/menu/menu_host_root_view.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -62,6 +62,14 @@ bool MenuHostRootView::OnMouseWheel(const MouseWheelEvent& event) {
#endif
}
+ui::GestureStatus MenuHostRootView::OnGestureEvent(const GestureEvent& event) {
+ // ChromeOS uses MenuController to forward events like other
+ // mouse events.
+ if (!GetMenuController())
+ return ui::GESTURE_STATUS_UNKNOWN;
+ return GetMenuController()->OnGestureEvent(submenu_, event);
+}
+
MenuController* MenuHostRootView::GetMenuController() {
return submenu_ ? submenu_->GetMenuItem()->GetMenuController() : NULL;
}
diff --git a/ui/views/controls/menu/menu_host_root_view.h b/ui/views/controls/menu/menu_host_root_view.h
index 15f61bb..1af721c 100644
--- a/ui/views/controls/menu/menu_host_root_view.h
+++ b/ui/views/controls/menu/menu_host_root_view.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -31,6 +31,7 @@ class MenuHostRootView : public internal::RootView {
virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
virtual void OnMouseMoved(const MouseEvent& event) OVERRIDE;
virtual bool OnMouseWheel(const MouseWheelEvent& event) OVERRIDE;
+ virtual ui::GestureStatus OnGestureEvent(const GestureEvent& event) OVERRIDE;
private:
// Returns the MenuController for this MenuHostRootView.
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 37f199b..3839ac7 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -1,9 +1,12 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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/controls/menu/submenu_view.h"
+#include <algorithm>
+
+#include "base/compiler_specific.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -39,7 +42,9 @@ SubmenuView::SubmenuView(MenuItemView* parent)
scroll_view_container_(NULL),
max_accelerator_width_(0),
minimum_preferred_width_(0),
- resize_open_menu_(false) {
+ resize_open_menu_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ scroll_animator_(new ScrollAnimator(this))) {
DCHECK(parent);
// We'll delete ourselves, otherwise the ScrollView would delete us on close.
set_parent_owned(false);
@@ -242,6 +247,26 @@ bool SubmenuView::OnMouseWheel(const MouseWheelEvent& e) {
return true;
}
+ui::GestureStatus SubmenuView::OnGestureEvent(const GestureEvent& e) {
+ ui::GestureStatus to_return = ui::GESTURE_STATUS_CONSUMED;
+ switch (e.type()) {
+ case ui::ET_GESTURE_SCROLL_BEGIN:
+ scroll_animator_->Stop();
+ break;
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ OnScroll(0, e.delta_y());
+ break;
+ case ui::ET_GESTURE_SCROLL_END:
+ if (e.delta_y() != 0.0f)
+ scroll_animator_->Start(0, e.delta_y());
+ break;
+ default:
+ to_return = ui::GESTURE_STATUS_UNKNOWN;
+ break;
+ }
+ return to_return;
+}
+
bool SubmenuView::IsShowing() {
return host_ && host_->IsMenuHostVisible();
}
@@ -395,4 +420,17 @@ gfx::Rect SubmenuView::CalculateDropIndicatorBounds(
}
}
+void SubmenuView::OnScroll(float dx, float dy) {
+ const gfx::Rect& vis_bounds = GetVisibleBounds();
+ const gfx::Rect& full_bounds = bounds();
+ int x = vis_bounds.x();
+ int y = vis_bounds.y() - static_cast<int>(dy);
+ // clamp y to [0, full_height - vis_height)
+ y = std::max(y, 0);
+ y = std::min(y, full_bounds.height() - vis_bounds.height() - 1);
+ gfx::Rect new_vis_bounds(x, y, vis_bounds.width(), vis_bounds.height());
+ if (new_vis_bounds != vis_bounds)
+ ScrollRectToVisible(new_vis_bounds);
+}
+
} // namespace views
diff --git a/ui/views/controls/menu/submenu_view.h b/ui/views/controls/menu/submenu_view.h
index d4d0497..40981a2 100644
--- a/ui/views/controls/menu/submenu_view.h
+++ b/ui/views/controls/menu/submenu_view.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -9,6 +9,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "ui/views/animation/scroll_animator.h"
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/view.h"
@@ -33,7 +34,8 @@ class MenuScrollViewContainer;
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
-class VIEWS_EXPORT SubmenuView : public View {
+class VIEWS_EXPORT SubmenuView : public View,
+ public ScrollDelegate {
public:
// The submenu's class name.
static const char kViewClassName[];
@@ -74,6 +76,9 @@ class VIEWS_EXPORT SubmenuView : public View {
// Scrolls on menu item boundaries.
virtual bool OnMouseWheel(const MouseWheelEvent& e) OVERRIDE;
+ // Scrolls on menu item boundaries.
+ virtual ui::GestureStatus OnGestureEvent(const GestureEvent& e) OVERRIDE;
+
// Returns true if the menu is showing.
bool IsShowing();
@@ -170,6 +175,9 @@ class VIEWS_EXPORT SubmenuView : public View {
gfx::Rect CalculateDropIndicatorBounds(MenuItemView* item,
MenuDelegate::DropPosition position);
+ // Implementation of ScrollDelegate
+ virtual void OnScroll(float dx, float dy) OVERRIDE;
+
// Parent menu item.
MenuItemView* parent_menu_item_;
@@ -196,6 +204,9 @@ class VIEWS_EXPORT SubmenuView : public View {
// Reposition open menu when contained views change size.
bool resize_open_menu_;
+ // The submenu's scroll animator
+ scoped_ptr<ScrollAnimator> scroll_animator_;
+
DISALLOW_COPY_AND_ASSIGN(SubmenuView);
};
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 7768c60..409d773 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -51,6 +51,8 @@
'accessible_pane_view.h',
'animation/bounds_animator.cc',
'animation/bounds_animator.h',
+ 'animation/scroll_animator.cc',
+ 'animation/scroll_animator.h',
'background.cc',
'background.h',
'border.cc',