15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/slide_out_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/transform.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideOutView::SlideOutView()
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : gesture_scroll_amount_(0.f) {
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If accelerated compositing is not available, this widget tracks the
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OnSlideOut event but does not render any visible changes.
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetPaintToLayer(true);
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetFillsBoundsOpaquely(false);
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SlideOutView::~SlideOutView() {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SlideOutView::OnGestureEvent(ui::GestureEvent* event) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->type() == ui::ET_SCROLL_FLING_START) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The threshold for the fling velocity is computed empirically.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The unit is in pixels/second.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const float kFlingThresholdForClose = 800.f;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fabsf(event->details().velocity_x()) > kFlingThresholdForClose) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SlideOutAndClose(event->details().velocity_x() < 0 ? SLIDE_LEFT :
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       SLIDE_RIGHT);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event->StopPropagation();
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RestoreVisualState();
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!event->IsScrollGestureEvent())
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gesture_scroll_amount_ = 0.f;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The scroll-update events include the incremental scroll amount.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gesture_scroll_amount_ += event->details().scroll_x();
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    gfx::Transform transform;
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    transform.Translate(gesture_scroll_amount_, 0.0);
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    layer()->SetTransform(transform);
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    layer()->SetOpacity(
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        1.f - std::min(fabsf(gesture_scroll_amount_) / width(), 1.f));
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event->type() == ui::ET_GESTURE_SCROLL_END) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const float kScrollRatioForClosingNotification = 0.5f;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float scrolled_ratio = fabsf(gesture_scroll_amount_) / width();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (scrolled_ratio >= kScrollRatioForClosingNotification) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SlideOutAndClose(gesture_scroll_amount_ < 0 ? SLIDE_LEFT : SLIDE_RIGHT);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event->StopPropagation();
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RestoreVisualState();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->SetHandled();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SlideOutView::RestoreVisualState() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore the layer state.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kSwipeRestoreDurationMS = 150;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  settings.SetTransitionDuration(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMS));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer()->SetTransform(gfx::Transform());
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer()->SetOpacity(1.f);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SlideOutView::SlideOutAndClose(SlideDirection direction) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kSwipeOutTotalDurationMS = 150;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int swipe_out_duration = kSwipeOutTotalDurationMS * layer()->opacity();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  settings.SetTransitionDuration(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(swipe_out_duration));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  settings.AddObserver(this);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Transform transform;
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  transform.Translate(direction == SLIDE_LEFT ? -width() : width(), 0.0);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer()->SetTransform(transform);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layer()->SetOpacity(0.f);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SlideOutView::OnImplicitAnimationsCompleted() {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnSlideOut();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
97