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 "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h"
9 #include "testing/gtest/include/gtest/gtest.h"
13 const int kSpacing
= 3;
14 const int kBorderWidth
= 5;
18 class GtkChromeShrinkableHBoxTest
: public testing::Test
{
20 GtkChromeShrinkableHBoxTest()
21 : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL
)),
22 box_(gtk_chrome_shrinkable_hbox_new(FALSE
, FALSE
, kSpacing
)) {
23 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_LTR
);
24 gtk_window_set_default_size(GTK_WINDOW(window_
), 200, 200);
25 gtk_container_add(GTK_CONTAINER(window_
), box_
);
26 gtk_container_set_border_width(GTK_CONTAINER(box_
), kBorderWidth
);
29 virtual ~GtkChromeShrinkableHBoxTest() {
30 gtk_widget_destroy(window_
);
33 // Add some children widgets with arbitrary width and padding.
34 void AddChildren(bool pack_start
) {
48 for (size_t i
= 0; kChildrenData
[i
].width
; ++i
) {
49 GtkWidget
* child
= gtk_fixed_new();
50 gtk_widget_set_size_request(child
, kChildrenData
[i
].width
, -1);
52 gtk_chrome_shrinkable_hbox_pack_start(
53 GTK_CHROME_SHRINKABLE_HBOX(box_
), child
, kChildrenData
[i
].padding
);
55 gtk_chrome_shrinkable_hbox_pack_end(
56 GTK_CHROME_SHRINKABLE_HBOX(box_
), child
, kChildrenData
[i
].padding
);
61 // Check if all children's size allocation are inside the |box_|'s boundary.
62 void Validate(bool pack_start
) {
63 std::vector
<ChildData
> children_data
;
64 gtk_container_foreach(GTK_CONTAINER(box_
), CollectChildData
,
67 size_t children_count
= children_data
.size();
68 size_t visible_children_count
= 0;
69 for (size_t i
= 0; i
< children_count
; ++i
) {
70 if (children_data
[i
].visible
)
71 ++visible_children_count
;
74 if (visible_children_count
== 0)
77 int border_width
= gtk_container_get_border_width(GTK_CONTAINER(box_
));
78 int x
= box_
->allocation
.x
+ border_width
;
79 int width
= box_
->allocation
.width
- border_width
* 2;
80 int spacing
= gtk_box_get_spacing(GTK_BOX(box_
));
81 bool homogeneous
= gtk_box_get_homogeneous(GTK_BOX(box_
));
84 // If the |box_| is in homogeneous mode, then check if the visible
85 // children are not overlapped with each other.
86 int homogeneous_child_width
=
87 (width
- (visible_children_count
- 1) * spacing
) /
88 visible_children_count
;
90 for (size_t i
= 0; i
< children_count
; ++i
) {
91 SCOPED_TRACE(testing::Message() << "Validate homogeneous child " << i
92 << " visible: " << children_data
[i
].visible
93 << " padding: " << children_data
[i
].padding
94 << " x: " << children_data
[i
].x
95 << " width: " << children_data
[i
].width
);
97 if (children_data
[i
].visible
)
98 ASSERT_LE(children_data
[i
].width
, homogeneous_child_width
);
101 // If the |box_| is not in homogeneous mode, then just check if all
102 // visible children are inside the |box_|'s boundary. And for those
103 // hidden children which are out of the boundary, they should only
104 // be hidden one by one from the end of the |box_|.
105 bool last_visible
= pack_start
;
106 bool visibility_changed
= false;
107 for (size_t i
= 0; i
< children_count
; ++i
) {
108 SCOPED_TRACE(testing::Message() << "Validate child " << i
109 << " visible: " << children_data
[i
].visible
110 << " padding: " << children_data
[i
].padding
111 << " x: " << children_data
[i
].x
112 << " width: " << children_data
[i
].width
);
114 if (last_visible
!= children_data
[i
].visible
) {
115 ASSERT_FALSE(visibility_changed
);
116 visibility_changed
= true;
117 last_visible
= children_data
[i
].visible
;
119 if (children_data
[i
].visible
) {
120 ASSERT_GE(children_data
[i
].x
,
121 x
+ children_data
[i
].padding
);
122 ASSERT_LE(children_data
[i
].x
+ children_data
[i
].width
,
123 x
+ width
- children_data
[i
].padding
);
129 void Test(bool pack_start
) {
130 gtk_widget_show_all(window_
);
131 GtkAllocation allocation
= { 0, 0, 0, 200 };
132 gtk_chrome_shrinkable_hbox_set_hide_child_directly(
133 GTK_CHROME_SHRINKABLE_HBOX(box_
), FALSE
);
134 for (int width
= 500; width
> kBorderWidth
* 2; --width
) {
135 SCOPED_TRACE(testing::Message() << "Shrink hide_child_directly = FALSE,"
136 << " width = " << width
);
138 allocation
.width
= width
;
139 // Reducing the width may cause some children to be hidden, which will
140 // cause queue resize, so it's necessary to do another size allocation to
141 // emulate the queue resize.
142 gtk_widget_size_allocate(box_
, &allocation
);
143 gtk_widget_size_allocate(box_
, &allocation
);
144 ASSERT_NO_FATAL_FAILURE(Validate(pack_start
)) << "width = " << width
;
147 for (int width
= kBorderWidth
* 2; width
<= 500; ++width
) {
148 SCOPED_TRACE(testing::Message() << "Expand hide_child_directly = FALSE,"
149 << " width = " << width
);
151 allocation
.width
= width
;
152 // Expanding the width may cause some invisible children to be shown,
153 // which will cause queue resize, so it's necessary to do another size
154 // allocation to emulate the queue resize.
155 gtk_widget_size_allocate(box_
, &allocation
);
156 gtk_widget_size_allocate(box_
, &allocation
);
157 ASSERT_NO_FATAL_FAILURE(Validate(pack_start
));
160 gtk_chrome_shrinkable_hbox_set_hide_child_directly(
161 GTK_CHROME_SHRINKABLE_HBOX(box_
), TRUE
);
162 for (int width
= 500; width
> kBorderWidth
* 2; --width
) {
163 SCOPED_TRACE(testing::Message() << "Shrink hide_child_directly = TRUE,"
164 << " width = " << width
);
166 allocation
.width
= width
;
167 gtk_widget_size_allocate(box_
, &allocation
);
168 gtk_widget_size_allocate(box_
, &allocation
);
169 ASSERT_NO_FATAL_FAILURE(Validate(pack_start
));
172 for (int width
= kBorderWidth
* 2; width
<= 500; ++width
) {
173 SCOPED_TRACE(testing::Message() << "Expand hide_child_directly = TRUE,"
174 << " width = " << width
);
176 allocation
.width
= width
;
177 gtk_widget_size_allocate(box_
, &allocation
);
178 gtk_widget_size_allocate(box_
, &allocation
);
179 ASSERT_NO_FATAL_FAILURE(Validate(pack_start
));
195 static void CollectChildData(GtkWidget
* child
, gpointer userdata
) {
197 gtk_box_query_child_packing(GTK_BOX(gtk_widget_get_parent(child
)), child
,
198 NULL
, NULL
, &padding
, NULL
);
201 data
.visible
= gtk_widget_get_visible(child
);
202 data
.padding
= padding
;
203 data
.x
= child
->allocation
.x
;
204 data
.width
= child
->allocation
.width
;
206 reinterpret_cast<std::vector
<ChildData
>*>(userdata
)->push_back(data
);
210 TEST_F(GtkChromeShrinkableHBoxTest
, PackStart
) {
214 SCOPED_TRACE("Test LTR");
215 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_LTR
);
216 EXPECT_NO_FATAL_FAILURE(Test(true));
219 SCOPED_TRACE("Test RTL");
220 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_RTL
);
221 EXPECT_NO_FATAL_FAILURE(Test(true));
225 TEST_F(GtkChromeShrinkableHBoxTest
, PackEnd
) {
229 SCOPED_TRACE("Test LTR");
230 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_LTR
);
231 EXPECT_NO_FATAL_FAILURE(Test(false));
234 SCOPED_TRACE("Test RTL");
235 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_RTL
);
236 EXPECT_NO_FATAL_FAILURE(Test(false));
240 TEST_F(GtkChromeShrinkableHBoxTest
, Homogeneous
) {
242 gtk_box_set_homogeneous(GTK_BOX(box_
), true);
245 SCOPED_TRACE("Test LTR");
246 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_LTR
);
247 EXPECT_NO_FATAL_FAILURE(Test(true));
250 SCOPED_TRACE("Test RTL");
251 gtk_widget_set_direction(box_
, GTK_TEXT_DIR_RTL
);
252 EXPECT_NO_FATAL_FAILURE(Test(true));