| 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..6ecf28a0ea407e04ef49071651e8454dae07da8a
|
| --- /dev/null
|
| +++ b/ui/views/examples/box_layout_example.cc
|
| @@ -0,0 +1,412 @@
|
| +// Copyright 2017 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 "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 "base/strings/utf_string_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/examples/example_combobox_model.h"
|
| +#include "ui/views/layout/fill_layout.h"
|
| +#include "ui/views/view.h"
|
| +
|
| +namespace views {
|
| +namespace examples {
|
| +
|
| +namespace {
|
| +
|
| +// This View holds two other views which consists of a view on the left onto
|
| +// which the BoxLayout is attached for demonstrating its features. The view
|
| +// on the right contains all the various controls which allow the user to
|
| +// interactively control the various features/properties of BoxLayout. Layout()
|
| +// will ensure the left view takes 75% and the right view fills the remaining
|
| +// 25%.
|
| +class FullPanel : public View {
|
| + public:
|
| + FullPanel() {}
|
| + ~FullPanel() override {}
|
| +
|
| + // View
|
| + void Layout() override;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(FullPanel);
|
| +};
|
| +
|
| +// This view is created and added to the left-side view in the FullPanel each
|
| +// time the "Add" button is pressed. It also will display Textfield controls
|
| +// when the mouse is pressed over the view. These Textfields allow the user to
|
| +// interactively set each margin and the "flex" for the given view.
|
| +class ChildPanel : public View, public TextfieldController {
|
| + public:
|
| + explicit ChildPanel(BoxLayoutExample* example);
|
| + ~ChildPanel() override {}
|
| +
|
| + // View
|
| + gfx::Size GetPreferredSize() const override;
|
| + bool OnMousePressed(const ui::MouseEvent& event) override;
|
| + void Layout() override;
|
| +
|
| + 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;
|
| + Textfield* flex_;
|
| + Textfield* margin_[4];
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ChildPanel);
|
| +};
|
| +
|
| +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(base::ASCIIToUTF16(""));
|
| +}
|
| +
|
| +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);
|
| + }
|
| + }
|
| + }
|
| + 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(base::ASCIIToUTF16("0"));
|
| + textfield->set_controller(this);
|
| + textfield->SetVisible(false);
|
| + AddChildView(textfield);
|
| + return textfield;
|
| +}
|
| +
|
| +const int kSpacing = 3;
|
| +const int kPadding = 8;
|
| +const int kMaxPanels = 5;
|
| +const int kChildPanelGroup = 100;
|
| +const char* orientation_values[2] = {"Horizontal", "Vertical"};
|
| +const char* main_axis_values[3] = {"Start", "Center", "End"};
|
| +const char* cross_axis_values[4] = {"Stretch", "Start", "Center", "End"};
|
| +}
|
| +
|
| +BoxLayoutExample::BoxLayoutExample() : ExampleBase("Box Layout") {}
|
| +
|
| +BoxLayoutExample::~BoxLayoutExample() {}
|
| +
|
| +Combobox* BoxLayoutExample::CreateCombobox(const base::string16& label_text,
|
| + const char** items,
|
| + int count,
|
| + int& vertical_pos) {
|
| + Label* label = new Label(label_text);
|
| + label->SetPosition(gfx::Point(kPadding, vertical_pos));
|
| + label->SizeToPreferredSize();
|
| + Combobox* combo_box =
|
| + new Combobox(base::MakeUnique<ExampleComboboxModel>(items, count));
|
| + combo_box->SetPosition(
|
| + gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
|
| + combo_box->SizeToPreferredSize();
|
| + combo_box->set_listener(this);
|
| + label->SetSize(gfx::Size(label->width(), combo_box->height()));
|
| + control_panel_->AddChildView(label);
|
| + control_panel_->AddChildView(combo_box);
|
| + vertical_pos += combo_box->height() + kSpacing;
|
| + return combo_box;
|
| +}
|
| +
|
| +Textfield* BoxLayoutExample::CreateRawTextfield(int& horizontal_pos,
|
| + int vertical_pos,
|
| + bool add) {
|
| + Textfield* text_field = new Textfield();
|
| + text_field->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
|
| + text_field->set_default_width_in_chars(3);
|
| + text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
|
| + text_field->SizeToPreferredSize();
|
| + text_field->SetText(base::ASCIIToUTF16("0"));
|
| + text_field->set_controller(this);
|
| + horizontal_pos += text_field->width() + kSpacing;
|
| + if (add)
|
| + control_panel_->AddChildView(text_field);
|
| + return text_field;
|
| +}
|
| +
|
| +Textfield* BoxLayoutExample::CreateTextfield(const base::string16& label_text,
|
| + int& vertical_pos) {
|
| + Label* label = new Label(label_text);
|
| + label->SetPosition(gfx::Point(kPadding, vertical_pos));
|
| + label->SizeToPreferredSize();
|
| + int horizontal_pos = label->x() + label->width() + kSpacing;
|
| + Textfield* text_field =
|
| + CreateRawTextfield(horizontal_pos, vertical_pos, false);
|
| + label->SetSize(gfx::Size(label->width(), text_field->height()));
|
| + control_panel_->AddChildView(label);
|
| + control_panel_->AddChildView(text_field);
|
| + vertical_pos += text_field->height() + kSpacing;
|
| + return text_field;
|
| +}
|
| +
|
| +void BoxLayoutExample::CreateExampleView(View* container) {
|
| + 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 = kSpacing;
|
| + add_button_ =
|
| + MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
|
| + add_button_->SetPosition(gfx::Point(kPadding, vertical_pos));
|
| + add_button_->SizeToPreferredSize();
|
| + control_panel_->AddChildView(add_button_);
|
| + vertical_pos += add_button_->height() + kSpacing;
|
| +
|
| + orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
|
| + orientation_values, 2, vertical_pos);
|
| + main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
|
| + main_axis_values, 3, vertical_pos);
|
| + cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
|
| + cross_axis_values, 4, vertical_pos);
|
| +
|
| + between_child_spacing_ =
|
| + CreateTextfield(base::ASCIIToUTF16("Child spacing"), vertical_pos);
|
| + default_flex_ =
|
| + CreateTextfield(base::ASCIIToUTF16("Default flex"), vertical_pos);
|
| + min_cross_axis_size_ =
|
| + CreateTextfield(base::ASCIIToUTF16("Min cross axis"), vertical_pos);
|
| +
|
| + border_insets_[0] =
|
| + CreateTextfield(base::ASCIIToUTF16("Insets"), vertical_pos);
|
| + int horizontal_pos =
|
| + border_insets_[0]->x() + border_insets_[0]->width() + kSpacing;
|
| + for (unsigned i = 1; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
|
| + ++i)
|
| + border_insets_[i] =
|
| + CreateRawTextfield(horizontal_pos, border_insets_[0]->y(), true);
|
| +
|
| + collapse_margins_ = new Checkbox(base::ASCIIToUTF16("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_ < kMaxPanels) {
|
| + ++panel_count_;
|
| + ChildPanel* panel = new ChildPanel(this);
|
| + panel->SetGroup(kChildPanelGroup);
|
| + box_layout_panel_->AddChildView(panel);
|
| + RefreshLayoutPanel();
|
| + } else {
|
| + PrintStatus("Only %i panels may be added", kMaxPanels);
|
| + }
|
| + } 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::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);
|
| + } else if (textfield == border_insets_[0] || textfield == border_insets_[1] ||
|
| + textfield == border_insets_[2] || textfield == border_insets_[3]) {
|
| + UpdateBorderInsets();
|
| + }
|
| + RefreshLayoutPanel();
|
| +}
|
| +
|
| +void BoxLayoutExample::RefreshLayoutPanel() {
|
| + box_layout_panel_->Layout();
|
| + box_layout_panel_->SchedulePaint();
|
| +}
|
| +
|
| +void BoxLayoutExample::UpdateBorderInsets() {
|
| + int inset_values[4];
|
| + for (unsigned i = 0; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
|
| + ++i)
|
| + base::StringToInt(border_insets_[i]->text(), &inset_values[i]);
|
| + layout_->set_inside_border_insets(gfx::Insets(
|
| + inset_values[0], inset_values[1], inset_values[2], inset_values[3]));
|
| +}
|
| +
|
| +void BoxLayoutExample::UpdateLayoutManager() {
|
| + int child_spacing;
|
| + int default_flex;
|
| + int min_cross_size;
|
| + base::StringToInt(between_child_spacing_->text(), &child_spacing);
|
| + 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);
|
| + UpdateBorderInsets();
|
| + 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
|
|
|