diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-22 23:04:38 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-22 23:04:38 +0000 |
commit | 17a6cb95e99a66058f8767a8e026148e7130119d (patch) | |
tree | e4ef0d098c3de3c5c93b66c816712f210b4d85f4 /ui/aura_shell | |
parent | f552df55f9bac09d13c0d8d9566d9c1d3e73e4cc (diff) | |
download | chromium_src-17a6cb95e99a66058f8767a8e026148e7130119d.zip chromium_src-17a6cb95e99a66058f8767a8e026148e7130119d.tar.gz chromium_src-17a6cb95e99a66058f8767a8e026148e7130119d.tar.bz2 |
Aura: Fix window resizing for large drags.
* Fix a DCHECK due to a negative width when resizing the right edge past the left one, and vice versa.
* Fix the window moving when resizing its left edge past the minimum size, ditto for top edge.
* Add unit tests for above.
* Add GetMinimizeSize() method to aura::WindowDelegate interface.
BUG=104245
TEST=aura_shell_unittests, manual
Review URL: http://codereview.chromium.org/8618009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111244 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura_shell')
-rw-r--r-- | ui/aura_shell/toplevel_window_event_filter.cc | 131 | ||||
-rw-r--r-- | ui/aura_shell/toplevel_window_event_filter.h | 28 | ||||
-rw-r--r-- | ui/aura_shell/toplevel_window_event_filter_unittest.cc | 95 |
3 files changed, 187 insertions, 67 deletions
diff --git a/ui/aura_shell/toplevel_window_event_filter.cc b/ui/aura_shell/toplevel_window_event_filter.cc index d6e996c..c29da93 100644 --- a/ui/aura_shell/toplevel_window_event_filter.cc +++ b/ui/aura_shell/toplevel_window_event_filter.cc @@ -106,15 +106,25 @@ int GetSizeChangeDirectionForWindowComponent(int window_component) { return size_change_direction; } -int GetXMultiplierForWindowComponent(int window_component) { - return window_component == HTTOPRIGHT ? -1 : 1; +// Returns true for resize components along the right edge, where a drag in +// positive x will make the window larger. +bool IsRightEdge(int window_component) { + return window_component == HTTOPRIGHT || + window_component == HTRIGHT || + window_component == HTBOTTOMRIGHT || + window_component == HTGROWBOX; } -int GetYMultiplierForWindowComponent(int window_component) { - return window_component == HTBOTTOMLEFT ? -1 : 1; +// Returns true for resize components in along the bottom edge, where a drag +// in positive y will make the window larger. +bool IsBottomEdge(int window_component) { + return window_component == HTBOTTOMLEFT || + window_component == HTBOTTOM || + window_component == HTBOTTOMRIGHT || + window_component == HTGROWBOX; } -} +} // namespace ToplevelWindowEventFilter::ToplevelWindowEventFilter(aura::Window* owner) : EventFilter(owner), @@ -143,8 +153,7 @@ bool ToplevelWindowEventFilter::PreHandleMouseEvent(aura::Window* target, // pressed without mouse move event. UpdateWindowComponentForEvent(target, event); mouse_down_bounds_ = target->bounds(); - mouse_down_offset_in_target_ = event->location(); - mouse_down_offset_in_parent_ = mouse_down_offset_in_target_; + mouse_down_offset_in_parent_ = event->location(); aura::Window::ConvertPointToWindow(target, target->parent(), &mouse_down_offset_in_parent_); return GetBoundsChangeForWindowComponent(window_component_) != @@ -192,8 +201,21 @@ bool ToplevelWindowEventFilter::HandleDrag(aura::Window* target, target->GetIntProperty(aura::kShowStateKey) != ui::SHOW_STATE_DEFAULT) return false; - target->SetBounds(gfx::Rect(GetOriginForDrag(bounds_change, target, event), - GetSizeForDrag(bounds_change, target, event))); + // Dragging a window moves the local coordinate frame, so do arithmetic + // in the parent coordinate frame. + gfx::Point event_location_in_parent(event->location()); + aura::Window::ConvertPointToWindow(target, target->parent(), + &event_location_in_parent); + int delta_x = event_location_in_parent.x() - mouse_down_offset_in_parent_.x(); + int delta_y = event_location_in_parent.y() - mouse_down_offset_in_parent_.y(); + + // The minimize size constraint may limit how much we change the window + // position. For example, dragging the left edge to the right should stop + // repositioning the window when the minimize size is reached. + gfx::Size size = GetSizeForDrag(bounds_change, target, &delta_x, &delta_y); + gfx::Point origin = GetOriginForDrag(bounds_change, delta_x, delta_y); + + target->SetBounds(gfx::Rect(origin, size)); return true; } @@ -206,23 +228,16 @@ void ToplevelWindowEventFilter::UpdateWindowComponentForEvent( gfx::Point ToplevelWindowEventFilter::GetOriginForDrag( int bounds_change, - aura::Window* target, - aura::MouseEvent* event) const { + int delta_x, + int delta_y) const { gfx::Point origin = mouse_down_bounds_.origin(); if (bounds_change & kBoundsChange_Repositions) { int pos_change_direction = GetPositionChangeDirectionForWindowComponent(window_component_); - - if (pos_change_direction & kBoundsChangeDirection_Horizontal) { - origin.set_x(event->location().x()); - origin.Offset(-mouse_down_offset_in_target_.x(), 0); - origin.Offset(target->bounds().x(), 0); - } - if (pos_change_direction & kBoundsChangeDirection_Vertical) { - origin.set_y(event->location().y()); - origin.Offset(0, -mouse_down_offset_in_target_.y()); - origin.Offset(0, target->bounds().y()); - } + if (pos_change_direction & kBoundsChangeDirection_Horizontal) + origin.Offset(delta_x, 0); + if (pos_change_direction & kBoundsChangeDirection_Vertical) + origin.Offset(0, delta_y); } return origin; } @@ -230,40 +245,56 @@ gfx::Point ToplevelWindowEventFilter::GetOriginForDrag( gfx::Size ToplevelWindowEventFilter::GetSizeForDrag( int bounds_change, aura::Window* target, - aura::MouseEvent* event) const { + int* delta_x, + int* delta_y) const { gfx::Size size = mouse_down_bounds_.size(); if (bounds_change & kBoundsChange_Resizes) { + gfx::Size min_size = target->delegate()->GetMinimumSize(); int size_change_direction = GetSizeChangeDirectionForWindowComponent(window_component_); - - gfx::Point event_location_in_parent(event->location()); - aura::Window::ConvertPointToWindow(target, target->parent(), - &event_location_in_parent); - - // The math changes depending on whether the window is being resized, or - // repositioned in addition to being resized. - int first_x = bounds_change & kBoundsChange_Repositions ? - mouse_down_offset_in_parent_.x() : event_location_in_parent.x(); - int first_y = bounds_change & kBoundsChange_Repositions ? - mouse_down_offset_in_parent_.y() : event_location_in_parent.y(); - int second_x = bounds_change & kBoundsChange_Repositions ? - event_location_in_parent.x() : mouse_down_offset_in_parent_.x(); - int second_y = bounds_change & kBoundsChange_Repositions ? - event_location_in_parent.y() : mouse_down_offset_in_parent_.y(); - - int x_multiplier = GetXMultiplierForWindowComponent(window_component_); - int y_multiplier = GetYMultiplierForWindowComponent(window_component_); - - int width = size.width() + - (size_change_direction & kBoundsChangeDirection_Horizontal ? - x_multiplier * (first_x - second_x) : 0); - int height = size.height() + - (size_change_direction & kBoundsChangeDirection_Vertical ? - y_multiplier * (first_y - second_y) : 0); - - size.SetSize(width, height); + size.SetSize( + GetWidthForDrag(size_change_direction, min_size.width(), delta_x), + GetHeightForDrag(size_change_direction, min_size.height(), delta_y)); } return size; } +int ToplevelWindowEventFilter::GetWidthForDrag(int size_change_direction, + int min_width, + int* delta_x) const { + int width = mouse_down_bounds_.width(); + if (size_change_direction & kBoundsChangeDirection_Horizontal) { + // Along the right edge, positive delta_x increases the window size. + int x_multiplier = IsRightEdge(window_component_) ? 1 : -1; + width += x_multiplier * (*delta_x); + + // Ensure we don't shrink past the minimum width and clamp delta_x + // for the window origin computation. + if (width < min_width) { + width = min_width; + *delta_x = -x_multiplier * (mouse_down_bounds_.width() - min_width); + } + } + return width; +} + +int ToplevelWindowEventFilter::GetHeightForDrag(int size_change_direction, + int min_height, + int* delta_y) const { + int height = mouse_down_bounds_.height(); + if (size_change_direction & kBoundsChangeDirection_Vertical) { + // Along the bottom edge, positive delta_y increases the window size. + int y_multiplier = IsBottomEdge(window_component_) ? 1 : -1; + height += y_multiplier * (*delta_y); + + // Ensure we don't shrink past the minimum height and clamp delta_y + // for the window origin computation. + if (height < min_height) { + height = min_height; + *delta_y = -y_multiplier * (mouse_down_bounds_.height() - min_height); + } + } + return height; +} + } // namespace aura diff --git a/ui/aura_shell/toplevel_window_event_filter.h b/ui/aura_shell/toplevel_window_event_filter.h index e114586..6491c0a 100644 --- a/ui/aura_shell/toplevel_window_event_filter.h +++ b/ui/aura_shell/toplevel_window_event_filter.h @@ -53,17 +53,29 @@ class AURA_SHELL_EXPORT ToplevelWindowEventFilter : public aura::EventFilter { // Calculates the new origin of the window during a drag. gfx::Point GetOriginForDrag(int bounds_change, - aura::Window* target, - aura::MouseEvent* event) const; + int delta_x, + int delta_y) const; - // Calculates the new size of the window during a drag. + // Calculates the new size of the |target| window during a drag. + // If the size is constrained, |delta_x| and |delta_y| may be clamped. gfx::Size GetSizeForDrag(int bounds_change, aura::Window* target, - aura::MouseEvent* event) const; - - // The mouse position in the target window when the mouse was pressed, in - // target window coordinates. - gfx::Point mouse_down_offset_in_target_; + int* delta_x, + int* delta_y) const; + + // Calculates new width of a window during a drag where the mouse + // position changed by |delta_x|. |delta_x| may be clamped if the window + // size is constrained by |min_width|. + int GetWidthForDrag(int size_change_direction, + int min_width, + int* delta_x) const; + + // Calculates new height of a window during a drag where the mouse + // position changed by |delta_y|. |delta_y| may be clamped if the window + // size is constrained by |min_height|. + int GetHeightForDrag(int size_change_direction, + int min_height, + int* delta_y) const; // The mouse position in the target window when the mouse was pressed, in // the target window's parent's coordinates. diff --git a/ui/aura_shell/toplevel_window_event_filter_unittest.cc b/ui/aura_shell/toplevel_window_event_filter_unittest.cc index e2c0094..a2c0eed 100644 --- a/ui/aura_shell/toplevel_window_event_filter_unittest.cc +++ b/ui/aura_shell/toplevel_window_event_filter_unittest.cc @@ -43,13 +43,8 @@ class TestWindowDelegate : public aura::test::TestWindowDelegate { private: // Overridden from aura::Test::TestWindowDelegate: - virtual void OnBoundsChanging(gfx::Rect* new_bounds) OVERRIDE { - if (!min_size_.IsEmpty()) { - new_bounds->set_width(std::max(min_size_.width(), - new_bounds->width())); - new_bounds->set_height(std::max(min_size_.height(), - new_bounds->height())); - } + virtual gfx::Size GetMinimumSize() const OVERRIDE { + return min_size_; } virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE { return hittest_code_; @@ -126,7 +121,7 @@ TEST_F(ToplevelWindowEventFilterTest, GrowBox) { scoped_ptr<aura::Window> w1(CreateWindow(HTGROWBOX)); TestWindowDelegate* window_delegate = static_cast<TestWindowDelegate*>(w1->delegate()); - window_delegate->set_min_size(gfx::Size(50, 50)); + window_delegate->set_min_size(gfx::Size(40, 40)); gfx::Point position = w1->bounds().origin(); aura::test::EventGenerator generator; @@ -147,7 +142,7 @@ TEST_F(ToplevelWindowEventFilterTest, GrowBox) { // Enforce minimum size. generator.DragMouseBy(-60, -60); EXPECT_EQ(position, w1->bounds().origin()); - EXPECT_EQ(gfx::Size(50, 50), w1->bounds().size()); + EXPECT_EQ(gfx::Size(40, 40), w1->bounds().size()); } TEST_F(ToplevelWindowEventFilterTest, Right) { @@ -223,5 +218,87 @@ TEST_F(ToplevelWindowEventFilterTest, Client) { EXPECT_EQ(bounds, w1->bounds()); } +TEST_F(ToplevelWindowEventFilterTest, LeftPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTLEFT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + + // Simulate a large left-to-right drag. Window width should be clamped to + // minimum and position change should be limited as well. + DragFromCenterBy(w1.get(), 333, 0); + EXPECT_EQ(gfx::Point(60, 0), w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 100), w1->bounds().size()); +} + +TEST_F(ToplevelWindowEventFilterTest, RightPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTRIGHT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + gfx::Point position = w1->bounds().origin(); + + // Simulate a large right-to-left drag. Window width should be clamped to + // minimum and position should not change. + DragFromCenterBy(w1.get(), -333, 0); + EXPECT_EQ(position, w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 100), w1->bounds().size()); +} + +TEST_F(ToplevelWindowEventFilterTest, TopLeftPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTTOPLEFT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + + // Simulate a large top-left to bottom-right drag. Window width should be + // clamped to minimum and position should be limited. + DragFromCenterBy(w1.get(), 333, 444); + EXPECT_EQ(gfx::Point(60, 60), w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 40), w1->bounds().size()); +} + +TEST_F(ToplevelWindowEventFilterTest, TopRightPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTTOPRIGHT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + + // Simulate a large top-right to bottom-left drag. Window size should be + // clamped to minimum, x position should not change, and y position should + // be clamped. + DragFromCenterBy(w1.get(), -333, 444); + EXPECT_EQ(gfx::Point(0, 60), w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 40), w1->bounds().size()); +} + +TEST_F(ToplevelWindowEventFilterTest, BottomLeftPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMLEFT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + + // Simulate a large bottom-left to top-right drag. Window size should be + // clamped to minimum, x position should be clamped, and y position should + // not change. + DragFromCenterBy(w1.get(), 333, -444); + EXPECT_EQ(gfx::Point(60, 0), w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 40), w1->bounds().size()); +} + +TEST_F(ToplevelWindowEventFilterTest, BottomRightPastMinimum) { + scoped_ptr<aura::Window> w1(CreateWindow(HTBOTTOMRIGHT)); + TestWindowDelegate* window_delegate = + static_cast<TestWindowDelegate*>(w1->delegate()); + window_delegate->set_min_size(gfx::Size(40, 40)); + gfx::Point position = w1->bounds().origin(); + + // Simulate a large bottom-right to top-left drag. Window size should be + // clamped to minimum and position should not change. + DragFromCenterBy(w1.get(), -333, -444); + EXPECT_EQ(position, w1->bounds().origin()); + EXPECT_EQ(gfx::Size(40, 40), w1->bounds().size()); +} + } // namespace test } // namespace aura |