diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 02:58:56 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-13 02:58:56 +0000 |
commit | 1d0dfbce01312325b5ce383218740530a446a0cf (patch) | |
tree | a12e233e9d8a945582487ac7bec2d9af8f30e80b /ash/wm | |
parent | 84ff1e9c512b93641613927257a39e4d2def3987 (diff) | |
download | chromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.zip chromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.tar.gz chromium_src-1d0dfbce01312325b5ce383218740530a446a0cf.tar.bz2 |
ash: Add gesture support for the window-maximize button.
BUG=132282
TEST=aura_shell_unittests
Review URL: https://chromiumcodereview.appspot.com/10536124
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141843 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/wm')
-rw-r--r-- | ash/wm/custom_frame_view_ash.h | 15 | ||||
-rw-r--r-- | ash/wm/custom_frame_view_ash_unittest.cc | 194 | ||||
-rw-r--r-- | ash/wm/workspace/frame_maximize_button.cc | 121 | ||||
-rw-r--r-- | ash/wm/workspace/frame_maximize_button.h | 17 |
4 files changed, 307 insertions, 40 deletions
diff --git a/ash/wm/custom_frame_view_ash.h b/ash/wm/custom_frame_view_ash.h index fc31015..fea059f 100644 --- a/ash/wm/custom_frame_view_ash.h +++ b/ash/wm/custom_frame_view_ash.h @@ -35,6 +35,21 @@ class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView, CustomFrameViewAsh(); virtual ~CustomFrameViewAsh(); + // For testing. + class TestApi { + public: + explicit TestApi(CustomFrameViewAsh* frame) : frame_(frame) { + } + + views::ImageButton* maximize_button() const { + return frame_->maximize_button_; + } + + private: + TestApi(); + CustomFrameViewAsh* frame_; + }; + void Init(views::Widget* frame); views::ImageButton* close_button() { return close_button_; } diff --git a/ash/wm/custom_frame_view_ash_unittest.cc b/ash/wm/custom_frame_view_ash_unittest.cc new file mode 100644 index 0000000..d6149df --- /dev/null +++ b/ash/wm/custom_frame_view_ash_unittest.cc @@ -0,0 +1,194 @@ +// 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 "ash/wm/custom_frame_view_ash.h" + +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/window_util.h" +#include "ash/wm/workspace/snap_sizer.h" +#include "base/command_line.h" +#include "ui/aura/aura_switches.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/window.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/test/test_views_delegate.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +namespace internal { + +namespace { + +class ShellViewsDelegate : public views::TestViewsDelegate { + public: + ShellViewsDelegate() {} + virtual ~ShellViewsDelegate() {} + + // Overridden from views::TestViewsDelegate: + virtual views::NonClientFrameView* CreateDefaultNonClientFrameView( + views::Widget* widget) OVERRIDE { + return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(widget); + } + bool UseTransparentWindows() const OVERRIDE { + // Ash uses transparent window frames. + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate); +}; + +class TestWidgetDelegate : public views::WidgetDelegateView { + public: + TestWidgetDelegate() {} + virtual ~TestWidgetDelegate() {} + + // Overridden from views::WidgetDelegate: + virtual views::View* GetContentsView() OVERRIDE { + return this; + } + virtual bool CanResize() const OVERRIDE { + return true; + } + virtual bool CanMaximize() const OVERRIDE { + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); +}; + +} // namespace + +class CustomFrameViewAshTest : public ash::test::AshTestBase { + public: + CustomFrameViewAshTest() {} + virtual ~CustomFrameViewAshTest() {} + + views::Widget* CreateWidget() { + views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); + views::Widget* widget = new views::Widget; + params.delegate = new TestWidgetDelegate; + widget->Init(params); + widget->Show(); + return widget; + } + + CustomFrameViewAsh* custom_frame_view_ash(views::Widget* widget) const { + return static_cast<CustomFrameViewAsh*>(widget->non_client_view()-> + frame_view()); + } + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + if (!views::ViewsDelegate::views_delegate) { + views_delegate_.reset(new ShellViewsDelegate); + views::ViewsDelegate::views_delegate = views_delegate_.get(); + } + } + + virtual void TearDown() OVERRIDE { + if (views_delegate_.get()) { + views::ViewsDelegate::views_delegate = NULL; + views_delegate_.reset(); + } + AshTestBase::TearDown(); + } + + private: + scoped_ptr<views::ViewsDelegate> views_delegate_; + + DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest); +}; + +// Tests that clicking on the resize-button toggles between maximize and normal +// state. +TEST_F(CustomFrameViewAshTest, ResizeButtonToggleMaximize) { + views::Widget* widget = CreateWidget(); + aura::Window* window = widget->GetNativeWindow(); + CustomFrameViewAsh* frame = custom_frame_view_ash(widget); + CustomFrameViewAsh::TestApi test(frame); + views::View* view = test.maximize_button(); + gfx::Point center = view->GetScreenBounds().CenterPoint(); + + aura::test::EventGenerator generator(window->GetRootWindow(), center); + + EXPECT_FALSE(ash::wm::IsWindowMaximized(window)); + + generator.ClickLeftButton(); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(ash::wm::IsWindowMaximized(window)); + + center = view->GetScreenBounds().CenterPoint(); + generator.MoveMouseTo(center); + generator.ClickLeftButton(); + RunAllPendingInMessageLoop(); + EXPECT_FALSE(ash::wm::IsWindowMaximized(window)); + + widget->Close(); +} + +// Tests that click+dragging on the resize-button tiles or minimizes the window. +TEST_F(CustomFrameViewAshTest, ResizeButtonDrag) { + views::Widget* widget = CreateWidget(); + aura::Window* window = widget->GetNativeWindow(); + CustomFrameViewAsh* frame = custom_frame_view_ash(widget); + CustomFrameViewAsh::TestApi test(frame); + views::View* view = test.maximize_button(); + gfx::Point center = view->GetScreenBounds().CenterPoint(); + const int kGridSize = ash::Shell::GetInstance()->GetGridSize(); + + aura::test::EventGenerator generator(window->GetRootWindow(), center); + + EXPECT_TRUE(ash::wm::IsWindowNormal(window)); + + // Snap right. + { + generator.PressLeftButton(); + generator.MoveMouseBy(10, 0); + generator.ReleaseLeftButton(); + RunAllPendingInMessageLoop(); + + EXPECT_FALSE(ash::wm::IsWindowMaximized(window)); + EXPECT_FALSE(ash::wm::IsWindowMinimized(window)); + internal::SnapSizer sizer(window, center, + internal::SnapSizer::RIGHT_EDGE, kGridSize); + EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString()); + } + + // Snap left. + { + center = view->GetScreenBounds().CenterPoint(); + generator.MoveMouseTo(center); + generator.PressLeftButton(); + generator.MoveMouseBy(-10, 0); + generator.ReleaseLeftButton(); + RunAllPendingInMessageLoop(); + + EXPECT_FALSE(ash::wm::IsWindowMaximized(window)); + EXPECT_FALSE(ash::wm::IsWindowMinimized(window)); + internal::SnapSizer sizer(window, center, + internal::SnapSizer::LEFT_EDGE, kGridSize); + EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString()); + } + + // Minimize. + { + center = view->GetScreenBounds().CenterPoint(); + generator.MoveMouseTo(center); + generator.PressLeftButton(); + generator.MoveMouseBy(0, 10); + generator.ReleaseLeftButton(); + RunAllPendingInMessageLoop(); + + EXPECT_TRUE(ash::wm::IsWindowMinimized(window)); + } + + widget->Close(); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc index 06afc02..061d33f 100644 --- a/ash/wm/workspace/frame_maximize_button.cc +++ b/ash/wm/workspace/frame_maximize_button.cc @@ -116,17 +116,8 @@ FrameMaximizeButton::~FrameMaximizeButton() { bool FrameMaximizeButton::OnMousePressed(const views::MouseEvent& event) { is_snap_enabled_ = event.IsLeftMouseButton(); - if (is_snap_enabled_) { - snap_sizer_.reset(NULL); - InstallEventFilter(); - snap_type_ = SNAP_NONE; - press_location_ = event.location(); - exceeded_drag_threshold_ = false; - update_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kUpdateDelayMS), - this, &FrameMaximizeButton::UpdateSnapFromCursorScreenPoint); - } + if (is_snap_enabled_) + ProcessStartEvent(event); ImageButton::OnMousePressed(event); return true; } @@ -140,34 +131,14 @@ void FrameMaximizeButton::OnMouseExited(const views::MouseEvent& event) { } bool FrameMaximizeButton::OnMouseDragged(const views::MouseEvent& event) { - if (is_snap_enabled_) { - int delta_x = event.location().x() - press_location_.x(); - int delta_y = event.location().y() - press_location_.y(); - if (!exceeded_drag_threshold_) { - exceeded_drag_threshold_ = - views::View::ExceededDragThreshold(delta_x, delta_y); - } - if (exceeded_drag_threshold_) - UpdateSnap(event.location()); - } + if (is_snap_enabled_) + ProcessUpdateEvent(event); return ImageButton::OnMouseDragged(event); } void FrameMaximizeButton::OnMouseReleased(const views::MouseEvent& event) { - update_timer_.Stop(); - UninstallEventFilter(); - bool should_snap = is_snap_enabled_; - is_snap_enabled_ = false; - if (should_snap && snap_type_ != SNAP_NONE) { - SetState(BS_NORMAL); - // SetState will not call SchedulePaint() if state was already set to - // BS_NORMAL during a drag. - SchedulePaint(); - phantom_window_.reset(); - Snap(); - } else { + if (!ProcessEndEvent(event)) ImageButton::OnMouseReleased(event); - } } void FrameMaximizeButton::OnMouseCaptureLost() { @@ -175,6 +146,38 @@ void FrameMaximizeButton::OnMouseCaptureLost() { ImageButton::OnMouseCaptureLost(); } +ui::GestureStatus FrameMaximizeButton::OnGestureEvent( + const views::GestureEvent& event) { + if (event.type() == ui::ET_GESTURE_TAP_DOWN) { + is_snap_enabled_ = true; + ProcessStartEvent(event); + return ui::GESTURE_STATUS_CONSUMED; + } + + if (event.type() == ui::ET_GESTURE_TAP || + event.type() == ui::ET_GESTURE_SCROLL_END) { + if (event.type() == ui::ET_GESTURE_TAP) + snap_type_ = SnapTypeForLocation(event.location()); + ProcessEndEvent(event); + return ui::GESTURE_STATUS_CONSUMED; + } + + if (event.type() == ui::ET_GESTURE_END && event.delta_x() == 1 && + is_snap_enabled_) { + snap_type_ = SnapTypeForLocation(event.location()); + ProcessEndEvent(event); + return ui::GESTURE_STATUS_CONSUMED; + } + + if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE || + event.type() == ui::ET_GESTURE_SCROLL_BEGIN) { + ProcessUpdateEvent(event); + return ui::GESTURE_STATUS_CONSUMED; + } + + return ImageButton::OnGestureEvent(event); +} + gfx::ImageSkia FrameMaximizeButton::GetImageToPaint() { if (is_snap_enabled_) { int id = 0; @@ -223,6 +226,50 @@ gfx::ImageSkia FrameMaximizeButton::GetImageToPaint() { return ImageButton::GetImageToPaint(); } +void FrameMaximizeButton::ProcessStartEvent(const views::LocatedEvent& event) { + DCHECK(is_snap_enabled_); + snap_sizer_.reset(NULL); + InstallEventFilter(); + snap_type_ = SNAP_NONE; + press_location_ = event.location(); + exceeded_drag_threshold_ = false; + update_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kUpdateDelayMS), + this, + &FrameMaximizeButton::UpdateSnapFromEventLocation); +} + +void FrameMaximizeButton::ProcessUpdateEvent(const views::LocatedEvent& event) { + DCHECK(is_snap_enabled_); + int delta_x = event.x() - press_location_.x(); + int delta_y = event.y() - press_location_.y(); + if (!exceeded_drag_threshold_) { + exceeded_drag_threshold_ = + views::View::ExceededDragThreshold(delta_x, delta_y); + } + if (exceeded_drag_threshold_) + UpdateSnap(event.location()); +} + +bool FrameMaximizeButton::ProcessEndEvent(const views::LocatedEvent& event) { + update_timer_.Stop(); + UninstallEventFilter(); + bool should_snap = is_snap_enabled_; + is_snap_enabled_ = false; + + if (!should_snap || snap_type_ == SNAP_NONE) + return false; + + SetState(BS_NORMAL); + // SetState will not call SchedulePaint() if state was already set to + // BS_NORMAL during a drag. + SchedulePaint(); + phantom_window_.reset(); + Snap(); + return true; +} + void FrameMaximizeButton::Cancel() { UninstallEventFilter(); is_snap_enabled_ = false; @@ -243,14 +290,12 @@ void FrameMaximizeButton::UninstallEventFilter() { escape_event_filter_.reset(NULL); } -void FrameMaximizeButton::UpdateSnapFromCursorScreenPoint() { +void FrameMaximizeButton::UpdateSnapFromEventLocation() { // If the drag threshold has been exceeded the snap location is up to date. if (exceeded_drag_threshold_) return; exceeded_drag_threshold_ = true; - gfx::Point cursor_point(gfx::Screen::GetCursorScreenPoint()); - ConvertPointFromScreen(this, &cursor_point); - UpdateSnap(cursor_point); + UpdateSnap(press_location_); } void FrameMaximizeButton::UpdateSnap(const gfx::Point& location) { diff --git a/ash/wm/workspace/frame_maximize_button.h b/ash/wm/workspace/frame_maximize_button.h index c95e515..4d51ae3 100644 --- a/ash/wm/workspace/frame_maximize_button.h +++ b/ash/wm/workspace/frame_maximize_button.h @@ -35,6 +35,8 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton { virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE; virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE; virtual void OnMouseCaptureLost() OVERRIDE; + virtual ui::GestureStatus OnGestureEvent( + const views::GestureEvent& event) OVERRIDE; protected: // ImageButton overrides: @@ -53,6 +55,17 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton { SNAP_NONE }; + // Initializes the snap-gesture based on the event. This should only be called + // when the event is confirmed to have started a snap gesture. + void ProcessStartEvent(const views::LocatedEvent& event); + + // Updates the snap-state based on the current event. This should only be + // called after the snap gesture has already started. + void ProcessUpdateEvent(const views::LocatedEvent& event); + + // Returns true if the window was snapped. Returns false otherwise. + bool ProcessEndEvent(const views::LocatedEvent& event); + // Cancels snap behavior. void Cancel(); @@ -60,9 +73,9 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton { void InstallEventFilter(); void UninstallEventFilter(); - // Updates the snap position from the current location. This is invoked by + // Updates the snap position from the event location. This is invoked by // |update_timer_|. - void UpdateSnapFromCursorScreenPoint(); + void UpdateSnapFromEventLocation(); // Updates |snap_type_| based on a mouse drag. void UpdateSnap(const gfx::Point& location); |