summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-26 17:57:59 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-26 17:57:59 +0000
commit54784de9a4fb8f9845a93a1db1254a1d41918a37 (patch)
tree182f482fa2b916caeab61494482908081acf4df4 /ash
parent7efbb259c8f252b000650ac494242b79d74ee8c1 (diff)
downloadchromium_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.cc58
-rw-r--r--ash/wm/toplevel_window_event_filter.h14
-rw-r--r--ash/wm/toplevel_window_event_filter_unittest.cc52
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