blob: 8b9805f5daf98f4f227b2e562ef17a6d13cce9a4 [file] [log] [blame]
// 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