910e62b5创建于 1月15日历史提交
// 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/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(CreateSolidBorder(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<Label>();
  themed_label->SetText(u"A left-aligned blue label.");
  themed_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  themed_label->SetEnabledColor(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(
      CreateSolidBorder(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(
      CreateSolidBorder(2, ExamplesColorIds::kColorLabelExampleCustomBorder));
  control_container->SetBackground(CreateSolidBackground(
      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->AddChildViewRaw(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