1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/single_split_view.h"
7 #include "base/logging.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "ui/events/event_utils.h"
10 #include "ui/views/controls/single_split_view_listener.h"
14 static void VerifySplitViewLayout(const views::SingleSplitView
& split
) {
15 ASSERT_EQ(2, split
.child_count());
17 const views::View
* leading
= split
.child_at(0);
18 const views::View
* trailing
= split
.child_at(1);
20 if (split
.bounds().IsEmpty()) {
21 EXPECT_TRUE(leading
->bounds().IsEmpty());
22 EXPECT_TRUE(trailing
->bounds().IsEmpty());
26 EXPECT_FALSE(leading
->bounds().IsEmpty());
27 EXPECT_FALSE(trailing
->bounds().IsEmpty());
28 EXPECT_FALSE(leading
->bounds().Intersects(trailing
->bounds()));
30 if (split
.orientation() == views::SingleSplitView::HORIZONTAL_SPLIT
) {
31 EXPECT_EQ(leading
->bounds().height(), split
.bounds().height());
32 EXPECT_EQ(trailing
->bounds().height(), split
.bounds().height());
33 EXPECT_LT(leading
->bounds().width() + trailing
->bounds().width(),
34 split
.bounds().width());
35 } else if (split
.orientation() == views::SingleSplitView::VERTICAL_SPLIT
) {
36 EXPECT_EQ(leading
->bounds().width(), split
.bounds().width());
37 EXPECT_EQ(trailing
->bounds().width(), split
.bounds().width());
38 EXPECT_LT(leading
->bounds().height() + trailing
->bounds().height(),
39 split
.bounds().height());
45 class SingleSplitViewListenerImpl
: public views::SingleSplitViewListener
{
47 SingleSplitViewListenerImpl() : count_(0) {}
49 bool SplitHandleMoved(views::SingleSplitView
* sender
) override
{
54 int count() const { return count_
; }
59 DISALLOW_COPY_AND_ASSIGN(SingleSplitViewListenerImpl
);
62 class MinimumSizedView
: public views::View
{
64 MinimumSizedView(gfx::Size min_size
) : min_size_(min_size
) {}
68 gfx::Size
GetMinimumSize() const override
;
71 gfx::Size
MinimumSizedView::GetMinimumSize() const {
79 TEST(SingleSplitViewTest
, Resize
) {
80 // Test cases to iterate through for horizontal and vertical split views.
82 // Split view resize policy for this test case.
83 bool resize_leading_on_bounds_change
;
84 // Split view size to set.
85 int primary_axis_size
;
86 int secondary_axis_size
;
87 // Expected divider offset.
90 // The initial split size is 100x100, divider at 33.
91 { true, 100, 100, 33 },
92 // Grow the split view, leading view should grow.
93 { true, 1000, 100, 933 },
94 // Shrink the split view, leading view should shrink.
95 { true, 200, 100, 133 },
96 // Minimize the split view, divider should not move.
98 // Restore the split view, divider should not move.
99 { false, 500, 100, 133 },
100 // Resize the split view by secondary axis, divider should not move.
101 { false, 500, 600, 133 }
104 SingleSplitView::Orientation orientations
[] = {
105 SingleSplitView::HORIZONTAL_SPLIT
,
106 SingleSplitView::VERTICAL_SPLIT
109 for (size_t orientation
= 0; orientation
< arraysize(orientations
);
111 // Create a split view.
112 SingleSplitView
split(
113 new View(), new View(), orientations
[orientation
], NULL
);
115 // Set initial size and divider offset.
116 EXPECT_EQ(test_cases
[0].primary_axis_size
,
117 test_cases
[0].secondary_axis_size
);
118 split
.SetBounds(0, 0, test_cases
[0].primary_axis_size
,
119 test_cases
[0].secondary_axis_size
);
120 split
.set_divider_offset(test_cases
[0].divider_offset
);
123 // Run all test cases.
124 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
125 split
.set_resize_leading_on_bounds_change(
126 test_cases
[i
].resize_leading_on_bounds_change
);
127 if (split
.orientation() == SingleSplitView::HORIZONTAL_SPLIT
) {
128 split
.SetBounds(0, 0, test_cases
[i
].primary_axis_size
,
129 test_cases
[i
].secondary_axis_size
);
131 split
.SetBounds(0, 0, test_cases
[i
].secondary_axis_size
,
132 test_cases
[i
].primary_axis_size
);
135 EXPECT_EQ(test_cases
[i
].divider_offset
, split
.divider_offset());
136 VerifySplitViewLayout(split
);
139 // Special cases, one of the child views is hidden.
140 split
.child_at(0)->SetVisible(false);
143 EXPECT_EQ(split
.size(), split
.child_at(1)->size());
145 split
.child_at(0)->SetVisible(true);
146 split
.child_at(1)->SetVisible(false);
149 EXPECT_EQ(split
.size(), split
.child_at(0)->size());
153 TEST(SingleSplitViewTest
, MouseDrag
) {
154 const int kMinimumChildSize
= 25;
155 MinimumSizedView
*child0
=
156 new MinimumSizedView(gfx::Size(5, kMinimumChildSize
));
157 MinimumSizedView
*child1
=
158 new MinimumSizedView(gfx::Size(5, kMinimumChildSize
));
159 SingleSplitViewListenerImpl listener
;
160 SingleSplitView
split(
161 child0
, child1
, SingleSplitView::VERTICAL_SPLIT
, &listener
);
163 const int kTotalSplitSize
= 100;
164 split
.SetBounds(0, 0, 10, kTotalSplitSize
);
165 const int kInitialDividerOffset
= 33;
166 const int kMouseOffset
= 2; // Mouse offset in the divider.
167 const int kMouseMoveDelta
= 7;
168 split
.set_divider_offset(kInitialDividerOffset
);
171 gfx::Point
press_point(7, kInitialDividerOffset
+ kMouseOffset
);
172 ui::MouseEvent
mouse_pressed(ui::ET_MOUSE_PRESSED
, press_point
, press_point
,
173 ui::EventTimeForNow(), 0, 0);
174 ASSERT_TRUE(split
.OnMousePressed(mouse_pressed
));
175 EXPECT_EQ(kInitialDividerOffset
, split
.divider_offset());
176 EXPECT_EQ(0, listener
.count());
178 // Drag divider to the bottom.
179 gfx::Point
drag_1_point(
180 5, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
);
181 ui::MouseEvent
mouse_dragged_1(ui::ET_MOUSE_DRAGGED
, drag_1_point
,
182 drag_1_point
, ui::EventTimeForNow(), 0, 0);
183 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_1
));
184 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
, split
.divider_offset());
185 EXPECT_EQ(1, listener
.count());
187 // Drag divider to the top, beyond first child minimum size.
188 gfx::Point
drag_2_point(
189 7, kMinimumChildSize
- 5);
190 ui::MouseEvent
mouse_dragged_2(ui::ET_MOUSE_DRAGGED
, drag_2_point
,
191 drag_2_point
, ui::EventTimeForNow(), 0, 0);
192 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_2
));
193 EXPECT_EQ(kMinimumChildSize
, split
.divider_offset());
194 EXPECT_EQ(2, listener
.count());
196 // Drag divider to the bottom, beyond second child minimum size.
197 gfx::Point
drag_3_point(
198 7, kTotalSplitSize
- kMinimumChildSize
+ 5);
199 ui::MouseEvent
mouse_dragged_3(ui::ET_MOUSE_DRAGGED
, drag_3_point
,
200 drag_3_point
, ui::EventTimeForNow(), 0, 0);
201 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_3
));
202 EXPECT_EQ(kTotalSplitSize
- kMinimumChildSize
- split
.GetDividerSize(),
203 split
.divider_offset());
204 EXPECT_EQ(3, listener
.count());
206 // Drag divider between childs' minimum sizes.
207 gfx::Point
drag_4_point(
208 6, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
* 2);
209 ui::MouseEvent
mouse_dragged_4(ui::ET_MOUSE_DRAGGED
, drag_4_point
,
210 drag_4_point
, ui::EventTimeForNow(), 0, 0);
211 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_4
));
212 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
* 2,
213 split
.divider_offset());
214 EXPECT_EQ(4, listener
.count());
216 gfx::Point
release_point(
217 7, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
* 2);
218 ui::MouseEvent
mouse_released(ui::ET_MOUSE_RELEASED
, release_point
,
219 release_point
, ui::EventTimeForNow(), 0, 0);
220 split
.OnMouseReleased(mouse_released
);
221 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
* 2,
222 split
.divider_offset());
224 // Expect intial offset after a system/user gesture cancels the drag.
225 // This shouldn't occur after mouse release, but it's sufficient for testing.
226 split
.OnMouseCaptureLost();
227 EXPECT_EQ(kInitialDividerOffset
, split
.divider_offset());
228 EXPECT_EQ(5, listener
.count());