diff options
author | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 18:05:47 +0000 |
---|---|---|
committer | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 18:05:47 +0000 |
commit | 88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4 (patch) | |
tree | 63f8754188d4f1f7ec35e0e07b3bd11d98f060ca /ash | |
parent | 75ffa6b04b62224ba97d4b4a6f932ee1effe134e (diff) | |
download | chromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.zip chromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.tar.gz chromium_src-88fa8bf4bdda72610f727a0a3f7ce5e4fd7d2dc4.tar.bz2 |
Adding proper dragging behavior for L/R maximized windows.
BUG=141750
TEST=unit tests & visual
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=155840
Review URL: https://chromiumcodereview.appspot.com/10918077
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156058 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/wm/default_window_resizer.cc | 6 | ||||
-rw-r--r-- | ash/wm/frame_painter.cc | 40 | ||||
-rw-r--r-- | ash/wm/frame_painter.h | 3 | ||||
-rw-r--r-- | ash/wm/frame_painter_unittest.cc | 67 | ||||
-rw-r--r-- | ash/wm/window_resizer.cc | 20 | ||||
-rw-r--r-- | ash/wm/window_resizer.h | 4 | ||||
-rw-r--r-- | ash/wm/workspace/frame_maximize_button.cc | 7 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 12 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer_unittest.cc | 33 |
9 files changed, 187 insertions, 5 deletions
diff --git a/ash/wm/default_window_resizer.cc b/ash/wm/default_window_resizer.cc index 50cac97..dd874e3 100644 --- a/ash/wm/default_window_resizer.cc +++ b/ash/wm/default_window_resizer.cc @@ -7,6 +7,7 @@ #include "ash/shell.h" #include "ash/wm/coordinate_conversion.h" #include "ash/wm/cursor_manager.h" +#include "ash/wm/property_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" @@ -42,6 +43,8 @@ void DefaultWindowResizer::Drag(const gfx::Point& location, int event_flags) { gfx::Rect bounds(CalculateBoundsForDrag(details_, location)); if (bounds != details_.window->bounds()) { + if (!did_move_or_resize_ && !details_.restore_bounds.IsEmpty()) + ClearRestoreBounds(details_.window); did_move_or_resize_ = true; details_.window->SetBounds(bounds); } @@ -55,6 +58,9 @@ void DefaultWindowResizer::RevertDrag() { return; details_.window->SetBounds(details_.initial_bounds); + + if (!details_.restore_bounds.IsEmpty()) + SetRestoreBoundsInScreen(details_.window, details_.restore_bounds); } aura::Window* DefaultWindowResizer::GetTarget() { diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc index 1bfede6..a63f68a 100644 --- a/ash/wm/frame_painter.cc +++ b/ash/wm/frame_painter.cc @@ -7,6 +7,7 @@ #include "ash/ash_constants.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" +#include "ash/wm/property_util.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace_controller.h" #include "base/logging.h" // DCHECK @@ -26,6 +27,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/screen.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -246,6 +248,7 @@ int FramePainter::NonClientHitTest(views::NonClientFrameView* view, kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize); + frame_component = AdjustFrameHitCodeForMaximizedModes(frame_component); if (frame_component != HTNOWHERE) return frame_component; @@ -610,6 +613,43 @@ int FramePainter::GetHeaderOpacity(HeaderMode header_mode, return kInactiveWindowOpacity; } +int FramePainter::AdjustFrameHitCodeForMaximizedModes(int hit_code) { + if (hit_code != HTNOWHERE && wm::IsWindowNormal(window_) && + GetRestoreBoundsInScreen(window_)) { + // When there is a restore rectangle, a left/right maximized window might + // be active. + const gfx::Rect& bounds = frame_->GetWindowBoundsInScreen(); + const gfx::Rect& screen = + gfx::Screen::GetDisplayMatching(bounds).work_area(); + if (bounds.y() == screen.y() && bounds.bottom() == screen.bottom()) { + // The window is probably either left or right maximized. + if (bounds.x() == screen.x()) { + // It is left maximized and we can only allow a right resize. + return (hit_code == HTBOTTOMRIGHT || + hit_code == HTTOPRIGHT || + hit_code == HTRIGHT) ? HTRIGHT : HTNOWHERE; + } else if (bounds.right() == screen.right()) { + // It is right maximized and we can only allow a left resize. + return (hit_code == HTBOTTOMLEFT || + hit_code == HTTOPLEFT || + hit_code == HTLEFT) ? HTLEFT : HTNOWHERE; + } + } else if (bounds.x() == screen.x() && + bounds.right() == screen.right()) { + // If horizontal fill mode is activated we don't allow a left/right + // resizing. + if (hit_code == HTTOPRIGHT || + hit_code == HTTOP || + hit_code == HTTOPLEFT) + return HTTOP; + return (hit_code == HTBOTTOMRIGHT || + hit_code == HTBOTTOM || + hit_code == HTBOTTOMLEFT) ? HTBOTTOM : HTNOWHERE; + } + } + return hit_code; +} + // static bool FramePainter::UseSoloWindowHeader() { if (!instances_) diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h index 57045e3..cd725d4 100644 --- a/ash/wm/frame_painter.h +++ b/ash/wm/frame_painter.h @@ -141,6 +141,9 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver, int theme_frame_id, const gfx::ImageSkia* theme_frame_overlay); + // Adjust frame operations for left / right maximized modes. + int AdjustFrameHitCodeForMaximizedModes(int hit_code); + // Returns true if there is exactly one visible, normal-type window using // a header painted by this class, in which case we should paint a transparent // window header. diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc index c918f23..870761e 100644 --- a/ash/wm/frame_painter_unittest.cc +++ b/ash/wm/frame_painter_unittest.cc @@ -7,18 +7,40 @@ #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" +#include "ash/wm/property_util.h" #include "base/memory/scoped_ptr.h" #include "grit/ui_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/root_window.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/screen.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/window/non_client_view.h" using views::Widget; using views::ImageButton; namespace { +class ResizableWidgetDelegate : public views::WidgetDelegate { + public: + ResizableWidgetDelegate(views::Widget* widget) { + widget_ = widget; + } + + virtual bool CanResize() const OVERRIDE { return true; } + // Implementations of the widget class. + virtual views::Widget* GetWidget() OVERRIDE { return widget_; } + virtual const views::Widget* GetWidget() const OVERRIDE { return widget_; } + + private: + views::Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate); +}; + // Creates a test widget that owns its native widget. Widget* CreateTestWidget() { Widget* widget = new Widget; @@ -37,6 +59,17 @@ Widget* CreateAlwaysOnTopWidget() { return widget; } +Widget* CreateResizableWidget() { + Widget* widget = new Widget; + Widget::InitParams params; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.keep_on_top = true; + params.delegate = new ResizableWidgetDelegate(widget); + params.type = Widget::InitParams::TYPE_WINDOW; + widget->Init(params); + return widget; +} + } // namespace namespace ash { @@ -161,4 +194,38 @@ TEST_F(FramePainterTest, GetHeaderOpacity) { &custom_overlay)); } +// Test the hit test function with windows which are "partially maximized". +TEST_F(FramePainterTest, HitTestSpecialMaximizedModes) { + // Create a widget and a painter for it. + scoped_ptr<Widget> w1(CreateResizableWidget()); + FramePainter p1; + ImageButton size1(NULL); + ImageButton close1(NULL); + p1.Init(w1.get(), NULL, &size1, &close1, FramePainter::SIZE_BUTTON_MAXIMIZES); + views::NonClientFrameView* frame = w1->non_client_view()->frame_view(); + w1->Show(); + gfx::Rect any_rect = gfx::Rect(0, 0, 100, 100); + gfx::Rect screen = gfx::Screen::GetDisplayMatching(any_rect).work_area(); + w1->SetBounds(any_rect); + EXPECT_EQ(HTTOPLEFT, p1.NonClientHitTest(frame, gfx::Point(0, 15))); + w1->SetBounds(gfx::Rect( + screen.x(), screen.y(), screen.width() / 2, screen.height())); + // A hit without a set restore rect should produce a top left hit. + EXPECT_EQ(HTTOPLEFT, p1.NonClientHitTest(frame, gfx::Point(0, 15))); + ash::SetRestoreBoundsInScreen(w1->GetNativeWindow(), any_rect); + // A hit into the corner should produce nowhere - not left. + EXPECT_EQ(HTCAPTION, p1.NonClientHitTest(frame, gfx::Point(0, 15))); + // A hit into the middle upper area should generate right - not top&right. + EXPECT_EQ(HTRIGHT, + p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2, 15))); + // A hit into the middle should generate right. + EXPECT_EQ(HTRIGHT, + p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2, + screen.height() / 2))); + // A hit into the middle lower area should generate right - not bottom&right. + EXPECT_EQ(HTRIGHT, + p1.NonClientHitTest(frame, gfx::Point(screen.width() / 2, + screen.height() - 1))); +} + } // namespace ash diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc index 592fd81..c759c91 100644 --- a/ash/wm/window_resizer.cc +++ b/ash/wm/window_resizer.cc @@ -6,6 +6,8 @@ #include "ash/screen_ash.h" #include "ash/shell.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" @@ -112,6 +114,7 @@ WindowResizer::Details::Details(aura::Window* window, int window_component) : window(window), initial_bounds(window->bounds()), + restore_bounds(gfx::Rect()), initial_location_in_parent(location), initial_opacity(window->layer()->opacity()), window_component(window_component), @@ -121,6 +124,10 @@ WindowResizer::Details::Details(aura::Window* window, size_change_direction( GetSizeChangeDirectionForWindowComponent(window_component)), is_resizable(bounds_change != kBoundsChangeDirection_None) { + if (wm::IsWindowNormal(window) && + GetRestoreBoundsInScreen(window) && + window_component == HTCAPTION) + restore_bounds = *GetRestoreBoundsInScreen(window); } WindowResizer::Details::~Details() { @@ -175,6 +182,17 @@ gfx::Rect WindowResizer::CalculateBoundsForDrag( gfx::Size size = GetSizeForDrag(details, &delta_x, &delta_y); gfx::Point origin = GetOriginForDrag(details, delta_x, delta_y); + // When we might want to reposition a window which is also restored to its + // previous size, to keep the cursor within the dragged window. + if (!details.restore_bounds.IsEmpty() && + details.bounds_change & kBoundsChange_Repositions) { + // However - it is not desirable to change the origin if the window would + // be still hit by the cursor. + if (details.initial_location_in_parent.x() > + details.initial_bounds.x() + details.restore_bounds.width()) + origin.set_x(location.x() - details.restore_bounds.width() / 2); + } + gfx::Rect new_bounds(origin, size); // Update bottom edge to stay in the work area when we are resizing // by dragging the bottome edge or corners. @@ -229,6 +247,8 @@ gfx::Size WindowResizer::GetSizeForDrag(const Details& details, gfx::Size min_size = details.window->delegate()->GetMinimumSize(); size.SetSize(GetWidthForDrag(details, min_size.width(), delta_x), GetHeightForDrag(details, min_size.height(), delta_y)); + } else if (!details.restore_bounds.IsEmpty()) { + size = details.restore_bounds.size(); } return size; } diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h index 13ffb13..67dea81 100644 --- a/ash/wm/window_resizer.h +++ b/ash/wm/window_resizer.h @@ -64,6 +64,10 @@ class ASH_EXPORT WindowResizer { // Initial bounds of the window. gfx::Rect initial_bounds; + // Restore bounds (in screen coordinates) of the window before the drag + // started. Only set if the window is normal and is being dragged. + gfx::Rect restore_bounds; + // Location passed to the constructor, in |window->parent()|'s coordinates. gfx::Point initial_location_in_parent; diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc index c874f6e..735b1a6 100644 --- a/ash/wm/workspace/frame_maximize_button.cc +++ b/ash/wm/workspace/frame_maximize_button.cc @@ -553,9 +553,12 @@ MaximizeBubbleFrameState gfx::Rect screen = gfx::Screen::GetDisplayMatching(bounds).work_area(); if (bounds.width() < (screen.width() * kMinSnapSizePercent) / 100) return FRAME_STATE_NONE; + // We might still have a horizontally filled window at this point which we + // treat as no special state. + if (bounds.y() != screen.y() || bounds.height() != screen.height()) + return FRAME_STATE_NONE; + // We have to be in a maximize mode at this point. - DCHECK(bounds.y() == screen.y()); - DCHECK(bounds.height() >= screen.height()); if (bounds.x() == screen.x()) return FRAME_STATE_SNAP_LEFT; if (bounds.right() == screen.right()) diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 85bb095..88c9c9f 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -125,8 +125,11 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) { if (wm::IsWindowNormal(window())) AdjustBoundsForMainWindow(&bounds, grid_size); if (bounds != window()->bounds()) { - if (!did_move_or_resize_) + if (!did_move_or_resize_) { + if (!details_.restore_bounds.IsEmpty()) + ClearRestoreBounds(window()); RestackWindows(); + } did_move_or_resize_ = true; } @@ -164,7 +167,9 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) { if (snap_type_ == SNAP_LEFT_EDGE || snap_type_ == SNAP_RIGHT_EDGE) { if (!GetRestoreBoundsInScreen(window())) - SetRestoreBoundsInParent(window(), details_.initial_bounds); + SetRestoreBoundsInParent(window(), details_.restore_bounds.IsEmpty() ? + details_.initial_bounds : + details_.restore_bounds); window()->SetBounds(snap_sizer_->target_bounds()); return; } @@ -196,6 +201,9 @@ void WorkspaceWindowResizer::RevertDrag() { return; window()->SetBounds(details_.initial_bounds); + if (!details_.restore_bounds.IsEmpty()) + SetRestoreBoundsInScreen(details_.window, details_.restore_bounds); + if (details_.window_component == HTRIGHT) { int last_x = details_.initial_bounds.right(); for (size_t i = 0; i < attached_windows_.size(); ++i) { diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc index ba15148..b7eb06f 100644 --- a/ash/wm/workspace/workspace_window_resizer_unittest.cc +++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc @@ -458,7 +458,6 @@ TEST_F(WorkspaceWindowResizerTest, Edge) { EXPECT_EQ("20,30 50x60", GetRestoreBoundsInScreen(window_.get())->ToString()); } - // Try the same with the right side. scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( window_.get(), gfx::Point(), HTCAPTION, empty_windows())); @@ -869,5 +868,37 @@ TEST_F(WorkspaceWindowResizerTest, TestProperSizerResolutions) { EXPECT_EQ("0,0 640x552", rect.ToString()); } +// Verifies that a dragged window will restore to its pre-maximized size. +TEST_F(WorkspaceWindowResizerTest, RestoreToPreMaximizeCoordinates) { + window_->SetBounds(gfx::Rect(0, 0, 1000, 1000)); + SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Drag the window to new position by adding (10, 10) to original point, + // the window should get restored. + resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0); + resizer->CompleteDrag(0); + EXPECT_EQ("10,10 320x160", window_->bounds().ToString()); + // The restore rectangle should get cleared as well. + EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window_.get())); +} + +// Verifies that a dragged window will restore to its pre-maximized size. +TEST_F(WorkspaceWindowResizerTest, RevertResizeOperation) { + window_->SetBounds(gfx::Rect(0, 0, 1000, 1000)); + SetRestoreBoundsInScreen(window_.get(), gfx::Rect(96, 112, 320, 160)); + scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( + window_.get(), gfx::Point(), HTCAPTION, empty_windows())); + ASSERT_TRUE(resizer.get()); + // Drag the window to new poistion by adding (180, 16) to original point, + // the window should get restored. + resizer->Drag(CalculateDragPoint(*resizer, 180, 16), 0); + resizer->RevertDrag(); + EXPECT_EQ("0,0 1000x1000", window_->bounds().ToString()); + EXPECT_EQ("96,112 320x160", + GetRestoreBoundsInScreen(window_.get())->ToString()); +} + } // namespace internal } // namespace ash |