Index: ash/wm/overview/window_selector_item.cc |
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc |
index 13b52b7856fe51df29935df38d369ac7848b1f63..2559362fffdf8dc848974cea9360559c60686dba 100644 |
--- a/ash/wm/overview/window_selector_item.cc |
+++ b/ash/wm/overview/window_selector_item.cc |
@@ -37,6 +37,13 @@ namespace ash { |
namespace { |
+// The minimum fling velocity which will cause a window to be closed. Unit is |
+// pixels per second. |
+const float kMinimumFlingVelocity = 4000.0f; |
+ |
+// The minimum opacity used during touch scroll gestures. |
+const float kMinimumOpacity = 0.2f; |
+ |
// In the conceptual overview table, the window margin is the space reserved |
// around the window within the cell. This margin does not overlap so the |
// closest distance between adjacent windows will be twice this amount. |
@@ -72,6 +79,36 @@ gfx::Rect GetTransformedBounds(aura::Window* window) { |
return ToEnclosingRect(bounds); |
} |
+// Convenvience method to fade in a Window with predefined animation settings. |
+// Note: The fade in animation will occur after a delay where the delay is how |
+// long the lay out animations take. |
+void SetupFadeInAfterLayout(aura::Window* window) { |
+ ui::Layer* layer = window->layer(); |
+ layer->SetOpacity(0.0f); |
+ ScopedOverviewAnimationSettings animation_settings( |
+ OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, |
+ window); |
+ layer->SetOpacity(1.0f); |
+} |
+ |
+// Convenience method to fade out a window using the animation settings defined |
+// by OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT. |
+void SetupFadeOut(aura::Window* window) { |
+ ScopedOverviewAnimationSettings animation_settings( |
+ OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT, |
+ window); |
+ window->layer()->SetOpacity(0.0f); |
+} |
+ |
+// Calculates the window opacity from the given scroll |distance| and the |
+// |min opacity_distance|. |
+float CalculateOpacityFromScrollDistance(int distance, |
+ int min_opacity_distance) { |
+ float opacity = |
+ 1.0f - static_cast<float>(abs(distance)) / min_opacity_distance; |
+ return std::min(1.0f, std::max(kMinimumOpacity, opacity)); |
+} |
+ |
// An image button with a close window icon. |
class OverviewCloseButton : public views::ImageButton { |
public: |
@@ -99,9 +136,10 @@ OverviewCloseButton::~OverviewCloseButton() { |
} // namespace |
WindowSelectorItem::OverviewLabelButton::OverviewLabelButton( |
- views::ButtonListener* listener, |
+ WindowSelectorItem* selector_item, |
const base::string16& text) |
- : LabelButton(listener, text), |
+ : LabelButton(selector_item, text), |
+ selector_item_(selector_item), |
top_padding_(0) { |
} |
@@ -114,6 +152,12 @@ gfx::Rect WindowSelectorItem::OverviewLabelButton::GetChildAreaBounds() { |
return bounds; |
} |
+void WindowSelectorItem::OverviewLabelButton::OnGestureEvent( |
+ ui::GestureEvent* event) { |
+ selector_item_->OnGestureEvent(event); |
+ views::LabelButton::OnGestureEvent(event); |
+} |
+ |
WindowSelectorItem::WindowSelectorItem(aura::Window* window) |
: dimmed_(false), |
root_window_(window->GetRootWindow()), |
@@ -216,6 +260,72 @@ void WindowSelectorItem::ButtonPressed(views::Button* sender, |
wm::GetWindowState(transform_window_.window())->Activate(); |
} |
+void WindowSelectorItem::OnGestureEvent(ui::GestureEvent* event) { |
+ if (Shell::GetInstance()->window_selector_controller()-> |
+ swipe_to_close_disabled()) |
+ return; |
+ |
+ int delta_x = 0; |
+ if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) |
+ scroll_x_origin_ = event->x(); |
+ else |
+ delta_x = event->x() - scroll_x_origin_; |
+ |
+ switch (event->type()) { |
+ case ui::ET_GESTURE_SCROLL_BEGIN: { |
+ // We need to call SetHandled() for the ET_GESTURE_SCROLL_BEGIN event so |
+ // that future ET_GESTURE_SCROLL_* events are sent here. |
+ event->SetHandled(); |
+ close_button_->SetEnabled(false); |
+ SetupFadeOut(close_button_widget_.GetNativeWindow()); |
+ break; |
+ } |
+ case ui::ET_GESTURE_SCROLL_UPDATE: { |
+ event->SetHandled(); |
+ ScopedTransformOverviewWindow::ScopedAnimationSettings |
+ animation_settings; |
+ transform_window_.BeginScopedAnimation( |
+ OverviewAnimationType::OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM, |
+ &animation_settings); |
+ |
+ gfx::Transform new_transform; |
+ new_transform.Translate(delta_x, 0); |
+ new_transform.PreconcatTransform( |
+ transform_window_.get_overview_transform()); |
+ transform_window_.SetTransform(root_window(), new_transform); |
+ |
+ const float opacity = CalculateOpacityFromScrollDistance(delta_x, |
+ GetMinimumCloseDistance()); |
+ transform_window_.SetOpacity(opacity); |
+ break; |
+ } |
+ case ui::ET_GESTURE_SCROLL_END: { |
+ event->SetHandled(); |
+ if (abs(delta_x) > GetMinimumCloseDistance()) { |
+ transform_window_.Close(); |
+ break; |
+ } |
+ ResetScrolledWindow(); |
+ break; |
+ } |
+ case ui::ET_SCROLL_FLING_START: { |
+ event->SetHandled(); |
+ if (abs(delta_x) > GetMinimumCloseDistance() || |
+ fabs(event->details().velocity_x()) > kMinimumFlingVelocity) { |
+ transform_window_.Close(); |
+ break; |
+ } |
+ ResetScrolledWindow(); |
+ break; |
+ } |
+ case ui::ET_GESTURE_END: |
+ scroll_x_origin_ = 0; |
+ break; |
+ default: |
+ break; |
+ } |
+} |
+ |
void WindowSelectorItem::OnWindowDestroying(aura::Window* window) { |
window->RemoveObserver(this); |
transform_window_.OnWindowDestroyed(); |
@@ -228,6 +338,20 @@ void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) { |
UpdateCloseButtonAccessibilityName(); |
} |
+void WindowSelectorItem::ResetScrolledWindow() { |
+ ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; |
+ transform_window_.BeginScopedAnimation( |
+ OverviewAnimationType::OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL, |
+ &animation_settings); |
+ |
+ transform_window_.SetTransform(root_window(), |
+ transform_window_.get_overview_transform()); |
+ transform_window_.SetOpacity(1.0); |
+ |
+ SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow()); |
+ close_button_->SetEnabled(true); |
+} |
+ |
void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, |
OverviewAnimationType animation_type) { |
DCHECK(root_window_ == GetWindow()->GetRootWindow()); |
@@ -261,8 +385,7 @@ void WindowSelectorItem::UpdateWindowLabel( |
if (!window_label_->IsVisible()) { |
window_label_->Show(); |
- ScopedOverviewAnimationSettings::SetupFadeInAfterLayout( |
- window_label_->GetNativeWindow()); |
+ SetupFadeInAfterLayout(window_label_->GetNativeWindow()); |
} |
gfx::Rect converted_bounds = |
@@ -311,8 +434,7 @@ void WindowSelectorItem::UpdateCloseButtonLayout( |
OverviewAnimationType animation_type) { |
if (!close_button_->visible()) { |
close_button_->SetVisible(true); |
- ScopedOverviewAnimationSettings::SetupFadeInAfterLayout( |
- close_button_widget_.GetNativeWindow()); |
+ SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow()); |
} |
ScopedOverviewAnimationSettings animation_settings(animation_type, |
close_button_widget_.GetNativeWindow()); |
@@ -334,4 +456,8 @@ void WindowSelectorItem::UpdateCloseButtonAccessibilityName() { |
GetWindow()->title())); |
} |
+int WindowSelectorItem::GetMinimumCloseDistance() const { |
+ return target_bounds_.size().width() / 2; |
+} |
+ |
} // namespace ash |