Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2933)

Unified Diff: ui/views/examples/box_layout_example.cc

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: Added margin collapsing and a BoxLayout example Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/views/examples/box_layout_example.cc
diff --git a/ui/views/examples/box_layout_example.cc b/ui/views/examples/box_layout_example.cc
new file mode 100644
index 0000000000000000000000000000000000000000..39f087a08ed6ce9d4106ce76f4fda9a44d324390
--- /dev/null
+++ b/ui/views/examples/box_layout_example.cc
@@ -0,0 +1,419 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
sky 2017/05/09 19:26:02 no (c)
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "box_layout_example.h"
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/models/combobox_model.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
+
+namespace views {
+namespace examples {
+
+namespace {
+
+class FullPanel : public View {
sky 2017/05/09 19:26:02 Please add comments for classes. This name is conf
kylix_rd 2017/05/10 15:30:36 Done.
+ public:
+ FullPanel() {}
+ ~FullPanel() override {}
+
+ void Layout() override;
sky 2017/05/09 19:26:03 Prefix with where override comes from.
kylix_rd 2017/05/10 15:30:36 Done.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FullPanel);
+};
+
+class ChildPanel : public View, public TextfieldController {
+ public:
+ ChildPanel(BoxLayoutExample* example);
sky 2017/05/09 19:26:02 explicit.
kylix_rd 2017/05/10 15:30:36 Done.
+ ~ChildPanel() override {}
+
+ // View
+ gfx::Size GetPreferredSize() const override;
+ bool OnMousePressed(const ui::MouseEvent& event) override;
+ void Layout() override;
+
+ void set_listener(ViewListener* listener) { listener_ = listener; }
+ void SetSelected(bool value);
+ bool selected() const { return selected_; };
+
+ int GetFlex();
+
+ private:
+ // TextfieldController
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+
+ Textfield* CreateTextfield();
+
+ BoxLayoutExample* example_;
+ bool selected_ = false;
+ ViewListener* listener_ = nullptr;
+ Textfield* flex_;
+ Textfield* margin_[4];
+
+ DISALLOW_COPY_AND_ASSIGN(ChildPanel);
+};
+
+class ExampleModel : public ui::ComboboxModel {
sky 2017/05/09 19:26:03 Can you use ui/views/examples/example_combobox_mod
kylix_rd 2017/05/10 15:30:36 Yep. I didn't notice it was there. Done.
+ public:
+ ExampleModel(const std::initializer_list<base::string16>& items)
+ : ui::ComboboxModel(), items_(items) {}
+ ~ExampleModel() override {}
+ // ComboboxModel
sky 2017/05/09 19:26:02 newline between 78/79.
+ int GetItemCount() const override { return items_.size(); }
+
+ base::string16 GetItemAt(int index) override { return items_[index]; }
+
+ private:
+ std::vector<base::string16> items_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExampleModel);
+};
+
+void FullPanel::Layout() {
+ DCHECK_EQ(child_count(), 2);
+ View* left_panel = child_at(0);
+ View* right_panel = child_at(1);
+ gfx::Rect bounds = GetContentsBounds();
+ left_panel->SetBounds(bounds.x(), bounds.y(), (bounds.width() * 75) / 100,
+ bounds.height());
+ right_panel->SetBounds(left_panel->width(), bounds.y(),
+ bounds.width() - left_panel->width(), bounds.height());
+}
+
+ChildPanel::ChildPanel(BoxLayoutExample* example) : View(), example_(example) {
+ SetBorder(CreateSolidBorder(1, SK_ColorGRAY));
+ for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i)
+ margin_[i] = CreateTextfield();
+ flex_ = CreateTextfield();
+ flex_->SetText(L"");
+}
+
+gfx::Size ChildPanel::GetPreferredSize() const {
+ return gfx::Size(180, 90);
+}
+
+bool ChildPanel::OnMousePressed(const ui::MouseEvent& event) {
+ if (event.IsOnlyLeftMouseButton())
+ SetSelected(true);
+ return true;
+}
+
+void ChildPanel::Layout() {
+ const int kSpacing = 2;
+ if (selected_) {
+ gfx::Rect client = GetContentsBounds();
+ for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
+ gfx::Point pos;
+ Textfield* textfield = margin_[i];
+ switch (i) {
+ case 0:
+ pos = gfx::Point((client.width() - textfield->width()) / 2, kSpacing);
+ break;
+ case 1:
+ pos =
+ gfx::Point(kSpacing, (client.height() - textfield->height()) / 2);
+ break;
+ case 2:
+ pos = gfx::Point((client.width() - textfield->width()) / 2,
+ client.height() - textfield->height() - kSpacing);
+ break;
+ case 3:
+ pos = gfx::Point(client.width() - textfield->width() - kSpacing,
+ (client.height() - textfield->height()) / 2);
+ break;
+ default:
+ NOTREACHED();
+ }
+ textfield->SetPosition(pos);
+ }
+ flex_->SetPosition(gfx::Point((client.width() - flex_->width()) / 2,
+ (client.height() - flex_->height()) / 2));
+ }
+}
+
+void ChildPanel::SetSelected(bool value) {
+ if (value != selected_) {
+ selected_ = value;
+ SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
+ if (selected_ && parent()) {
+ for (int i = 0; i < parent()->child_count(); ++i) {
+ View* child = parent()->child_at(i);
+ if (child != this && child->GetGroup() == GetGroup()) {
+ ChildPanel* child_panel = static_cast<ChildPanel*>(child);
+ child_panel->SetSelected(false);
+ }
+ }
+ if (listener_)
+ listener_->ViewSelected(this);
+ }
+ for (Textfield* textfield : margin_)
+ textfield->SetVisible(selected_);
+ flex_->SetVisible(selected_);
+ InvalidateLayout();
+ example_->RefreshLayoutPanel();
+ }
+}
+
+int ChildPanel::GetFlex() {
+ int flex;
+ if (base::StringToInt(flex_->text(), &flex))
+ return flex;
+ return -1;
+}
+
+void ChildPanel::ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) {
+ int edges[4];
+ for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
+ base::StringToInt(margin_[i]->text(), &edges[i]);
+ }
+ gfx::Insets margins = gfx::Insets(edges[0], edges[1], edges[2], edges[3]);
+ if (!margins.IsEmpty())
+ this->SetProperty(kMarginsKey, new gfx::Insets(margins));
+ else
+ this->ClearProperty(kMarginsKey);
+ if (sender == flex_)
+ example_->UpdateLayoutManager();
+ example_->RefreshLayoutPanel();
+}
+
+Textfield* ChildPanel::CreateTextfield() {
+ Textfield* textfield = new Textfield();
+ textfield->set_default_width_in_chars(3);
+ textfield->SizeToPreferredSize();
+ textfield->SetText(L"0");
+ textfield->set_controller(this);
+ textfield->SetVisible(false);
+ AddChildView(textfield);
+ return textfield;
+}
+}
+
+BoxLayoutExample::BoxLayoutExample() : ExampleBase("Box Layout") {}
+
+BoxLayoutExample::~BoxLayoutExample() {}
+
+void BoxLayoutExample::CreateExampleView(View* container) {
+ const int kSpacing = 5;
+ const int kPadding = 8;
+ container->SetLayoutManager(new FillLayout());
+ full_panel_ = new FullPanel();
+ container->AddChildView(full_panel_);
+
+ box_layout_panel_ = new View();
+ box_layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
+ full_panel_->AddChildView(box_layout_panel_);
+ control_panel_ = new View();
+ full_panel_->AddChildView(control_panel_);
+
+ int vertical_pos = kPadding;
+ add_button_ = MdTextButton::CreateSecondaryUiButton(this, L"Add");
+ add_button_->SetPosition(gfx::Point(kPadding, vertical_pos));
+ add_button_->SizeToPreferredSize();
+ control_panel_->AddChildView(add_button_);
+ vertical_pos += add_button_->height() + kSpacing;
+
+ Label* label = new Label(L"Orientation");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ orientation_ = new Combobox(base::MakeUnique<ExampleModel>(
+ std::initializer_list<base::string16>({L"Horizontal", L"Vertical"})));
+ orientation_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ orientation_->SizeToPreferredSize();
+ orientation_->set_listener(this);
+ label->SetSize(gfx::Size(label->width(), orientation_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(orientation_);
+ vertical_pos += orientation_->height() + kSpacing;
+
+ label = new Label(L"Main axis");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ main_axis_alignment_ = new Combobox(base::MakeUnique<ExampleModel>(
+ std::initializer_list<base::string16>({L"Start", L"Center", L"End"})));
+ main_axis_alignment_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ main_axis_alignment_->SizeToPreferredSize();
+ main_axis_alignment_->set_listener(this);
+ label->SetSize(gfx::Size(label->width(), main_axis_alignment_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(main_axis_alignment_);
+ vertical_pos += main_axis_alignment_->height() + kSpacing;
+
+ label = new Label(L"Cross axis");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ cross_axis_alignment_ = new Combobox(
+ base::MakeUnique<ExampleModel>(std::initializer_list<base::string16>(
+ {L"Stretch", L"Start", L"Center", L"End"})));
+ cross_axis_alignment_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ cross_axis_alignment_->SizeToPreferredSize();
+ cross_axis_alignment_->set_listener(this);
+ label->SetSize(gfx::Size(label->width(), cross_axis_alignment_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(cross_axis_alignment_);
+ vertical_pos += cross_axis_alignment_->height() + kSpacing;
+
+ label = new Label(L"Child spacing");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ between_child_spacing_ = new Textfield();
+ between_child_spacing_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ between_child_spacing_->set_default_width_in_chars(3);
+ between_child_spacing_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
+ between_child_spacing_->SizeToPreferredSize();
+ between_child_spacing_->SetText(L"0");
+ between_child_spacing_->set_controller(this);
+ label->SetSize(gfx::Size(label->width(), between_child_spacing_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(between_child_spacing_);
+ vertical_pos += between_child_spacing_->height() + kSpacing;
+
+ label = new Label(L"Default flex");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ default_flex_ = new Textfield();
+ default_flex_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ default_flex_->set_default_width_in_chars(3);
+ default_flex_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
+ default_flex_->SizeToPreferredSize();
+ default_flex_->SetText(L"0");
+ default_flex_->set_controller(this);
+ label->SetSize(gfx::Size(label->width(), default_flex_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(default_flex_);
+ vertical_pos += default_flex_->height() + kSpacing;
+
+ label = new Label(L"Min cross axis");
+ label->SetPosition(gfx::Point(kPadding, vertical_pos));
+ label->SizeToPreferredSize();
+ min_cross_axis_size_ = new Textfield();
+ min_cross_axis_size_->SetPosition(
+ gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
+ min_cross_axis_size_->set_default_width_in_chars(3);
+ min_cross_axis_size_->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
+ min_cross_axis_size_->SizeToPreferredSize();
+ min_cross_axis_size_->SetText(L"0");
+ min_cross_axis_size_->set_controller(this);
+ label->SetSize(gfx::Size(label->width(), min_cross_axis_size_->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(min_cross_axis_size_);
+ vertical_pos += min_cross_axis_size_->height() + kSpacing;
+
+ collapse_margins_ = new Checkbox(L"Collapse margins");
+ collapse_margins_->SetPosition(gfx::Point(kPadding, vertical_pos));
+ collapse_margins_->SizeToPreferredSize();
+ collapse_margins_->set_listener(this);
+ control_panel_->AddChildView(collapse_margins_);
+
+ UpdateLayoutManager();
+}
+
+void BoxLayoutExample::ButtonPressed(Button* sender, const ui::Event& event) {
+ if (sender == add_button_) {
+ if (panel_count_ < 5) {
+ ++panel_count_;
+ ChildPanel* panel = new ChildPanel(this);
+ panel->set_listener(this);
+ panel->SetGroup(100);
+ box_layout_panel_->AddChildView(panel);
+ RefreshLayoutPanel();
+ } else {
+ PrintStatus("Only 5 panels may be added");
+ }
+ } else if (sender == collapse_margins_) {
+ UpdateLayoutManager();
+ RefreshLayoutPanel();
+ }
+}
+
+void BoxLayoutExample::OnPerformAction(Combobox* combobox) {
+ if (combobox == orientation_) {
+ UpdateLayoutManager();
+ } else if (combobox == main_axis_alignment_) {
+ layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
+ main_axis_alignment_->selected_index()));
+ } else if (combobox == cross_axis_alignment_) {
+ layout_->set_cross_axis_alignment(
+ static_cast<BoxLayout::CrossAxisAlignment>(
+ cross_axis_alignment_->selected_index()));
+ }
+ RefreshLayoutPanel();
+}
+
+void BoxLayoutExample::ViewSelected(View* view) {}
+
+void BoxLayoutExample::ContentsChanged(Textfield* textfield,
+ const base::string16& new_contents) {
+ if (textfield == between_child_spacing_) {
+ UpdateLayoutManager();
+ } else if (textfield == default_flex_) {
+ int default_flex;
+ base::StringToInt(default_flex_->text(), &default_flex);
+ layout_->SetDefaultFlex(default_flex);
+ } else if (textfield == min_cross_axis_size_) {
+ int min_cross_size;
+ base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
+ layout_->set_minimum_cross_axis_size(min_cross_size);
+ }
+ RefreshLayoutPanel();
+}
+
+void BoxLayoutExample::RefreshLayoutPanel() {
+ box_layout_panel_->Layout();
+ box_layout_panel_->SchedulePaint();
+}
+
+void BoxLayoutExample::UpdateLayoutManager() {
+ int child_spacing;
+ int default_flex;
+ int min_cross_size;
+ base::StringToInt(between_child_spacing_->text(), &child_spacing);
sky 2017/05/09 19:26:03 Remember that conversion may fail and return false
kylix_rd 2017/05/09 20:07:06 According to the doc, errors will set |*output| to
+ base::StringToInt(default_flex_->text(), &default_flex);
+ base::StringToInt(min_cross_axis_size_->text(), &min_cross_size);
+ layout_ = new BoxLayout(orientation_->selected_index() == 0
+ ? BoxLayout::Orientation::kHorizontal
+ : BoxLayout::Orientation::kVertical,
+ 0, 0, child_spacing, collapse_margins_->checked());
+ layout_->set_cross_axis_alignment(static_cast<BoxLayout::CrossAxisAlignment>(
+ cross_axis_alignment_->selected_index()));
+ layout_->set_main_axis_alignment(static_cast<BoxLayout::MainAxisAlignment>(
+ main_axis_alignment_->selected_index()));
+ layout_->SetDefaultFlex(default_flex);
+ layout_->set_minimum_cross_axis_size(min_cross_size);
+ for (int i = 0; i < box_layout_panel_->child_count(); ++i) {
+ ChildPanel* panel =
+ static_cast<ChildPanel*>(box_layout_panel_->child_at(i));
+ int flex = panel->GetFlex();
+ if (flex < 0)
+ layout_->ClearFlexForView(panel);
+ else
+ layout_->SetFlexForView(panel, flex);
+ }
+ box_layout_panel_->SetLayoutManager(layout_);
+}
+
+} // namespace examples
+} // namespace views

Powered by Google App Engine
This is Rietveld 408576698