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/views/controls/single_split_view_listener.h"
13 static void VerifySplitViewLayout(const views::SingleSplitView
& split
) {
14 ASSERT_EQ(2, split
.child_count());
16 const views::View
* leading
= split
.child_at(0);
17 const views::View
* trailing
= split
.child_at(1);
19 if (split
.bounds().IsEmpty()) {
20 EXPECT_TRUE(leading
->bounds().IsEmpty());
21 EXPECT_TRUE(trailing
->bounds().IsEmpty());
25 EXPECT_FALSE(leading
->bounds().IsEmpty());
26 EXPECT_FALSE(trailing
->bounds().IsEmpty());
27 EXPECT_FALSE(leading
->bounds().Intersects(trailing
->bounds()));
29 if (split
.orientation() == views::SingleSplitView::HORIZONTAL_SPLIT
) {
30 EXPECT_EQ(leading
->bounds().height(), split
.bounds().height());
31 EXPECT_EQ(trailing
->bounds().height(), split
.bounds().height());
32 EXPECT_LT(leading
->bounds().width() + trailing
->bounds().width(),
33 split
.bounds().width());
34 } else if (split
.orientation() == views::SingleSplitView::VERTICAL_SPLIT
) {
35 EXPECT_EQ(leading
->bounds().width(), split
.bounds().width());
36 EXPECT_EQ(trailing
->bounds().width(), split
.bounds().width());
37 EXPECT_LT(leading
->bounds().height() + trailing
->bounds().height(),
38 split
.bounds().height());
44 class SingleSplitViewListenerImpl
: public views::SingleSplitViewListener
{
46 SingleSplitViewListenerImpl() : count_(0) {}
48 virtual bool SplitHandleMoved(views::SingleSplitView
* sender
) OVERRIDE
{
53 int count() const { return count_
; }
58 DISALLOW_COPY_AND_ASSIGN(SingleSplitViewListenerImpl
);
61 class MinimumSizedView
: public views::View
{
63 MinimumSizedView(gfx::Size min_size
) : min_size_(min_size
) {}
67 virtual gfx::Size
GetMinimumSize() const OVERRIDE
;
70 gfx::Size
MinimumSizedView::GetMinimumSize() const {
78 TEST(SingleSplitViewTest
, Resize
) {
79 // Test cases to iterate through for horizontal and vertical split views.
81 // Split view resize policy for this test case.
82 bool resize_leading_on_bounds_change
;
83 // Split view size to set.
84 int primary_axis_size
;
85 int secondary_axis_size
;
86 // Expected divider offset.
89 // The initial split size is 100x100, divider at 33.
90 { true, 100, 100, 33 },
91 // Grow the split view, leading view should grow.
92 { true, 1000, 100, 933 },
93 // Shrink the split view, leading view should shrink.
94 { true, 200, 100, 133 },
95 // Minimize the split view, divider should not move.
97 // Restore the split view, divider should not move.
98 { false, 500, 100, 133 },
99 // Resize the split view by secondary axis, divider should not move.
100 { false, 500, 600, 133 }
103 SingleSplitView::Orientation orientations
[] = {
104 SingleSplitView::HORIZONTAL_SPLIT
,
105 SingleSplitView::VERTICAL_SPLIT
108 for (size_t orientation
= 0; orientation
< arraysize(orientations
);
110 // Create a split view.
111 SingleSplitView
split(
112 new View(), new View(), orientations
[orientation
], NULL
);
114 // Set initial size and divider offset.
115 EXPECT_EQ(test_cases
[0].primary_axis_size
,
116 test_cases
[0].secondary_axis_size
);
117 split
.SetBounds(0, 0, test_cases
[0].primary_axis_size
,
118 test_cases
[0].secondary_axis_size
);
119 split
.set_divider_offset(test_cases
[0].divider_offset
);
122 // Run all test cases.
123 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
124 split
.set_resize_leading_on_bounds_change(
125 test_cases
[i
].resize_leading_on_bounds_change
);
126 if (split
.orientation() == SingleSplitView::HORIZONTAL_SPLIT
) {
127 split
.SetBounds(0, 0, test_cases
[i
].primary_axis_size
,
128 test_cases
[i
].secondary_axis_size
);
130 split
.SetBounds(0, 0, test_cases
[i
].secondary_axis_size
,
131 test_cases
[i
].primary_axis_size
);
134 EXPECT_EQ(test_cases
[i
].divider_offset
, split
.divider_offset());
135 VerifySplitViewLayout(split
);
138 // Special cases, one of the child views is hidden.
139 split
.child_at(0)->SetVisible(false);
142 EXPECT_EQ(split
.size(), split
.child_at(1)->size());
144 split
.child_at(0)->SetVisible(true);
145 split
.child_at(1)->SetVisible(false);
148 EXPECT_EQ(split
.size(), split
.child_at(0)->size());
152 TEST(SingleSplitViewTest
, MouseDrag
) {
153 const int kMinimumChildSize
= 25;
154 MinimumSizedView
*child0
=
155 new MinimumSizedView(gfx::Size(5, kMinimumChildSize
));
156 MinimumSizedView
*child1
=
157 new MinimumSizedView(gfx::Size(5, kMinimumChildSize
));
158 SingleSplitViewListenerImpl listener
;
159 SingleSplitView
split(
160 child0
, child1
, SingleSplitView::VERTICAL_SPLIT
, &listener
);
162 const int kTotalSplitSize
= 100;
163 split
.SetBounds(0, 0, 10, kTotalSplitSize
);
164 const int kInitialDividerOffset
= 33;
165 const int kMouseOffset
= 2; // Mouse offset in the divider.
166 const int kMouseMoveDelta
= 7;
167 split
.set_divider_offset(kInitialDividerOffset
);
170 gfx::Point
press_point(7, kInitialDividerOffset
+ kMouseOffset
);
171 ui::MouseEvent
mouse_pressed(
172 ui::ET_MOUSE_PRESSED
, press_point
, press_point
, 0, 0);
173 ASSERT_TRUE(split
.OnMousePressed(mouse_pressed
));
174 EXPECT_EQ(kInitialDividerOffset
, split
.divider_offset());
175 EXPECT_EQ(0, listener
.count());
177 // Drag divider to the bottom.
178 gfx::Point
drag_1_point(
179 5, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
);
180 ui::MouseEvent
mouse_dragged_1(
181 ui::ET_MOUSE_DRAGGED
, drag_1_point
, drag_1_point
, 0, 0);
182 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_1
));
183 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
, split
.divider_offset());
184 EXPECT_EQ(1, listener
.count());
186 // Drag divider to the top, beyond first child minimum size.
187 gfx::Point
drag_2_point(
188 7, kMinimumChildSize
- 5);
189 ui::MouseEvent
mouse_dragged_2(
190 ui::ET_MOUSE_DRAGGED
, drag_2_point
, drag_2_point
, 0,0 );
191 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_2
));
192 EXPECT_EQ(kMinimumChildSize
, split
.divider_offset());
193 EXPECT_EQ(2, listener
.count());
195 // Drag divider to the bottom, beyond second child minimum size.
196 gfx::Point
drag_3_point(
197 7, kTotalSplitSize
- kMinimumChildSize
+ 5);
198 ui::MouseEvent
mouse_dragged_3(
199 ui::ET_MOUSE_DRAGGED
, drag_3_point
, drag_3_point
, 0, 0);
200 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_3
));
201 EXPECT_EQ(kTotalSplitSize
- kMinimumChildSize
- split
.GetDividerSize(),
202 split
.divider_offset());
203 EXPECT_EQ(3, listener
.count());
205 // Drag divider between childs' minimum sizes.
206 gfx::Point
drag_4_point(
207 6, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
* 2);
208 ui::MouseEvent
mouse_dragged_4(
209 ui::ET_MOUSE_DRAGGED
, drag_4_point
, drag_4_point
, 0, 0);
210 ASSERT_TRUE(split
.OnMouseDragged(mouse_dragged_4
));
211 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
* 2,
212 split
.divider_offset());
213 EXPECT_EQ(4, listener
.count());
215 gfx::Point
release_point(
216 7, kInitialDividerOffset
+ kMouseOffset
+ kMouseMoveDelta
* 2);
217 ui::MouseEvent
mouse_released(
218 ui::ET_MOUSE_RELEASED
, release_point
, release_point
, 0, 0);
219 split
.OnMouseReleased(mouse_released
);
220 EXPECT_EQ(kInitialDividerOffset
+ kMouseMoveDelta
* 2,
221 split
.divider_offset());
223 // Expect intial offset after a system/user gesture cancels the drag.
224 // This shouldn't occur after mouse release, but it's sufficient for testing.
225 split
.OnMouseCaptureLost();
226 EXPECT_EQ(kInitialDividerOffset
, split
.divider_offset());
227 EXPECT_EQ(5, listener
.count());