Home | History | Annotate | Download | only in controls
      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