Commit 490183da authored by Dana Fried's avatar Dana Fried Committed by Commit Bot

Create generalization for layout manager examples.

Will be used in a followup CL to simplify making examples for a new
layout manager without having to duplicate a bunch of code.

Change-Id: I3a37dc1656f70015170434c9da80ccbc20c1db88
Reviewed-on: https://chromium-review.googlesource.com/c/1351968Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611825}
parent 64c46f8f
...@@ -33,6 +33,8 @@ jumbo_component("views_examples_lib") { ...@@ -33,6 +33,8 @@ jumbo_component("views_examples_lib") {
"examples_window.h", "examples_window.h",
"label_example.cc", "label_example.cc",
"label_example.h", "label_example.h",
"layout_example_base.cc",
"layout_example_base.h",
"link_example.cc", "link_example.cc",
"link_example.h", "link_example.h",
"menu_example.cc", "menu_example.cc",
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "box_layout_example.h" #include "ui/views/examples/box_layout_example.h"
#include <vector> #include <memory>
#include <utility>
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -23,337 +24,46 @@ ...@@ -23,337 +24,46 @@
#include "ui/views/examples/example_combobox_model.h" #include "ui/views/examples/example_combobox_model.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/view_properties.h"
namespace views { namespace views {
namespace examples { namespace examples {
namespace { BoxLayoutExample::BoxLayoutExample() : LayoutExampleBase("Box Layout") {}
// 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, gfx::Size preferred_size);
~ChildPanel() override {}
// View
gfx::Size CalculatePreferredSize() 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];
gfx::Size preferred_size_;
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, gfx::Size preferred_size)
: View(), example_(example), preferred_size_(preferred_size) {
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::CalculatePreferredSize() const {
return preferred_size_;
}
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->SetDefaultWidthInChars(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 int kChildPanelWidth = 180;
const int kChildPanelHeight = 90;
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() {} BoxLayoutExample::~BoxLayoutExample() {}
Combobox* BoxLayoutExample::CreateCombobox(const base::string16& label_text, void BoxLayoutExample::CreateAdditionalControls(int vertical_pos) {
const char** items, static const char* orientation_values[2] = {"Horizontal", "Vertical"};
int count, static const char* main_axis_values[3] = {"Start", "Center", "End"};
int& vertical_pos) { static const char* cross_axis_values[4] = {"Stretch", "Start", "Center",
Label* label = new Label(label_text); "End"};
label->SetPosition(gfx::Point(kPadding, vertical_pos));
label->SizeToPreferredSize();
Combobox* combo_box =
new Combobox(std::make_unique<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->SetDefaultWidthInChars(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;
}
gfx::Size BoxLayoutExample::GetChildPanelSize() const {
int width;
int height;
if (!base::StringToInt(child_panel_size_[0]->text(), &width))
width = kChildPanelWidth;
if (!base::StringToInt(child_panel_size_[1]->text(), &height))
height = kChildPanelHeight;
return gfx::Size(std::max(0, width), std::max(0, height));
}
void BoxLayoutExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<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;
int horizontal_pos = kPadding;
add_button_ =
MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
add_button_->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
add_button_->SizeToPreferredSize();
control_panel_->AddChildView(add_button_);
horizontal_pos += add_button_->width() + kSpacing;
for (unsigned i = 0;
i < sizeof(child_panel_size_) / sizeof(child_panel_size_[0]); ++i) {
child_panel_size_[i] =
CreateRawTextfield(horizontal_pos, vertical_pos, true);
child_panel_size_[i]->SetY(
vertical_pos +
(add_button_->height() - child_panel_size_[i]->height()) / 2);
}
child_panel_size_[0]->SetText(base::IntToString16(kChildPanelWidth));
child_panel_size_[1]->SetText(base::IntToString16(kChildPanelHeight));
vertical_pos += add_button_->height() + kSpacing;
orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"), orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
orientation_values, 2, vertical_pos); orientation_values, 2, &vertical_pos);
main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"), main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
main_axis_values, 3, vertical_pos); main_axis_values, 3, &vertical_pos);
cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"), cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
cross_axis_values, 4, vertical_pos); cross_axis_values, 4, &vertical_pos);
between_child_spacing_ = between_child_spacing_ =
CreateTextfield(base::ASCIIToUTF16("Child spacing"), vertical_pos); CreateTextfield(base::ASCIIToUTF16("Child spacing"), &vertical_pos);
default_flex_ = default_flex_ =
CreateTextfield(base::ASCIIToUTF16("Default flex"), vertical_pos); CreateTextfield(base::ASCIIToUTF16("Default flex"), &vertical_pos);
min_cross_axis_size_ = min_cross_axis_size_ =
CreateTextfield(base::ASCIIToUTF16("Min cross axis"), vertical_pos); CreateTextfield(base::ASCIIToUTF16("Min cross axis"), &vertical_pos);
border_insets_[0] = CreateMarginsTextFields(base::ASCIIToUTF16("Insets"), border_insets_,
CreateTextfield(base::ASCIIToUTF16("Insets"), vertical_pos); &vertical_pos);
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_ = collapse_margins_ =
new Checkbox(base::ASCIIToUTF16("Collapse margins"), this); CreateCheckbox(base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
collapse_margins_->SetPosition(gfx::Point(kPadding, vertical_pos));
collapse_margins_->SizeToPreferredSize();
control_panel_->AddChildView(collapse_margins_);
UpdateLayoutManager(); UpdateLayoutManager();
} }
void BoxLayoutExample::ButtonPressed(Button* sender, const ui::Event& event) { void BoxLayoutExample::ButtonPressedImpl(Button* sender) {
if (sender == add_button_) { if (sender == collapse_margins_) {
if (panel_count_ < kMaxPanels) { RefreshLayoutPanel(true);
++panel_count_;
ChildPanel* panel = new ChildPanel(this, GetChildPanelSize());
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();
} }
} }
...@@ -368,7 +78,7 @@ void BoxLayoutExample::OnPerformAction(Combobox* combobox) { ...@@ -368,7 +78,7 @@ void BoxLayoutExample::OnPerformAction(Combobox* combobox) {
static_cast<BoxLayout::CrossAxisAlignment>( static_cast<BoxLayout::CrossAxisAlignment>(
cross_axis_alignment_->selected_index())); cross_axis_alignment_->selected_index()));
} }
RefreshLayoutPanel(); RefreshLayoutPanel(false);
} }
void BoxLayoutExample::ContentsChanged(Textfield* textfield, void BoxLayoutExample::ContentsChanged(Textfield* textfield,
...@@ -387,21 +97,11 @@ void BoxLayoutExample::ContentsChanged(Textfield* textfield, ...@@ -387,21 +97,11 @@ void BoxLayoutExample::ContentsChanged(Textfield* textfield,
textfield == border_insets_[2] || textfield == border_insets_[3]) { textfield == border_insets_[2] || textfield == border_insets_[3]) {
UpdateBorderInsets(); UpdateBorderInsets();
} }
RefreshLayoutPanel(); RefreshLayoutPanel(false);
}
void BoxLayoutExample::RefreshLayoutPanel() {
box_layout_panel_->Layout();
box_layout_panel_->SchedulePaint();
} }
void BoxLayoutExample::UpdateBorderInsets() { void BoxLayoutExample::UpdateBorderInsets() {
int inset_values[4]; layout_->set_inside_border_insets(TextfieldsToInsets(border_insets_));
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() { void BoxLayoutExample::UpdateLayoutManager() {
...@@ -421,16 +121,16 @@ void BoxLayoutExample::UpdateLayoutManager() { ...@@ -421,16 +121,16 @@ void BoxLayoutExample::UpdateLayoutManager() {
main_axis_alignment_->selected_index())); main_axis_alignment_->selected_index()));
layout->SetDefaultFlex(default_flex); layout->SetDefaultFlex(default_flex);
layout->set_minimum_cross_axis_size(min_cross_size); layout->set_minimum_cross_axis_size(min_cross_size);
layout_ = box_layout_panel_->SetLayoutManager(std::move(layout)); View* const panel = layout_panel();
layout_ = panel->SetLayoutManager(std::move(layout));
UpdateBorderInsets(); UpdateBorderInsets();
for (int i = 0; i < box_layout_panel_->child_count(); ++i) { for (int i = 0; i < panel->child_count(); ++i) {
ChildPanel* panel = ChildPanel* child_panel = static_cast<ChildPanel*>(panel->child_at(i));
static_cast<ChildPanel*>(box_layout_panel_->child_at(i)); int flex = child_panel->GetFlex();
int flex = panel->GetFlex();
if (flex < 0) if (flex < 0)
layout_->ClearFlexForView(panel); layout_->ClearFlexForView(child_panel);
else else
layout_->SetFlexForView(panel, flex); layout_->SetFlexForView(child_panel, flex);
} }
} }
......
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h" #include "ui/views/examples/layout_example_base.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/examples/example_base.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
namespace views { namespace views {
...@@ -21,26 +19,14 @@ class Textfield; ...@@ -21,26 +19,14 @@ class Textfield;
namespace examples { namespace examples {
namespace { class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public LayoutExampleBase {
class ChildPanel;
}
class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
public ButtonListener,
public ComboboxListener,
public TextfieldController {
public: public:
BoxLayoutExample(); BoxLayoutExample();
~BoxLayoutExample() override; ~BoxLayoutExample() override;
// ExampleBase
void CreateExampleView(View* container) override;
private: private:
friend views::examples::ChildPanel; // Set the border insets on the current BoxLayout instance.
// ButtonListener void UpdateBorderInsets();
void ButtonPressed(Button* sender, const ui::Event& event) override;
// ComboboxListener // ComboboxListener
void OnPerformAction(Combobox* combobox) override; void OnPerformAction(Combobox* combobox) override;
...@@ -49,45 +35,12 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase, ...@@ -49,45 +35,12 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
void ContentsChanged(Textfield* sender, void ContentsChanged(Textfield* sender,
const base::string16& new_contents) override; const base::string16& new_contents) override;
// Force the box_layout_panel_ to layout and repaint. // LayoutExampleBase
void RefreshLayoutPanel(); void ButtonPressedImpl(Button* sender) override;
void CreateAdditionalControls(int vertical_start_pos) override;
// Set the border insets on the current BoxLayout instance. void UpdateLayoutManager() override;
void UpdateBorderInsets();
// Create a new BoxLayout and ensure all settings match the current state of
// the various control_panel_ controls.
void UpdateLayoutManager();
// Create a Combobox with a label with |label_text| to the left. Adjust
// |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
Combobox* CreateCombobox(const base::string16& label_text,
const char** items,
int count,
int& vertical_pos);
// Create just a Textfield at the current position of |horizontal_pos| and
// |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
// text_field->width() + kSpacing.
Textfield* CreateRawTextfield(int& horizontal_pos,
int vertical_pos,
bool add);
// Create a Textfield with a label with |label_text| to the left. Adjust
// |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
Textfield* CreateTextfield(const base::string16& label_text,
int& vertical_pos);
// Returns the current values contained in the child_panel_size_[] Textfields
// as a gfx::Size. If either value is negative or not a valid integer,
// default values are returned, 180 x 90 for width and height, respectively.
gfx::Size GetChildPanelSize() const;
BoxLayout* layout_ = nullptr; BoxLayout* layout_ = nullptr;
View* full_panel_ = nullptr;
View* box_layout_panel_ = nullptr;
View* control_panel_ = nullptr;
LabelButton* add_button_ = nullptr;
Combobox* orientation_ = nullptr; Combobox* orientation_ = nullptr;
Combobox* main_axis_alignment_ = nullptr; Combobox* main_axis_alignment_ = nullptr;
Combobox* cross_axis_alignment_ = nullptr; Combobox* cross_axis_alignment_ = nullptr;
...@@ -95,9 +48,7 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase, ...@@ -95,9 +48,7 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
Textfield* default_flex_ = nullptr; Textfield* default_flex_ = nullptr;
Textfield* min_cross_axis_size_ = nullptr; Textfield* min_cross_axis_size_ = nullptr;
Textfield* border_insets_[4] = {nullptr, nullptr, nullptr, nullptr}; Textfield* border_insets_[4] = {nullptr, nullptr, nullptr, nullptr};
Textfield* child_panel_size_[2] = {nullptr, nullptr};
Checkbox* collapse_margins_ = nullptr; Checkbox* collapse_margins_ = nullptr;
int panel_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(BoxLayoutExample); DISALLOW_COPY_AND_ASSIGN(BoxLayoutExample);
}; };
......
// Copyright 2018 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 "ui/views/examples/layout_example_base.h"
#include <algorithm>
#include <memory>
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.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/textfield/textfield.h"
#include "ui/views/examples/example_combobox_model.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view_properties.h"
namespace views {
namespace examples {
namespace {
constexpr int kLayoutExampleVerticalSpacing = 3;
constexpr int kLayoutExampleLeftPadding = 8;
constexpr gfx::Size kLayoutExampleDefaultChildSize(180, 90);
// 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);
};
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());
}
} // namespace
LayoutExampleBase::ChildPanel::ChildPanel(LayoutExampleBase* example,
const gfx::Size& preferred_size)
: View(), example_(example), preferred_size_(preferred_size) {
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(""));
}
LayoutExampleBase::ChildPanel::~ChildPanel() = default;
gfx::Size LayoutExampleBase::ChildPanel::CalculatePreferredSize() const {
return preferred_size_;
}
bool LayoutExampleBase::ChildPanel::OnMousePressed(
const ui::MouseEvent& event) {
if (event.IsOnlyLeftMouseButton())
SetSelected(true);
return true;
}
void LayoutExampleBase::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 LayoutExampleBase::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(false);
}
}
int LayoutExampleBase::ChildPanel::GetFlex() {
int flex;
if (base::StringToInt(flex_->text(), &flex))
return flex;
return -1;
}
void LayoutExampleBase::ChildPanel::ContentsChanged(
Textfield* sender,
const base::string16& new_contents) {
const gfx::Insets margins = LayoutExampleBase::TextfieldsToInsets(margin_);
if (!margins.IsEmpty())
this->SetProperty(kMarginsKey, new gfx::Insets(margins));
else
this->ClearProperty(kMarginsKey);
example_->RefreshLayoutPanel(sender == flex_);
}
Textfield* LayoutExampleBase::ChildPanel::CreateTextfield() {
Textfield* textfield = new Textfield();
textfield->SetDefaultWidthInChars(3);
textfield->SizeToPreferredSize();
textfield->SetText(base::ASCIIToUTF16("0"));
textfield->set_controller(this);
textfield->SetVisible(false);
AddChildView(textfield);
return textfield;
}
LayoutExampleBase::LayoutExampleBase(const char* title) : ExampleBase(title) {}
LayoutExampleBase::~LayoutExampleBase() {}
Combobox* LayoutExampleBase::CreateCombobox(const base::string16& label_text,
const char* const* items,
int count,
int* vertical_pos) {
Label* label = new Label(label_text);
label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
label->SizeToPreferredSize();
Combobox* combo_box =
new Combobox(std::make_unique<ExampleComboboxModel>(items, count));
combo_box->SetPosition(
gfx::Point(label->x() + label->width() + kLayoutExampleVerticalSpacing,
*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() + kLayoutExampleVerticalSpacing;
return combo_box;
}
Textfield* LayoutExampleBase::CreateRawTextfield(int vertical_pos,
bool add,
int* horizontal_pos) {
Textfield* text_field = new Textfield();
text_field->SetPosition(gfx::Point(*horizontal_pos, vertical_pos));
text_field->SetDefaultWidthInChars(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() + kLayoutExampleVerticalSpacing;
if (add)
control_panel_->AddChildView(text_field);
return text_field;
}
Textfield* LayoutExampleBase::CreateTextfield(const base::string16& label_text,
int* vertical_pos) {
Label* label = new Label(label_text);
label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
label->SizeToPreferredSize();
int horizontal_pos =
label->x() + label->width() + kLayoutExampleVerticalSpacing;
Textfield* text_field =
CreateRawTextfield(*vertical_pos, false, &horizontal_pos);
label->SetSize(gfx::Size(label->width(), text_field->height()));
control_panel_->AddChildView(label);
control_panel_->AddChildView(text_field);
*vertical_pos += text_field->height() + kLayoutExampleVerticalSpacing;
return text_field;
}
void LayoutExampleBase::CreateMarginsTextFields(
const base::string16& label_text,
Textfield* textfields[4],
int* vertical_pos) {
textfields[0] = CreateTextfield(label_text, vertical_pos);
int center = textfields[0]->x() + textfields[0]->width() / 2;
int horizontal_pos = std::max(
0, center - (textfields[0]->width() + kLayoutExampleVerticalSpacing / 2));
textfields[1] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
textfields[3] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
*vertical_pos = textfields[1]->y() + textfields[1]->height() +
kLayoutExampleVerticalSpacing;
horizontal_pos = textfields[0]->x();
textfields[2] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
*vertical_pos = textfields[2]->y() + textfields[2]->height() +
kLayoutExampleVerticalSpacing;
}
Checkbox* LayoutExampleBase::CreateCheckbox(const base::string16& label_text,
int* vertical_pos) {
Checkbox* checkbox = new Checkbox(label_text, this);
checkbox->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
checkbox->SizeToPreferredSize();
control_panel_->AddChildView(checkbox);
*vertical_pos += checkbox->height() + kLayoutExampleVerticalSpacing;
return checkbox;
}
void LayoutExampleBase::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<FillLayout>());
full_panel_ = new FullPanel();
container->AddChildView(full_panel_);
layout_panel_ = new View();
layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
full_panel_->AddChildView(layout_panel_);
control_panel_ = new View();
full_panel_->AddChildView(control_panel_);
int vertical_pos = kLayoutExampleVerticalSpacing;
int horizontal_pos = kLayoutExampleLeftPadding;
add_button_ =
MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
add_button_->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
add_button_->SizeToPreferredSize();
control_panel_->AddChildView(add_button_);
horizontal_pos += add_button_->width() + kLayoutExampleVerticalSpacing;
for (unsigned i = 0;
i < sizeof(child_panel_size_) / sizeof(child_panel_size_[0]); ++i) {
child_panel_size_[i] =
CreateRawTextfield(vertical_pos, true, &horizontal_pos);
child_panel_size_[i]->SetY(
vertical_pos +
(add_button_->height() - child_panel_size_[i]->height()) / 2);
}
child_panel_size_[0]->SetText(
base::IntToString16(kLayoutExampleDefaultChildSize.width()));
child_panel_size_[1]->SetText(
base::IntToString16(kLayoutExampleDefaultChildSize.height()));
CreateAdditionalControls(add_button_->y() + add_button_->height() +
kLayoutExampleVerticalSpacing);
}
void LayoutExampleBase::ButtonPressed(Button* sender, const ui::Event& event) {
constexpr int kMaxPanels = 5;
constexpr int kChildPanelGroup = 100;
if (sender == add_button_) {
if (panel_count_ < kMaxPanels) {
++panel_count_;
ChildPanel* panel = new ChildPanel(
this,
TextfieldsToSize(child_panel_size_, kLayoutExampleDefaultChildSize));
panel->SetGroup(kChildPanelGroup);
layout_panel_->AddChildView(panel);
RefreshLayoutPanel(false);
} else {
PrintStatus("Only %i panels may be added", kMaxPanels);
}
} else {
ButtonPressedImpl(sender);
}
}
// Default implementation is to do nothing.
void LayoutExampleBase::ButtonPressedImpl(Button* sender) {}
void LayoutExampleBase::RefreshLayoutPanel(bool update_layout) {
if (update_layout)
UpdateLayoutManager();
layout_panel_->Layout();
layout_panel_->SchedulePaint();
}
gfx::Size LayoutExampleBase::TextfieldsToSize(Textfield* textfields[2],
const gfx::Size& default_size) {
int width;
int height;
if (!base::StringToInt(textfields[0]->text(), &width))
width = default_size.width();
if (!base::StringToInt(textfields[1]->text(), &height))
height = default_size.height();
return gfx::Size(std::max(0, width), std::max(0, height));
}
gfx::Insets LayoutExampleBase::TextfieldsToInsets(
Textfield* textfields[4],
const gfx::Insets& default_insets) {
int top;
int left;
int bottom;
int right;
if (!base::StringToInt(textfields[0]->text(), &top))
top = default_insets.top();
if (!base::StringToInt(textfields[1]->text(), &left))
left = default_insets.left();
if (!base::StringToInt(textfields[2]->text(), &bottom))
bottom = default_insets.bottom();
if (!base::StringToInt(textfields[3]->text(), &right))
right = default_insets.right();
return gfx::Insets(std::max(0, top), std::max(0, left), std::max(0, bottom),
std::max(0, right));
}
} // namespace examples
} // namespace views
// Copyright 2018 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 UI_VIEWS_EXAMPLES_LAYOUT_EXAMPLE_BASE_H_
#define UI_VIEWS_EXAMPLES_LAYOUT_EXAMPLE_BASE_H_
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/examples/example_base.h"
#include "ui/views/view.h"
namespace views {
namespace examples {
// Provides an example of a layout manager with arbitrary specific manager and
// controls. Lays out a sequence of ChildPanels in a view using the layout
// manager of choice.
class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
public ButtonListener,
public ComboboxListener,
public TextfieldController {
public:
// 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:
ChildPanel(LayoutExampleBase* example, const gfx::Size& preferred_size);
~ChildPanel() override;
// View
gfx::Size CalculatePreferredSize() 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();
LayoutExampleBase* example_;
bool selected_ = false;
Textfield* flex_;
Textfield* margin_[4];
gfx::Size preferred_size_;
DISALLOW_COPY_AND_ASSIGN(ChildPanel);
};
explicit LayoutExampleBase(const char* title);
~LayoutExampleBase() override;
// Force the box_layout_panel_ to layout and repaint.
void RefreshLayoutPanel(bool update_layout);
static gfx::Size TextfieldsToSize(
Textfield* textfields[2],
const gfx::Size& default_size = gfx::Size());
static gfx::Insets TextfieldsToInsets(
Textfield* textfields[4],
const gfx::Insets& default_insets = gfx::Insets());
protected:
View* layout_panel() { return layout_panel_; }
// Creates a Combobox with a label with |label_text| to the left. Adjust
// |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
Combobox* CreateCombobox(const base::string16& label_text,
const char* const* items,
int count,
int* vertical_pos);
// Creates just a Textfield at the current position of |horizontal_pos| and
// |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
// text_field->width() + kSpacing.
Textfield* CreateRawTextfield(int vertical_pos,
bool add,
int* horizontal_pos);
// Creates a Textfield with a label with |label_text| to the left. Adjust
// |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
Textfield* CreateTextfield(const base::string16& label_text,
int* vertical_pos);
// Creates a set of labeled Textfields with |label_text|, and four text fields
// arranged at compass points representing a set of insets. |vertical_pos| is
// updated to the bottom of the last Textfield + kSpacing, and |textfields| is
// populated with the fieds that are created.
void CreateMarginsTextFields(const base::string16& label_text,
Textfield* textfields[4],
int* vertical_pos);
// Creates a Checkbox with label |label_text|. Adjust |vertical_pos| to
// |vertical_pos| + checkbox->height() + kSpacing.
Checkbox* CreateCheckbox(const base::string16& label_text, int* vertical_pos);
// ButtonListener:
// Be sure to call LayoutExampleBase::ButtonPressed() to ensure the "add"
// button works correctly.
void ButtonPressed(Button* sender, const ui::Event& event) final;
// ExampleBase:
// Be sure to call LayoutExampleBase::CreateExampleView() to ensure default
// controls are created correctly.
void CreateExampleView(View* container) final;
// Called by CreateExampleView() to create any additional controls required by
// the specific layout. |vertical_start_pos| tells the control where to start
// placing new controls (i.e. the bottom of the existing common controls).
virtual void CreateAdditionalControls(int vertical_start_pos) = 0;
// Handles buttons added by derived classes after button handling for
// common controls is done.
virtual void ButtonPressedImpl(Button* sender);
// Performs layout-specific update of the layout manager.
virtual void UpdateLayoutManager() = 0;
private:
View* full_panel_ = nullptr;
View* layout_panel_ = nullptr;
View* control_panel_ = nullptr;
LabelButton* add_button_ = nullptr;
Textfield* child_panel_size_[2] = {nullptr, nullptr};
int panel_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(LayoutExampleBase);
};
} // namespace examples
} // namespace views
#endif // UI_VIEWS_EXAMPLES_LAYOUT_EXAMPLE_BASE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment