1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/controls/slide_out_view.h" 6 7 #include "ui/compositor/layer.h" 8 #include "ui/compositor/scoped_layer_animation_settings.h" 9 #include "ui/gfx/transform.h" 10 11 namespace views { 12 13 SlideOutView::SlideOutView() 14 : gesture_scroll_amount_(0.f) { 15 // If accelerated compositing is not available, this widget tracks the 16 // OnSlideOut event but does not render any visible changes. 17 if (get_use_acceleration_when_possible()) { 18 SetPaintToLayer(true); 19 SetFillsBoundsOpaquely(false); 20 } 21 } 22 23 SlideOutView::~SlideOutView() { 24 } 25 26 void SlideOutView::OnGestureEvent(ui::GestureEvent* event) { 27 if (event->type() == ui::ET_SCROLL_FLING_START) { 28 // The threshold for the fling velocity is computed empirically. 29 // The unit is in pixels/second. 30 const float kFlingThresholdForClose = 800.f; 31 if (fabsf(event->details().velocity_x()) > kFlingThresholdForClose) { 32 SlideOutAndClose(event->details().velocity_x() < 0 ? SLIDE_LEFT : 33 SLIDE_RIGHT); 34 event->StopPropagation(); 35 return; 36 } 37 RestoreVisualState(); 38 return; 39 } 40 41 if (!event->IsScrollGestureEvent()) 42 return; 43 44 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) { 45 gesture_scroll_amount_ = 0.f; 46 } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { 47 // The scroll-update events include the incremental scroll amount. 48 gesture_scroll_amount_ += event->details().scroll_x(); 49 50 if (get_use_acceleration_when_possible()) { 51 gfx::Transform transform; 52 transform.Translate(gesture_scroll_amount_, 0.0); 53 layer()->SetTransform(transform); 54 layer()->SetOpacity( 55 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f)); 56 } 57 58 } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { 59 const float kScrollRatioForClosingNotification = 0.5f; 60 float scrolled_ratio = fabsf(gesture_scroll_amount_) / width(); 61 if (scrolled_ratio >= kScrollRatioForClosingNotification) { 62 SlideOutAndClose(gesture_scroll_amount_ < 0 ? SLIDE_LEFT : SLIDE_RIGHT); 63 event->StopPropagation(); 64 return; 65 } 66 RestoreVisualState(); 67 } 68 69 event->SetHandled(); 70 } 71 72 void SlideOutView::RestoreVisualState() { 73 if (!get_use_acceleration_when_possible()) 74 return; 75 76 // Restore the layer state. 77 const int kSwipeRestoreDurationMS = 150; 78 ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); 79 settings.SetTransitionDuration( 80 base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMS)); 81 layer()->SetTransform(gfx::Transform()); 82 layer()->SetOpacity(1.f); 83 } 84 85 void SlideOutView::SlideOutAndClose(SlideDirection direction) { 86 if (!get_use_acceleration_when_possible()) { 87 // No animations, so don't wait to fire the OnSlideOut event. 88 OnSlideOut(); 89 return; 90 } 91 const int kSwipeOutTotalDurationMS = 150; 92 int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity(); 93 ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); 94 settings.SetTransitionDuration( 95 base::TimeDelta::FromMilliseconds(swipe_out_duration)); 96 settings.AddObserver(this); 97 98 gfx::Transform transform; 99 transform.Translate(direction == SLIDE_LEFT ? -width() : width(), 0.0); 100 layer()->SetTransform(transform); 101 layer()->SetOpacity(0.f); 102 } 103 104 void SlideOutView::OnImplicitAnimationsCompleted() { 105 OnSlideOut(); 106 } 107 108 } // namespace views 109