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 "ash/wm/gestures/tray_gesture_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/system/tray/system_tray_bubble.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/layer.h"
12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/transform.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinBubbleHeight = 13;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TrayGestureHandler::TrayGestureHandler()
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : widget_(NULL),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gesture_drag_amount_(0) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(oshima): Support multiple display case.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SystemTray* tray = Shell::GetInstance()->GetPrimarySystemTray();
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tray->ShowDefaultView(BUBBLE_CREATE_NEW);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemTrayBubble* bubble = tray->GetSystemBubble();
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bubble)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bubble->bubble_view()->set_gesture_dragging(true);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_ = bubble->bubble_view()->GetWidget();
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_->AddObserver(this);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds = widget_->GetWindowBoundsInScreen();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int height_change = bounds.height() - kMinBubbleHeight;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds.set_height(kMinBubbleHeight);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds.set_y(bounds.y() + height_change);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_->SetBounds(bounds);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TrayGestureHandler::~TrayGestureHandler() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (widget_)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget_->RemoveObserver(this);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TrayGestureHandler::UpdateGestureDrag(const ui::GestureEvent& event) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!widget_)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gesture_drag_amount_ += event.details().scroll_y();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gesture_drag_amount_ > 0 && gesture_drag_amount_ < kMinBubbleHeight) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget_->Close();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds = widget_->GetWindowBoundsInScreen();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_height = std::min(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kMinBubbleHeight + std::max(0, static_cast<int>(-gesture_drag_amount_)),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget_->GetContentsView()->GetPreferredSize().height());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int height_change = bounds.height() - new_height;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds.set_height(new_height);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bounds.set_y(bounds.y() + height_change);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_->SetBounds(bounds);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TrayGestureHandler::CompleteGestureDrag(const ui::GestureEvent& event) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!widget_)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_->RemoveObserver(this);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close the widget if it hasn't been dragged enough.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool should_close = false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int height = widget_->GetWindowBoundsInScreen().height();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int preferred_height =
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget_->GetContentsView()->GetPreferredSize().height();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.type() == ui::ET_GESTURE_SCROLL_END) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const float kMinThresholdGestureDrag = 0.4f;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (height < preferred_height * kMinThresholdGestureDrag)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_close = true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event.type() == ui::ET_SCROLL_FLING_START) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const float kMinThresholdGestureDragExposeFling = 0.25f;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const float kMinThresholdGestureFling = 1000.f;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (height < preferred_height * kMinThresholdGestureDragExposeFling &&
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        event.details().velocity_y() > -kMinThresholdGestureFling)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_close = true;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_close) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget_->Close();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SystemTrayBubble* bubble =
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Shell::GetInstance()->GetPrimarySystemTray()->GetSystemBubble();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bubble)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bubble->bubble_view()->set_gesture_dragging(false);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TrayGestureHandler::OnWidgetDestroying(views::Widget* widget) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(widget_, widget);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  widget_ = NULL;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ash
108