Commit d1d13295 authored by MinChen's avatar MinChen Committed by Commit Bot

Don't allow the window be snapped to a position that is smaller than its minimum size.

Changes:
1. Update the optional divider ratios (0.33f, 0.67f) according to the minimum size of
   the snapped windows.
2. Show the black scrim when the divider passes over the window's minimum size.

Test: SplitViewControllerTest.DividerPositionWithWindowMinimumSizeTest
Bug: 775227
Change-Id: Ia7ca6b42639a2e8963d5bfb95eb449e520f048fa
Reviewed-on: https://chromium-review.googlesource.com/735980
Commit-Queue: min c <minch@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#513222}
parent 7ac572d1
...@@ -31,20 +31,14 @@ namespace ash { ...@@ -31,20 +31,14 @@ namespace ash {
namespace { namespace {
// Five fixed position ratios of the divider. // Three fixed position ratios of the divider, which means the divider can
constexpr float kFixedPositionRatios[] = {0.0f, 0.33f, 0.5f, 0.67f, 1.0f}; // always be moved to these three positions.
constexpr float kFixedPositionRatios[] = {0.f, 0.5f, 1.0f};
float FindClosestFixedPositionRatio(float distance, float length) { // Two optional position ratios of the divider. Whether the divider can be moved
float current_ratio = distance / length; // to these two positions depends on the minimum size of the snapped windows.
float closest_ratio = 0.f; constexpr float kOneThirdPositionRatio = 0.33f;
for (float ratio : kFixedPositionRatios) { constexpr float kTwoThirdPositionRatio = 0.67f;
if (std::abs(current_ratio - ratio) <
std::abs(current_ratio - closest_ratio)) {
closest_ratio = ratio;
}
}
return closest_ratio;
}
gfx::Point GetBoundedPosition(const gfx::Point& location_in_screen, gfx::Point GetBoundedPosition(const gfx::Point& location_in_screen,
const gfx::Rect& bounds_in_screen) { const gfx::Rect& bounds_in_screen) {
...@@ -608,41 +602,53 @@ void SplitViewController::UpdateSnappedWindowsAndDividerBounds() { ...@@ -608,41 +602,53 @@ void SplitViewController::UpdateSnappedWindowsAndDividerBounds() {
SplitViewController::SnapPosition SplitViewController::GetBlackScrimPosition( SplitViewController::SnapPosition SplitViewController::GetBlackScrimPosition(
const gfx::Point& location_in_screen) { const gfx::Point& location_in_screen) {
SnapPosition position = SplitViewController::NONE;
const gfx::Rect work_area_bounds = const gfx::Rect work_area_bounds =
GetDisplayWorkAreaBoundsInScreen(GetDefaultSnappedWindow()); GetDisplayWorkAreaBoundsInScreen(GetDefaultSnappedWindow());
if (!work_area_bounds.Contains(location_in_screen)) if (!work_area_bounds.Contains(location_in_screen))
return position; return NONE;
switch (screen_orientation_) { gfx::Size left_window_min_size, right_window_min_size;
case blink::kWebScreenOrientationLockLandscapePrimary: if (left_window_ && left_window_->delegate())
case blink::kWebScreenOrientationLockLandscapeSecondary: left_window_min_size = left_window_->delegate()->GetMinimumSize();
if (location_in_screen.x() < if (right_window_ && right_window_->delegate())
work_area_bounds.x() + right_window_min_size = right_window_->delegate()->GetMinimumSize();
work_area_bounds.width() * kFixedPositionRatios[1]) {
position = IsCurrentScreenOrientationPrimary() ? LEFT : RIGHT; bool is_primary = IsCurrentScreenOrientationPrimary();
} else if (location_in_screen.x() > int long_length = GetDividerEndPosition();
work_area_bounds.x() + // The distance from the current resizing position to the left or right side
work_area_bounds.width() * kFixedPositionRatios[3]) { // of the screen. Note: left or right side here means the side of the
position = IsCurrentScreenOrientationPrimary() ? RIGHT : LEFT; // |left_window_| or |right_window_|.
} int left_window_distance = 0, right_window_distance = 0;
break; int min_left_length = 0, min_right_length = 0;
case blink::kWebScreenOrientationLockPortraitPrimary:
case blink::kWebScreenOrientationLockPortraitSecondary: if (IsCurrentScreenOrientationLandscape()) {
if (location_in_screen.y() > int left_distance = location_in_screen.x() - work_area_bounds.x();
work_area_bounds.y() + int right_distance = work_area_bounds.right() - location_in_screen.x();
work_area_bounds.height() * kFixedPositionRatios[3]) { left_window_distance = is_primary ? left_distance : right_distance;
position = IsCurrentScreenOrientationPrimary() ? LEFT : RIGHT; right_window_distance = is_primary ? right_distance : left_distance;
} else if (location_in_screen.y() <
work_area_bounds.y() + min_left_length = left_window_min_size.width();
work_area_bounds.height() * kFixedPositionRatios[1]) { min_right_length = right_window_min_size.width();
position = IsCurrentScreenOrientationPrimary() ? RIGHT : LEFT; } else {
} int top_distance = location_in_screen.y() - work_area_bounds.y();
break; int bottom_distance = work_area_bounds.bottom() - location_in_screen.y();
default: left_window_distance = is_primary ? bottom_distance : top_distance;
break; right_window_distance = is_primary ? top_distance : bottom_distance;
min_left_length = left_window_min_size.height();
min_right_length = right_window_min_size.height();
} }
return position;
if (left_window_distance < long_length * kOneThirdPositionRatio ||
left_window_distance < min_left_length) {
return LEFT;
}
if (right_window_distance < long_length * kOneThirdPositionRatio ||
right_window_distance < min_right_length) {
return RIGHT;
}
return NONE;
} }
void SplitViewController::UpdateDividerPosition( void SplitViewController::UpdateDividerPosition(
...@@ -699,11 +705,25 @@ void SplitViewController::MoveDividerToClosestFixedPosition() { ...@@ -699,11 +705,25 @@ void SplitViewController::MoveDividerToClosestFixedPosition() {
// extract the center from |divider_position_|. The result will also be the // extract the center from |divider_position_|. The result will also be the
// center of the divider, so extract the origin, unless the result is on of // center of the divider, so extract the origin, unless the result is on of
// the endpoints. // the endpoints.
float ratio = FindClosestFixedPositionRatio( float divider_distance =
divider_position_ + std::floor(divider_thickness / 2.f), divider_position_ + std::floor(divider_thickness / 2.f);
GetDividerEndPosition());
divider_position_ = std::floor(GetDividerEndPosition() * ratio); int work_area_long_length = GetDividerEndPosition();
if (ratio > 0.f && ratio < 1.f) float current_ratio = divider_distance / work_area_long_length;
float closest_ratio = 0.f;
std::vector<float> position_ratios(
kFixedPositionRatios,
kFixedPositionRatios + sizeof(kFixedPositionRatios) / sizeof(float));
GetDividerOptionalPositionRatios(position_ratios);
for (float ratio : position_ratios) {
if (std::abs(current_ratio - ratio) <
std::abs(current_ratio - closest_ratio)) {
closest_ratio = ratio;
}
}
divider_position_ = std::floor(work_area_long_length * closest_ratio);
if (closest_ratio > 0.f && closest_ratio < 1.f)
divider_position_ -= std::floor(divider_thickness / 2.f); divider_position_ -= std::floor(divider_thickness / 2.f);
} }
...@@ -790,4 +810,34 @@ void SplitViewController::AdjustLeftOrTopSnappedWindowBoundsDuringResizing( ...@@ -790,4 +810,34 @@ void SplitViewController::AdjustLeftOrTopSnappedWindowBoundsDuringResizing(
TransposeRect(left_or_top_rect); TransposeRect(left_or_top_rect);
} }
void SplitViewController::GetDividerOptionalPositionRatios(
std::vector<float>& position_ratios) {
bool is_left_or_top = IsLeftWindowOnTopOrLeftOfScreen(screen_orientation_);
aura::Window* left_or_top_window =
is_left_or_top ? left_window_ : right_window_;
aura::Window* right_or_bottom_window =
is_left_or_top ? right_window_ : left_window_;
bool is_landscape = IsCurrentScreenOrientationLandscape();
int long_length = GetDividerEndPosition();
float min_size_left_ratio = 0.f, min_size_right_ratio = 0.f;
int min_left_size = 0, min_right_size = 0;
if (left_or_top_window && left_or_top_window->delegate()) {
gfx::Size min_size = left_or_top_window->delegate()->GetMinimumSize();
min_left_size = is_landscape ? min_size.width() : min_size.height();
}
if (right_or_bottom_window && right_or_bottom_window->delegate()) {
gfx::Size min_size = right_or_bottom_window->delegate()->GetMinimumSize();
min_right_size = is_landscape ? min_size.width() : min_size.height();
}
min_size_left_ratio = static_cast<float>(min_left_size) / long_length;
min_size_right_ratio = static_cast<float>(min_right_size) / long_length;
if (min_size_left_ratio <= kOneThirdPositionRatio)
position_ratios.push_back(kOneThirdPositionRatio);
if (min_size_right_ratio <= kOneThirdPositionRatio)
position_ratios.push_back(kTwoThirdPositionRatio);
}
} // namespace ash } // namespace ash
...@@ -215,6 +215,12 @@ class ASH_EXPORT SplitViewController : public aura::WindowObserver, ...@@ -215,6 +215,12 @@ class ASH_EXPORT SplitViewController : public aura::WindowObserver,
void AdjustLeftOrTopSnappedWindowBoundsDuringResizing( void AdjustLeftOrTopSnappedWindowBoundsDuringResizing(
gfx::Rect* left_or_top_rect); gfx::Rect* left_or_top_rect);
// Gets the divider optional position ratios. The divider can always be
// moved to the positions in |kFixedPositionRatios|. Whether the divider can
// be moved to |kOneThirdPositionRatio| or |kTwoThirdPositionRatio| depends
// on the minimum size of current snapped windows.
void GetDividerOptionalPositionRatios(std::vector<float>& positionRatios);
// The current left/right snapped window. // The current left/right snapped window.
aura::Window* left_window_ = nullptr; aura::Window* left_window_ = nullptr;
aura::Window* right_window_ = nullptr; aura::Window* right_window_ = nullptr;
......
...@@ -84,6 +84,12 @@ class SplitViewControllerTest : public AshTestBase { ...@@ -84,6 +84,12 @@ class SplitViewControllerTest : public AshTestBase {
return split_view_controller()->split_view_divider(); return split_view_controller()->split_view_divider();
} }
blink::WebScreenOrientationLockType screen_orientation() {
return split_view_controller()->screen_orientation();
}
int divider_position() { return split_view_controller()->divider_position(); }
private: private:
class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate { class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate {
public: public:
...@@ -959,4 +965,87 @@ TEST_F(SplitViewControllerTest, SnapWindowBoundsWithMinimumSizeTest) { ...@@ -959,4 +965,87 @@ TEST_F(SplitViewControllerTest, SnapWindowBoundsWithMinimumSizeTest) {
EndSplitView(); EndSplitView();
} }
// Tests that if a snapped window's minumum size is larger than one third but
// smaller than half of the work area's longer side. The divider should be
// snapped to a position that is larger than the window's minimum size.
TEST_F(SplitViewControllerTest, DividerPositionWithWindowMinimumSizeTest) {
const gfx::Rect bounds(0, 0, 200, 200);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
aura::test::TestWindowDelegate* delegate1 =
static_cast<aura::test::TestWindowDelegate*>(window1->delegate());
ui::test::EventGenerator& generator(GetEventGenerator());
EXPECT_EQ(blink::kWebScreenOrientationLockLandscapePrimary,
screen_orientation());
gfx::Rect workarea_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
// Snap the divider to one third position when there is only left window with
// minimum size larger than one third of the display's width. The divider
// should be snapped to the middle position after dragging.
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
delegate1->set_minimum_size(
gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
gfx::Rect divider_bounds =
split_view_divider()->GetDividerBoundsInScreen(false);
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
// Snap the divider to two third position, it should be kept at there after
// dragging.
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
EXPECT_GT(divider_position(), 0.5f * workarea_bounds.width());
EXPECT_LE(divider_position(), 0.67f * workarea_bounds.width());
EndSplitView();
// Snap the divider to two third position when there is only right window with
// minium size larger than one third of the display's width. The divider
// should be snapped to the middle position after dragging.
delegate1->set_minimum_size(
gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
split_view_controller()->SnapWindow(window1.get(),
SplitViewController::RIGHT);
divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
// Snap the divider to one third position, it should be kept at there after
// dragging.
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
EXPECT_GT(divider_position(), 0);
EXPECT_LE(divider_position(), 0.33f * workarea_bounds.width());
EndSplitView();
// Snap the divider to one third position when there are both left and right
// snapped windows with the same minimum size larger than one third of the
// display's width. The divider should be snapped to the middle position after
// dragging.
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
aura::test::TestWindowDelegate* delegate2 =
static_cast<aura::test::TestWindowDelegate*>(window2->delegate());
delegate2->set_minimum_size(
gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller()->SnapWindow(window2.get(),
SplitViewController::RIGHT);
divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
// Snap the divider to two third position, it should be snapped to the middle
// position after dragging.
generator.set_current_location(divider_bounds.CenterPoint());
generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
EndSplitView();
}
} // namespace ash } // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment