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 SlideOutView()13SlideOutView::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 SetPaintToLayer(true); 18 SetFillsBoundsOpaquely(false); 19 } 20 ~SlideOutView()21SlideOutView::~SlideOutView() { 22 } 23 OnGestureEvent(ui::GestureEvent * event)24void SlideOutView::OnGestureEvent(ui::GestureEvent* event) { 25 if (event->type() == ui::ET_SCROLL_FLING_START) { 26 // The threshold for the fling velocity is computed empirically. 27 // The unit is in pixels/second. 28 const float kFlingThresholdForClose = 800.f; 29 if (fabsf(event->details().velocity_x()) > kFlingThresholdForClose) { 30 SlideOutAndClose(event->details().velocity_x() < 0 ? SLIDE_LEFT : 31 SLIDE_RIGHT); 32 event->StopPropagation(); 33 return; 34 } 35 RestoreVisualState(); 36 return; 37 } 38 39 if (!event->IsScrollGestureEvent()) 40 return; 41 42 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) { 43 gesture_scroll_amount_ = 0.f; 44 } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { 45 // The scroll-update events include the incremental scroll amount. 46 gesture_scroll_amount_ += event->details().scroll_x(); 47 48 gfx::Transform transform; 49 transform.Translate(gesture_scroll_amount_, 0.0); 50 layer()->SetTransform(transform); 51 layer()->SetOpacity( 52 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f)); 53 54 } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { 55 const float kScrollRatioForClosingNotification = 0.5f; 56 float scrolled_ratio = fabsf(gesture_scroll_amount_) / width(); 57 if (scrolled_ratio >= kScrollRatioForClosingNotification) { 58 SlideOutAndClose(gesture_scroll_amount_ < 0 ? SLIDE_LEFT : SLIDE_RIGHT); 59 event->StopPropagation(); 60 return; 61 } 62 RestoreVisualState(); 63 } 64 65 event->SetHandled(); 66 } 67 RestoreVisualState()68void SlideOutView::RestoreVisualState() { 69 // Restore the layer state. 70 const int kSwipeRestoreDurationMS = 150; 71 ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); 72 settings.SetTransitionDuration( 73 base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMS)); 74 layer()->SetTransform(gfx::Transform()); 75 layer()->SetOpacity(1.f); 76 } 77 SlideOutAndClose(SlideDirection direction)78void SlideOutView::SlideOutAndClose(SlideDirection direction) { 79 const int kSwipeOutTotalDurationMS = 150; 80 int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity(); 81 ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); 82 settings.SetTransitionDuration( 83 base::TimeDelta::FromMilliseconds(swipe_out_duration)); 84 settings.AddObserver(this); 85 86 gfx::Transform transform; 87 transform.Translate(direction == SLIDE_LEFT ? -width() : width(), 0.0); 88 layer()->SetTransform(transform); 89 layer()->SetOpacity(0.f); 90 } 91 OnImplicitAnimationsCompleted()92void SlideOutView::OnImplicitAnimationsCompleted() { 93 OnSlideOut(); 94 } 95 96 } // namespace views 97