blob: 7a2baf2994eb7db40dc4a03ac1cdc4ba57530e89 [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/examples_window.h"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_paths.h"
#include "ui/color/color_id.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
#include "ui/views/examples/create_examples.h"
#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace views::examples {
namespace {
constexpr char kEnableExamples[] = "enable-examples";
ExampleVector GetExamplesToShow(ExampleVector examples) {
using StringVector = std::vector<std::string>;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::ranges::sort(examples, {}, &ExampleBase::example_title);
std::string enable_examples =
command_line->GetSwitchValueASCII(kEnableExamples);
if (!enable_examples.empty()) {
// Filter examples to show based on the command line switch.
StringVector enabled =
base::SplitString(enable_examples, ";,", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
// Transform list of examples to just the list of names.
StringVector example_names;
std::ranges::transform(examples, std::back_inserter(example_names),
&ExampleBase::example_title);
std::ranges::sort(enabled);
// Get an intersection of list of titles between the full list and the list
// from the command-line.
StringVector valid_examples =
base::STLSetIntersection<StringVector>(enabled, example_names);
// If there are still example names in the list, only include the examples
// from the list.
if (!valid_examples.empty()) {
std::erase_if(examples, [&](const auto& example) {
return !base::Contains(valid_examples, example->example_title());
});
}
} else if (command_line->HasSwitch(kEnableExamples)) {
std::string titles;
for (auto& example : examples) {
titles = base::StrCat({titles, "\n\t", example->example_title()});
}
std::cout << "By default, all examples will be shown.\n";
std::cout << "You may want to specify the example(s) you want to run:"
<< titles << '\n';
}
return examples;
}
} // namespace
bool CheckCommandLineUsage() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch("help")) {
// Print the program usage.
std::cout << "Usage: " << command_line->GetProgram() << " [--"
<< kEnableExamples << "=<example1,[example2...]>]\n";
return true;
}
return false;
}
class ExamplesWindowContents : public WidgetDelegateView,
public TabbedPaneListener {
public:
ExamplesWindowContents(base::OnceClosure on_close, ExampleVector examples)
: on_close_(std::move(on_close)) {
SetHasWindowSizeControls(true);
SetBackground(CreateSolidBackground(ui::kColorDialogBackground));
auto* layout = SetLayoutManager(
std::make_unique<views::BoxLayout>(BoxLayout::Orientation::kVertical));
auto tabbed_pane =
std::make_unique<TabbedPane>(TabbedPane::Orientation::kVertical,
TabbedPane::TabStripStyle::kBorder, true);
tabbed_pane_ = AddChildView(std::move(tabbed_pane));
layout->SetFlexForView(tabbed_pane_, 1);
CreateSidePanel(std::move(examples));
status_label_ = AddChildView(std::make_unique<Label>());
status_label_->SetVisible(false);
tabbed_pane_->SetListener(this);
instance_ = this;
}
ExamplesWindowContents(const ExamplesWindowContents&) = delete;
ExamplesWindowContents& operator=(const ExamplesWindowContents&) = delete;
~ExamplesWindowContents() override = default;
// Sets the status area (at the bottom of the window) to |status|.
void SetStatus(std::string_view status) {
status_label_->SetText(base::UTF8ToUTF16(status));
status_label_->SetVisible(!status.empty());
}
void TabSelectedAt(int index) override { status_label_->SetVisible(false); }
static ExamplesWindowContents* instance() { return instance_; }
private:
// WidgetDelegateView:
std::u16string GetWindowTitle() const override { return u"Views Examples"; }
void WindowClosing() override {
instance_ = nullptr;
if (on_close_) {
std::move(on_close_).Run();
}
}
gfx::Size CalculatePreferredSize(
const SizeBounds& /*available_size*/) const override {
gfx::Size size(800, 300);
for (size_t i = 0; i < tabbed_pane_->GetTabCount(); ++i) {
size.set_height(
std::max(size.height(),
tabbed_pane_->GetTabContents(i)->GetHeightForWidth(800)));
}
return size;
}
gfx::Size GetMinimumSize() const override { return gfx::Size(50, 50); }
void CreateSidePanel(ExampleVector examples) {
for (auto& example : examples) {
auto tab_contents = std::make_unique<View>();
example->CreateExampleView(tab_contents.get());
example->SetContainer(
tabbed_pane_->AddTab(base::UTF8ToUTF16(example->example_title()),
std::move(tab_contents)));
}
examples_ = std::move(examples);
}
static ExamplesWindowContents* instance_;
raw_ptr<Label> status_label_ = nullptr;
base::OnceClosure on_close_;
raw_ptr<TabbedPane> tabbed_pane_ = nullptr;
ExampleVector examples_;
};
// static
ExamplesWindowContents* ExamplesWindowContents::instance_ = nullptr;
Widget* GetExamplesWidget() {
return ExamplesWindowContents::instance()
? ExamplesWindowContents::instance()->GetWidget()
: nullptr;
}
void ShowExamplesWindow(base::OnceClosure on_close,
ExampleVector examples,
gfx::NativeWindow window_context) {
if (ExamplesWindowContents::instance()) {
ExamplesWindowContents::instance()->GetWidget()->Activate();
} else {
examples = GetExamplesToShow(std::move(examples));
Widget* widget = new Widget;
Widget::InitParams params(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET,
Widget::InitParams::TYPE_WINDOW);
params.delegate =
new ExamplesWindowContents(std::move(on_close), std::move(examples));
params.context = window_context;
params.name = kExamplesWidgetName;
widget->Init(std::move(params));
widget->Show();
}
}
void PrintStatus(std::string_view status) {
if (ExamplesWindowContents::instance()) {
ExamplesWindowContents::instance()->SetStatus(status);
}
}
} // namespace views::examples