summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
Diffstat (limited to 'views')
-rw-r--r--views/box_layout.cc66
-rw-r--r--views/box_layout.h50
-rw-r--r--views/box_layout_unittest.cc108
-rw-r--r--views/examples/box_layout.cc37
-rw-r--r--views/examples/box_layout.h40
-rw-r--r--views/examples/widget_example.h10
-rw-r--r--views/views.gyp4
7 files changed, 232 insertions, 83 deletions
diff --git a/views/box_layout.cc b/views/box_layout.cc
new file mode 100644
index 0000000..84fb096
--- /dev/null
+++ b/views/box_layout.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/box_layout.h"
+
+namespace views {
+
+BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
+ int inside_border_spacing,
+ int between_child_spacing)
+ : orientation_(orientation),
+ inside_border_spacing_(inside_border_spacing),
+ between_child_spacing_(between_child_spacing) {
+}
+
+void BoxLayout::Layout(View* host) {
+ gfx::Rect childArea(gfx::Rect(host->size()));
+ childArea.Inset(host->GetInsets());
+ childArea.Inset(inside_border_spacing_, inside_border_spacing_);
+ int x = childArea.x();
+ int y = childArea.y();
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* child = host->GetChildViewAt(i);
+ if (child->IsVisible()) {
+ gfx::Rect bounds(x, y, childArea.width(), childArea.height());
+ gfx::Size size(child->GetPreferredSize());
+ if (orientation_ == kHorizontal) {
+ bounds.set_width(size.width());
+ x += size.width() + between_child_spacing_;
+ } else {
+ bounds.set_height(size.height());
+ y += size.height() + between_child_spacing_;
+ }
+ // Clamp child view bounds to |childArea|.
+ child->SetBounds(bounds.Intersect(childArea));
+ }
+ }
+}
+
+gfx::Size BoxLayout::GetPreferredSize(View* host) {
+ gfx::Rect bounds;
+ int position = 0;
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* child = host->GetChildViewAt(i);
+ if (child->IsVisible()) {
+ gfx::Size size(child->GetPreferredSize());
+ if (orientation_ == kHorizontal) {
+ gfx::Rect child_bounds(position, 0, size.width(), size.height());
+ bounds = bounds.Union(child_bounds);
+ position += size.width();
+ } else {
+ gfx::Rect child_bounds(0, position, size.width(), size.height());
+ bounds = bounds.Union(child_bounds);
+ position += size.height();
+ }
+ position += between_child_spacing_;
+ }
+ }
+ gfx::Insets insets(host->GetInsets());
+ return
+ gfx::Size(bounds.width() + insets.width() + 2 * inside_border_spacing_,
+ bounds.height() + insets.height() + 2 * inside_border_spacing_);
+}
+
+} // namespace views
diff --git a/views/box_layout.h b/views/box_layout.h
new file mode 100644
index 0000000..332be47
--- /dev/null
+++ b/views/box_layout.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_BOX_LAYOUT_H_
+#define VIEWS_BOX_LAYOUT_H_
+
+#include "base/basictypes.h"
+#include "views/layout_manager.h"
+
+namespace views {
+
+// A Layout manager that arranges child views vertically or horizontally in a
+// side-by-side fashion with spacing around and between the child views. The
+// child views are always sized according to their preferred size. If the
+// host's bounds provide insufficient space, child views will be clamped.
+// Excess space will not be distributed.
+class BoxLayout : public LayoutManager {
+ public:
+ enum Orientation {
+ kHorizontal,
+ kVertical,
+ };
+
+ // Use |inside_border_spacing| to add additional space between the child view
+ // area and the host view border. |between_child_spacing| controls the space
+ // in between child views.
+ BoxLayout(Orientation orientation,
+ int inside_border_spacing,
+ int between_child_spacing);
+ virtual ~BoxLayout() {}
+
+ // Overridden from views::LayoutManager:
+ virtual void Layout(View* host);
+ virtual gfx::Size GetPreferredSize(View* host);
+
+ private:
+ const Orientation orientation_;
+
+ // Spacing between child views and host view border.
+ const int inside_border_spacing_;
+ // Spacing to put in between child views.
+ const int between_child_spacing_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BoxLayout);
+};
+
+} // namespace views
+
+#endif // VIEWS_BOX_LAYOUT_H_
diff --git a/views/box_layout_unittest.cc b/views/box_layout_unittest.cc
new file mode 100644
index 0000000..712b2ef
--- /dev/null
+++ b/views/box_layout_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/box_layout.h"
+#include "views/view.h"
+
+class StaticSizedView : public views::View {
+ public:
+ explicit StaticSizedView(const gfx::Size& size)
+ : size_(size) { }
+
+ virtual gfx::Size GetPreferredSize() {
+ return size_;
+ }
+
+ private:
+ gfx::Size size_;
+};
+
+class BoxLayoutTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ host_.reset(new views::View);
+ }
+
+ scoped_ptr<views::View> host_;
+ scoped_ptr<views::BoxLayout> layout_;
+};
+
+TEST_F(BoxLayoutTest, Empty) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 10, 20));
+ EXPECT_EQ(gfx::Size(20, 20), layout_->GetPreferredSize(host_.get()));
+}
+
+TEST_F(BoxLayoutTest, AlignmentHorizontal) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0));
+ views::View* v1 = new StaticSizedView(gfx::Size(10, 20));
+ host_->AddChildView(v1);
+ views::View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+ EXPECT_EQ(gfx::Size(20, 20), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 20, 20);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 20), v1->bounds());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 20), v2->bounds());
+}
+
+TEST_F(BoxLayoutTest, AlignmentVertical) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0));
+ views::View* v1 = new StaticSizedView(gfx::Size(20, 10));
+ host_->AddChildView(v1);
+ views::View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+ EXPECT_EQ(gfx::Size(20, 20), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 20, 20);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 20, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 10, 20, 10), v2->bounds());
+}
+
+TEST_F(BoxLayoutTest, Spacing) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 7, 8));
+ views::View* v1 = new StaticSizedView(gfx::Size(10, 20));
+ host_->AddChildView(v1);
+ views::View* v2 = new StaticSizedView(gfx::Size(10, 20));
+ host_->AddChildView(v2);
+ EXPECT_EQ(gfx::Size(42, 34), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 100, 100);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(7, 7, 10, 86), v1->bounds());
+ EXPECT_EQ(gfx::Rect(25, 7, 10, 86), v2->bounds());
+}
+
+TEST_F(BoxLayoutTest, Overflow) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0));
+ views::View* v1 = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(v1);
+ views::View* v2 = new StaticSizedView(gfx::Size(10, 20));
+ host_->AddChildView(v2);
+ host_->SetBounds(0, 0, 10, 10);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+}
+
+TEST_F(BoxLayoutTest, NoSpace) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 10, 10));
+ views::View* childView = new StaticSizedView(gfx::Size(20, 20));
+ host_->AddChildView(childView);
+ host_->SetBounds(0, 0, 10, 10);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), childView->bounds());
+}
+
+TEST_F(BoxLayoutTest, InvisibleChild) {
+ layout_.reset(new views::BoxLayout(views::BoxLayout::kHorizontal, 10, 10));
+ views::View* v1 = new StaticSizedView(gfx::Size(20, 20));
+ v1->SetVisible(false);
+ host_->AddChildView(v1);
+ views::View* v2 = new StaticSizedView(gfx::Size(10, 10));
+ host_->AddChildView(v2);
+ EXPECT_EQ(gfx::Size(30, 30), layout_->GetPreferredSize(host_.get()));
+ host_->SetBounds(0, 0, 30, 30);
+ layout_->Layout(host_.get());
+ EXPECT_EQ(gfx::Rect(10, 10, 10, 10), v2->bounds());
+}
diff --git a/views/examples/box_layout.cc b/views/examples/box_layout.cc
deleted file mode 100644
index 957d0d6..0000000
--- a/views/examples/box_layout.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/examples/box_layout.h"
-
-namespace examples {
-
-BoxLayout::BoxLayout(Orientation orientation, int margin)
- : orientation_(orientation),
- margin_(margin) {
-}
-
-void BoxLayout::Layout(views::View* host) {
- int height = host->height();
- int width = host->width();
- int count = host->GetChildViewCount();
-
- int z = 0;
- for (int i = 0; i < count; ++i) {
- views::View* child = host->GetChildViewAt(i);
-
- if (orientation_ == kVertical) {
- child->SetBounds(0, z, width, height / count);
- z = (height + margin_) * (i + 1) / count;
- } else if (orientation_ == kHorizontal) {
- child->SetBounds(z, 0, width / count, height);
- z = (width + margin_) * (i + 1) / count;
- }
- }
-}
-
-gfx::Size BoxLayout::GetPreferredSize(views::View* host) {
- return gfx::Size();
-}
-
-} // namespace examples
diff --git a/views/examples/box_layout.h b/views/examples/box_layout.h
deleted file mode 100644
index 2e802aa..0000000
--- a/views/examples/box_layout.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef VIEWS_EXAMPLES_BOX_LAYOUT_H_
-#define VIEWS_EXAMPLES_BOX_LAYOUT_H_
-
-#include "views/layout_manager.h"
-
-namespace examples {
-
-// A layout manager that layouts child views vertically or horizontally.
-class BoxLayout : public views::LayoutManager {
- public:
- enum Orientation {
- kHorizontal,
- kVertical,
- };
-
- BoxLayout(Orientation orientation, int margin);
-
- virtual ~BoxLayout() {}
-
- // Overridden from views::LayoutManager:
- virtual void Layout(views::View* host);
-
- virtual gfx::Size GetPreferredSize(views::View* host);
-
- private:
- const Orientation orientation_;
-
- // The pixel distance between children.
- const int margin_;
-
- DISALLOW_COPY_AND_ASSIGN(BoxLayout);
-};
-
-} // namespace examples
-
-#endif // VIEWS_EXAMPLES_BOX_LAYOUT_H_
diff --git a/views/examples/widget_example.h b/views/examples/widget_example.h
index 4fff3e2..9208a1b 100644
--- a/views/examples/widget_example.h
+++ b/views/examples/widget_example.h
@@ -6,8 +6,8 @@
#define VIEWS_EXAMPLES_WIDGET_EXAMPLE_H_
#include "views/background.h"
+#include "views/box_layout.h"
#include "views/controls/button/text_button.h"
-#include "views/examples/box_layout.h"
#include "views/examples/example_base.h"
#include "views/view.h"
#include "views/widget/root_view.h"
@@ -59,14 +59,16 @@ class WidgetExample : public ExampleBase, public views::ButtonListener {
virtual std::wstring GetExampleTitle() { return L"Widget"; }
virtual void CreateExampleView(views::View* container) {
- container->SetLayoutManager(new BoxLayout(BoxLayout::kHorizontal, 2));
+ container->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 2));
BuildButton(container, L"Create a popup widget", POPUP);
BuildButton(container, L"Create a transparent popup widget",
TRANSPARENT_POPUP);
#if defined(OS_LINUX)
views::View* vert_container = new views::View();
container->AddChildView(vert_container);
- vert_container->SetLayoutManager(new BoxLayout(BoxLayout::kVertical, 20));
+ vert_container->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 20));
BuildButton(vert_container, L"Create a child widget", CHILD);
BuildButton(vert_container, L"Create a transparent child widget",
TRANSPARENT_CHILD);
@@ -100,7 +102,7 @@ class WidgetExample : public ExampleBase, public views::ButtonListener {
views::View* button_container = new views::View();
button_container->SetLayoutManager(
- new BoxLayout(BoxLayout::kHorizontal, 1));
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 1));
button_container->AddChildView(close_button);
button_container->AddChildView(native_button);
diff --git a/views/views.gyp b/views/views.gyp
index 0193383..3ee4096 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -61,6 +61,8 @@
'background.h',
'border.cc',
'border.h',
+ 'box_layout.h',
+ 'box_layout.cc',
'controls/button/button.cc',
'controls/button/button.h',
'controls/button/button_dropdown.cc',
@@ -383,8 +385,6 @@
'..',
],
'sources': [
- 'examples/box_layout.cc',
- 'examples/box_layout.h',
'examples/button_example.h',
'examples/combobox_example.h',
'examples/example_base.cc',