// 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/slide_out_view.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/transform.h" namespace views { SlideOutView::SlideOutView() : gesture_scroll_amount_(0.f) { // If accelerated compositing is not available, this widget tracks the // OnSlideOut event but does not render any visible changes. SetPaintToLayer(true); SetFillsBoundsOpaquely(false); } SlideOutView::~SlideOutView() { } void SlideOutView::OnGestureEvent(ui::GestureEvent* event) { if (event->type() == ui::ET_SCROLL_FLING_START) { // The threshold for the fling velocity is computed empirically. // The unit is in pixels/second. const float kFlingThresholdForClose = 800.f; if (fabsf(event->details().velocity_x()) > kFlingThresholdForClose) { SlideOutAndClose(event->details().velocity_x() < 0 ? SLIDE_LEFT : SLIDE_RIGHT); event->StopPropagation(); return; } RestoreVisualState(); return; } if (!event->IsScrollGestureEvent()) return; if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) { gesture_scroll_amount_ = 0.f; } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { // The scroll-update events include the incremental scroll amount. gesture_scroll_amount_ += event->details().scroll_x(); gfx::Transform transform; transform.Translate(gesture_scroll_amount_, 0.0); layer()->SetTransform(transform); layer()->SetOpacity( 1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f)); } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { const float kScrollRatioForClosingNotification = 0.5f; float scrolled_ratio = fabsf(gesture_scroll_amount_) / width(); if (scrolled_ratio >= kScrollRatioForClosingNotification) { SlideOutAndClose(gesture_scroll_amount_ < 0 ? SLIDE_LEFT : SLIDE_RIGHT); event->StopPropagation(); return; } RestoreVisualState(); } event->SetHandled(); } void SlideOutView::RestoreVisualState() { // Restore the layer state. const int kSwipeRestoreDurationMS = 150; ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); settings.SetTransitionDuration( base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMS)); layer()->SetTransform(gfx::Transform()); layer()->SetOpacity(1.f); } void SlideOutView::SlideOutAndClose(SlideDirection direction) { const int kSwipeOutTotalDurationMS = 150; int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity(); ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); settings.SetTransitionDuration( base::TimeDelta::FromMilliseconds(swipe_out_duration)); settings.AddObserver(this); gfx::Transform transform; transform.Translate(direction == SLIDE_LEFT ? -width() : width(), 0.0); layer()->SetTransform(transform); layer()->SetOpacity(0.f); } void SlideOutView::OnImplicitAnimationsCompleted() { OnSlideOut(); } } // namespace views