diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-26 17:57:59 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-26 17:57:59 +0000 |
commit | 54784de9a4fb8f9845a93a1db1254a1d41918a37 (patch) | |
tree | 182f482fa2b916caeab61494482908081acf4df4 /ash | |
parent | 7efbb259c8f252b000650ac494242b79d74ee8c1 (diff) | |
download | chromium_src-54784de9a4fb8f9845a93a1db1254a1d41918a37.zip chromium_src-54784de9a4fb8f9845a93a1db1254a1d41918a37.tar.gz chromium_src-54784de9a4fb8f9845a93a1db1254a1d41918a37.tar.bz2 |
Adds the option for TopLevelWindowEventFilter to snap to a
grid. Resizes snap, but drags don't set bounds until done.
BUG=111285
TEST=none
R=ben@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9234056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119252 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/wm/toplevel_window_event_filter.cc | 58 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter.h | 14 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_filter_unittest.cc | 52 |
3 files changed, 116 insertions, 8 deletions
diff --git a/ash/wm/toplevel_window_event_filter.cc b/ash/wm/toplevel_window_event_filter.cc index fb50148..cafea95 100644 --- a/ash/wm/toplevel_window_event_filter.cc +++ b/ash/wm/toplevel_window_event_filter.cc @@ -14,6 +14,7 @@ #include "ui/aura/window_delegate.h" #include "ui/base/hit_test.h" #include "ui/base/ui_base_types.h" +#include "ui/gfx/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/screen.h" namespace ash { @@ -133,12 +134,31 @@ void ToggleMaximizedState(aura::Window* window) { ui::SHOW_STATE_NORMAL : ui::SHOW_STATE_MAXIMIZED); } +// Returns a location >= |location| that is aligned to fall on increments of +// |grid_size|. +int AlignToGrid(int location, int grid_size) { + if (grid_size <= 1 || location % grid_size == 0) + return location; + return floor(static_cast<float>(location) / static_cast<float>(grid_size) + + .5f) * grid_size; +} + +// Returns the closest location to |location| that is aligned to fall on +// increments of |grid_size|. +int AlignToGridRoundUp(int location, int grid_size) { + if (grid_size <= 1 || location % grid_size == 0) + return location; + return (location / grid_size + 1) * grid_size; +} + } // namespace ToplevelWindowEventFilter::ToplevelWindowEventFilter(aura::Window* owner) : EventFilter(owner), in_move_loop_(false), - window_component_(HTNOWHERE) { + window_component_(HTNOWHERE), + did_move_or_resize_(false), + grid_size_(0) { aura::client::SetWindowMoveClient(owner, this); } @@ -173,7 +193,7 @@ bool ToplevelWindowEventFilter::PreHandleMouseEvent(aura::Window* target, case ui::ET_MOUSE_DRAGGED: return HandleDrag(target, event); case ui::ET_MOUSE_RELEASED: - window_component_ = HTNOWHERE; + CompleteDrag(target); if (in_move_loop_) { MessageLoop::current()->Quit(); in_move_loop_ = false; @@ -213,7 +233,7 @@ ui::TouchStatus ToplevelWindowEventFilter::PreHandleTouchEvent( case ui::ET_TOUCH_RELEASED: pressed_touch_ids_.erase(event->touch_id()); if (pressed_touch_ids_.empty()) { - window_component_ = HTNOWHERE; + CompleteDrag(target); return ui::TOUCH_STATUS_END; } break; @@ -267,6 +287,24 @@ void ToplevelWindowEventFilter::MoveWindowToFront(aura::Window* target) { } } +void ToplevelWindowEventFilter::CompleteDrag(aura::Window* window) { + bool did_move_or_resize = did_move_or_resize_; + did_move_or_resize_ = false; + window_component_ = HTNOWHERE; + if (!did_move_or_resize || grid_size_ <= 1) + return; + const gfx::Rect& bounds(window->bounds()); + int x = AlignToGrid(bounds.x(), grid_size_); + int y = AlignToGrid(bounds.y(), grid_size_); + if (x != bounds.x() || y != bounds.y()) { + ui::ScopedLayerAnimationSettings scoped_setter( + window->layer()->GetAnimator()); + // Use a small duration since the grid is small. + scoped_setter.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100)); + window->SetBounds(gfx::Rect(gfx::Point(x ,y), bounds.size())); + } +} + bool ToplevelWindowEventFilter::HandleDrag(aura::Window* target, aura::LocatedEvent* event) { // This function only be triggered to move window @@ -315,6 +353,8 @@ bool ToplevelWindowEventFilter::HandleDrag(aura::Window* target, new_bounds.set_y(0); new_bounds.set_height(new_bounds.height() + delta); } + if (!did_move_or_resize_ && target->bounds() != new_bounds) + did_move_or_resize_ = true; target->SetBounds(new_bounds); return true; } @@ -359,6 +399,8 @@ gfx::Size ToplevelWindowEventFilter::GetSizeForDrag( gfx::Size size = mouse_down_bounds_.size(); if (bounds_change & kBoundsChange_Resizes) { gfx::Size min_size = target->delegate()->GetMinimumSize(); + min_size.set_width(AlignToGridRoundUp(min_size.width(), grid_size_)); + min_size.set_height(AlignToGridRoundUp(min_size.height(), grid_size_)); int size_change_direction = GetSizeChangeDirectionForWindowComponent(window_component_); size.SetSize( @@ -379,6 +421,11 @@ int ToplevelWindowEventFilter::GetWidthForDrag(aura::Window* target, // Along the right edge, positive delta_x increases the window size. int x_multiplier = IsRightEdge(window_component_) ? 1 : -1; width += x_multiplier * (*delta_x); + int adjusted_width = AlignToGrid(width, grid_size_); + if (adjusted_width != width) { + *delta_x += -x_multiplier * (width - adjusted_width); + width = adjusted_width; + } // Ensure we don't shrink past the minimum width and clamp delta_x // for the window origin computation. @@ -407,6 +454,11 @@ int ToplevelWindowEventFilter::GetHeightForDrag(aura::Window* target, // Along the bottom edge, positive delta_y increases the window size. int y_multiplier = IsBottomEdge(window_component_) ? 1 : -1; height += y_multiplier * (*delta_y); + int adjusted_height = AlignToGrid(height, grid_size_); + if (height != adjusted_height) { + *delta_y += -y_multiplier * (height - adjusted_height); + height = adjusted_height; + } // Ensure we don't shrink past the minimum height and clamp delta_y // for the window origin computation. diff --git a/ash/wm/toplevel_window_event_filter.h b/ash/wm/toplevel_window_event_filter.h index 2b5c88e..4689fc0 100644 --- a/ash/wm/toplevel_window_event_filter.h +++ b/ash/wm/toplevel_window_event_filter.h @@ -31,6 +31,11 @@ class ASH_EXPORT ToplevelWindowEventFilter : explicit ToplevelWindowEventFilter(aura::Window* owner); virtual ~ToplevelWindowEventFilter(); + // Sets the size of the grid. If non-zero all resizes and moves are forced to + // fall on a grid of the specified size. The default is 0, meaning the x,y and + // width,height are not restricted in anyway. + void set_grid_size(int size) { grid_size_ = size; } + // Overridden from aura::EventFilter: virtual bool PreHandleKeyEvent(aura::Window* target, aura::KeyEvent* event) OVERRIDE; @@ -57,6 +62,9 @@ class ASH_EXPORT ToplevelWindowEventFilter : // NOTE: this does NOT activate the window. void MoveWindowToFront(aura::Window* target); + // Invoked when the mouse is released to cleanup after a drag. + void CompleteDrag(aura::Window* window); + // Called during a drag to resize/position the window. // The return value is returned by OnMouseEvent() above. bool HandleDrag(aura::Window* target, aura::LocatedEvent* event); @@ -114,6 +122,12 @@ class ASH_EXPORT ToplevelWindowEventFilter : // Set of touch ids currently pressed. std::set<int> pressed_touch_ids_; + // Set to true if HandleDrag resized or moved the window. + bool did_move_or_resize_; + + // See description above setter. + int grid_size_; + DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventFilter); }; diff --git a/ash/wm/toplevel_window_event_filter_unittest.cc b/ash/wm/toplevel_window_event_filter_unittest.cc index db13f51..44f4ed3 100644 --- a/ash/wm/toplevel_window_event_filter_unittest.cc +++ b/ash/wm/toplevel_window_event_filter_unittest.cc @@ -61,13 +61,18 @@ class TestWindowDelegate : public aura::test::TestWindowDelegate { class ToplevelWindowEventFilterTest : public aura::test::AuraTestBase { public: - ToplevelWindowEventFilterTest() {} + ToplevelWindowEventFilterTest() : filter_(NULL) {} virtual ~ToplevelWindowEventFilterTest() {} virtual void SetUp() OVERRIDE { aura::test::AuraTestBase::SetUp(); - aura::RootWindow::GetInstance()->SetEventFilter( - new ToplevelWindowEventFilter(aura::RootWindow::GetInstance())); + filter_ = new ToplevelWindowEventFilter(aura::RootWindow::GetInstance()); + aura::RootWindow::GetInstance()->SetEventFilter(filter_); + } + + virtual void TearDown() OVERRIDE { + filter_ = NULL; + aura::test::AuraTestBase::TearDown(); } protected: @@ -92,6 +97,8 @@ class ToplevelWindowEventFilterTest : public aura::test::AuraTestBase { generator.PressMoveAndReleaseTouchBy(dx, dy); } + ToplevelWindowEventFilter* filter_; + private: DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventFilterTest); }; @@ -366,8 +373,6 @@ TEST_F(ToplevelWindowEventFilterTest, BottomWorkArea) { // Verifies we don't let windows drag to a -y location. TEST_F(ToplevelWindowEventFilterTest, DontDragToNegativeY) { scoped_ptr<aura::Window> target(CreateWindow(HTTOP)); - gfx::Rect work_area = - gfx::Screen::GetMonitorWorkAreaNearestWindow(target.get()); aura::test::EventGenerator generator(target.get()); generator.MoveMouseTo(0, 5); generator.DragMouseBy(0, -5); @@ -385,5 +390,42 @@ TEST_F(ToplevelWindowEventFilterTest, DontGotWiderThanScreen) { EXPECT_EQ(work_area.width(), target->bounds().width()); } +// Verifies that when a grid size is set resizes snap to the grid. +TEST_F(ToplevelWindowEventFilterTest, ResizeSnaps) { + filter_->set_grid_size(8); + scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT)); + DragFromCenterBy(target.get(), 11, 21); + EXPECT_EQ(112, target->bounds().width()); + EXPECT_EQ(120, target->bounds().height()); + // TODO(sky): enable when test animations complete immediately. + /* + target.reset(CreateWindow(HTTOPLEFT)); + target->SetBounds(gfx::Rect(48, 96, 100, 100)); + DragFromCenterBy(target.get(), -11, -21); + EXPECT_EQ(40, target->bounds().x()); + EXPECT_EQ(80, target->bounds().y()); + EXPECT_EQ(112, target->bounds().width()); + EXPECT_EQ(120, target->bounds().height()); + */ +} + +// Verifies that when a grid size is set dragging snaps to the grid. +TEST_F(ToplevelWindowEventFilterTest, DragSnaps) { + filter_->set_grid_size(8); + scoped_ptr<aura::Window> target(CreateWindow(HTCAPTION)); + aura::test::EventGenerator generator(target.get()); + generator.PressLeftButton(); + generator.MoveMouseTo(generator.current_location().Add(gfx::Point(11, 21))); + EXPECT_EQ(11, target->bounds().x()); + EXPECT_EQ(21, target->bounds().y()); + // TODO(sky): enable when test animations complete immediately. + /* + // We only snap moves to the grid on release. + generator.ReleaseLeftButton(); + EXPECT_EQ(8, target->bounds().x()); + EXPECT_EQ(24, target->bounds().y()); + */ +} + } // namespace test } // namespace aura |