blob: fdf537e051d7893914e5daf8657d594a173f6494 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/examples/label_example.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.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/examples/examples_color_id.h"
#include "ui/views/examples/examples_themed_label.h"
#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/box_layout_view.h"
#include "ui/views/layout/table_layout.h"
#include "ui/views/view.h"
using base::ASCIIToUTF16;
namespace views::examples {
namespace {
constexpr auto kAlignments =
std::to_array<const char* const>({"Left", "Center", "Right", "Head"});
// A Label with a clamped preferred width to demonstrate eliding or wrapping.
class ExamplePreferredSizeLabel : public Label {
METADATA_HEADER(ExamplePreferredSizeLabel, Label)
public:
ExamplePreferredSizeLabel() {
SetBorder(
CreateThemedSolidBorder(1, ExamplesColorIds::kColorLabelExampleBorder));
}
ExamplePreferredSizeLabel(const ExamplePreferredSizeLabel&) = delete;
ExamplePreferredSizeLabel& operator=(const ExamplePreferredSizeLabel&) =
delete;
~ExamplePreferredSizeLabel() override = default;
// Label:
gfx::Size CalculatePreferredSize(
const SizeBounds& available_size) const override {
return gfx::Size(50,
Label::CalculatePreferredSize(available_size).height());
}
};
BEGIN_METADATA(ExamplePreferredSizeLabel)
END_METADATA
// static
constexpr auto kElideBehaviors = std::to_array<const char* const>(
{"No Elide", "Truncate", "Elide Head", "Elide Middle", "Elide Tail",
"Elide Email", "Fade Tail"});
} // namespace
LabelExample::LabelExample()
: ExampleBase(l10n_util::GetStringUTF8(IDS_LABEL_SELECT_LABEL).c_str()) {}
LabelExample::~LabelExample() {
if (textfield_) {
textfield_->set_controller(nullptr);
}
observer_.Reset();
}
void LabelExample::CreateExampleView(View* container) {
observer_.Observe(container);
// A very simple label example, followed by additional helpful examples.
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kVertical, gfx::Insets(), 10));
container->AddChildView(std::make_unique<Label>(u"Hello world!"));
const char16_t hello_world_hebrew[] =
u"\x5e9\x5dc\x5d5\x5dd \x5d4\x5e2\x5d5\x5dc\x5dd!";
auto label = std::make_unique<Label>(hello_world_hebrew);
label->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
container->AddChildView(std::move(label));
label = std::make_unique<Label>(u"A UTF16 surrogate pair: \x5d0\x5b0");
label->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
container->AddChildView(std::move(label));
auto themed_label = std::make_unique<ThemedLabel>();
themed_label->SetText(u"A left-aligned blue label.");
themed_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
themed_label->SetEnabledColorId(
ExamplesColorIds::kColorLabelExampleBlueLabel);
container->AddChildView(std::move(themed_label));
label = std::make_unique<Label>(u"Password!");
label->SetObscured(true);
container->AddChildView(std::move(label));
label = std::make_unique<Label>(u"A Courier-18 label with shadows.");
label->SetFontList(gfx::FontList("Courier, 18px"));
label_ = container->AddChildView(std::move(label));
label = std::make_unique<ExamplePreferredSizeLabel>();
label->SetText(
u"A long label will elide toward its logical end if the text's width "
u"exceeds the label's available width.");
container->AddChildView(std::move(label));
label = std::make_unique<ExamplePreferredSizeLabel>();
label->SetText(
u"A multi-line label will wrap onto subsequent lines if the text's width "
u"exceeds the label's available width, which is helpful for extemely "
u"long text used to demonstrate line wrapping.");
label->SetMultiLine(true);
container->AddChildView(std::move(label));
label = std::make_unique<Label>(u"Label with thick border");
label->SetBorder(CreateThemedSolidBorder(
20, ExamplesColorIds::kColorLabelExampleThickBorder));
container->AddChildView(std::move(label));
label = std::make_unique<Label>(
u"A multiline label...\n\n...which supports text selection");
label->SetSelectable(true);
label->SetMultiLine(true);
container->AddChildView(std::move(label));
AddCustomLabel(container);
}
void LabelExample::MultilineCheckboxPressed() {
custom_label_->SetMultiLine(multiline_->GetChecked());
}
void LabelExample::ShadowsCheckboxPressed() {
gfx::ShadowValues shadows;
if (shadows_->GetChecked()) {
auto* const cp = custom_label_->GetColorProvider();
shadows = {
gfx::ShadowValue(
gfx::Vector2d(), 1,
cp->GetColor(ExamplesColorIds::kColorLabelExampleUpperShadow)),
gfx::ShadowValue(
gfx::Vector2d(2, 2), 0,
cp->GetColor(ExamplesColorIds::kColorLabelExampleLowerShadow))};
}
custom_label_->SetShadows(shadows);
}
void LabelExample::SelectableCheckboxPressed() {
custom_label_->SetSelectable(selectable_->GetChecked());
}
void LabelExample::ContentsChanged(Textfield* sender,
const std::u16string& new_contents) {
custom_label_->SetText(new_contents);
custom_label_->parent()->parent()->InvalidateLayout();
}
void LabelExample::AddCustomLabel(View* container) {
std::unique_ptr<View> control_container = std::make_unique<View>();
control_container->SetBorder(CreateThemedSolidBorder(
2, ExamplesColorIds::kColorLabelExampleCustomBorder));
control_container->SetBackground(CreateThemedSolidBackground(
ExamplesColorIds::kColorLabelExampleCustomBackground));
control_container->SetLayoutManager(
std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical));
auto* table = control_container->AddChildView(std::make_unique<View>());
table->SetLayoutManager(std::make_unique<TableLayout>())
->AddColumn(LayoutAlignment::kStart, LayoutAlignment::kStretch,
TableLayout::kFixedSize,
TableLayout::ColumnSize::kUsePreferred, 0, 0)
.AddColumn(LayoutAlignment::kStretch, LayoutAlignment::kStretch, 1.0f,
TableLayout::ColumnSize::kUsePreferred, 0, 0)
.AddRows(3, TableLayout::kFixedSize);
Label* content_label =
table->AddChildView(std::make_unique<Label>(u"Content: "));
textfield_ = table->AddChildView(std::make_unique<Textfield>());
textfield_->SetText(
u"Use the provided controls to configure the content and presentation of "
u"this custom label.");
textfield_->SetEditableSelectionRange(gfx::Range());
textfield_->set_controller(this);
textfield_->GetViewAccessibility().SetName(*content_label);
alignment_ = AddCombobox(table, u"Alignment: ", kAlignments,
&LabelExample::AlignmentChanged);
elide_behavior_ = AddCombobox(table, u"Elide Behavior: ", kElideBehaviors,
&LabelExample::ElidingChanged);
auto* checkboxes =
control_container->AddChildView(std::make_unique<BoxLayoutView>());
multiline_ = checkboxes->AddChildView(std::make_unique<Checkbox>(
u"Multiline", base::BindRepeating(&LabelExample::MultilineCheckboxPressed,
base::Unretained(this))));
shadows_ = checkboxes->AddChildView(std::make_unique<Checkbox>(
u"Shadows", base::BindRepeating(&LabelExample::ShadowsCheckboxPressed,
base::Unretained(this))));
selectable_ = checkboxes->AddChildView(std::make_unique<Checkbox>(
u"Selectable",
base::BindRepeating(&LabelExample::SelectableCheckboxPressed,
base::Unretained(this))));
control_container->AddChildView(std::make_unique<View>())
->SetPreferredSize(gfx::Size(1, 8));
custom_label_ = control_container->AddChildView(
std::make_unique<ExamplePreferredSizeLabel>());
custom_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
custom_label_->SetElideBehavior(gfx::NO_ELIDE);
custom_label_->SetText(textfield_->GetText());
// Disable the text selection checkbox if |custom_label_| does not support
// text selection.
selectable_->SetEnabled(custom_label_->IsSelectionSupported());
container->AddChildView(std::move(control_container));
}
Combobox* LabelExample::AddCombobox(View* parent,
std::u16string name,
base::span<const char* const> items,
void (LabelExample::*function)()) {
parent->AddChildView(std::make_unique<Label>(name));
auto* combobox = parent->AddChildView(std::make_unique<Combobox>(
std::make_unique<ExampleComboboxModel>(items)));
combobox->SetSelectedIndex(0);
combobox->GetViewAccessibility().SetName(name);
combobox->SetCallback(base::BindRepeating(function, base::Unretained(this)));
return parent->AddChildView(std::move(combobox));
}
void LabelExample::AlignmentChanged() {
custom_label_->SetHorizontalAlignment(static_cast<gfx::HorizontalAlignment>(
alignment_->GetSelectedIndex().value()));
}
void LabelExample::ElidingChanged() {
custom_label_->SetElideBehavior(static_cast<gfx::ElideBehavior>(
elide_behavior_->GetSelectedIndex().value()));
}
void LabelExample::OnViewThemeChanged(View* observed_view) {
auto* const cp = observed_view->GetColorProvider();
gfx::ShadowValues shadows = {
gfx::ShadowValue(
gfx::Vector2d(), 1,
cp->GetColor(ExamplesColorIds::kColorLabelExampleUpperShadow)),
gfx::ShadowValue(
gfx::Vector2d(2, 2), 0,
cp->GetColor(ExamplesColorIds::kColorLabelExampleLowerShadow))};
label_->SetShadows(shadows);
}
void LabelExample::OnViewIsDeleting(View* observed_view) {
observer_.Reset();
}
} // namespace views::examples