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 |