blob: 8ea663213ffb0a3dd95625e71188ffa2ed3a1c54 [file] [log] [blame]
// Copyright 2020 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_METADATA_VIEW_FACTORY_H_
#define UI_VIEWS_METADATA_VIEW_FACTORY_H_
#include <functional>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/memory/raw_ptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/class_property.h"
#include "ui/base/metadata/base_type_conversion.h"
#include "ui/views/metadata/view_factory_internal.h"
#include "ui/views/views_export.h"
namespace views {
template <typename Builder>
class BaseViewBuilderT : public internal::ViewBuilderCore {
public:
using ViewClass_ = typename internal::ViewClassTrait<Builder>::ViewClass_;
using ConfigureCallback = base::OnceCallback<void(ViewClass_*)>;
BaseViewBuilderT() { view_ = std::make_unique<ViewClass_>(); }
explicit BaseViewBuilderT(std::unique_ptr<ViewClass_> view) {
view_ = std::move(view);
}
explicit BaseViewBuilderT(ViewClass_* root_view) : root_view_(root_view) {}
BaseViewBuilderT(BaseViewBuilderT&&) = default;
BaseViewBuilderT& operator=(BaseViewBuilderT&&) = default;
~BaseViewBuilderT() override = default;
template <typename View>
Builder& CopyAddressTo(View** view_address) & {
*view_address = view_ ? view_.get() : root_view_.get();
return *static_cast<Builder*>(this);
}
template <typename View>
Builder&& CopyAddressTo(View** view_address) && {
return std::move(this->CopyAddressTo(view_address));
}
template <typename View>
Builder& CopyAddressTo(raw_ptr<View>* view_address) & {
*view_address = view_ ? view_.get() : root_view_.get();
return *static_cast<Builder*>(this);
}
template <typename View>
Builder&& CopyAddressTo(raw_ptr<View>* view_address) && {
return std::move(this->CopyAddressTo(view_address));
}
Builder& CustomConfigure(ConfigureCallback configure_callback) & {
configure_callback_ = std::move(configure_callback);
return *static_cast<Builder*>(this);
}
Builder&& CustomConfigure(ConfigureCallback configure_callback) && {
return std::move(this->CustomConfigure(std::move(configure_callback)));
}
template <typename Child>
Builder& AddChild(Child&& child) & {
children_.emplace_back(std::make_pair(child.Release(), absl::nullopt));
return *static_cast<Builder*>(this);
}
template <typename Child>
Builder&& AddChild(Child&& child) && {
return std::move(this->AddChild(std::move(child)));
}
template <typename Child>
Builder& AddChildAt(Child&& child, size_t index) & {
children_.emplace_back(std::make_pair(child.Release(), index));
return *static_cast<Builder*>(this);
}
template <typename Child>
Builder&& AddChildAt(Child&& child, size_t index) && {
return std::move(this->AddChildAt(std::move(child), index));
}
template <typename Child, typename... Types>
Builder& AddChildren(Child&& child, Types&&... args) & {
return AddChildrenImpl(&child, &args...);
}
template <typename Child, typename... Types>
Builder&& AddChildren(Child&& child, Types&&... args) && {
return std::move(this->AddChildrenImpl(&child, &args...));
}
[[nodiscard]] std::unique_ptr<ViewClass_> Build() && {
DCHECK(!root_view_) << "Root view specified. Use BuildChildren() instead.";
DCHECK(view_);
SetProperties(view_.get());
DoCustomConfigure(view_.get());
CreateChildren(view_.get());
return std::move(view_);
}
void BuildChildren() && {
DCHECK(!view_) << "Default constructor called. Use Build() instead.";
DCHECK(root_view_);
SetProperties(root_view_);
DoCustomConfigure(root_view_);
CreateChildren(root_view_);
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T>* property,
ui::metadata::ArgType<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyValueSetter<ViewClass_, T>>(
property, value);
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T>* property,
ui::metadata::ArgType<T> value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property,
ui::metadata::ArgType<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyMoveSetter<ViewClass_, T>>(
property, value);
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property,
ui::metadata::ArgType<T> value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property, T&& value) & {
auto setter =
std::make_unique<internal::ClassPropertyMoveSetter<ViewClass_, T>>(
property, std::move(value));
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property, T&& value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property,
std::unique_ptr<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyUniquePtrSetter<ViewClass_, T>>(
property, std::move(value));
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property,
std::unique_ptr<T> value) && {
return std::move(this->SetProperty(property, std::move(value)));
}
protected:
// Internal implementation which iterates over all the parameters without
// resorting to recursion which can lead to more code generation.
template <typename... Args>
Builder& AddChildrenImpl(Args*... args) & {
std::vector<internal::ViewBuilderCore*> children = {args...};
for (auto* child : children)
children_.emplace_back(std::make_pair(child->Release(), absl::nullopt));
return *static_cast<Builder*>(this);
}
void DoCustomConfigure(ViewClass_* view) {
if (configure_callback_)
std::move(configure_callback_).Run(view);
}
std::unique_ptr<View> DoBuild() override { return std::move(*this).Build(); }
// Optional callback invoked right before calling CreateChildren. This allows
// any additional configuration of the view not easily covered by the builder.
ConfigureCallback configure_callback_;
// Owned and meaningful during the Builder building process. Its
// ownership will be transferred out upon Build() call.
std::unique_ptr<ViewClass_> view_;
// Unowned root view. Used for creating a builder with an existing root
// instance.
raw_ptr<ViewClass_> root_view_ = nullptr;
};
} // namespace views
// Example of builder class generated by the following macros.
//
// template <typename Builder, typename ViewClass>
// class ViewBuilderT : public BaseViewBuilderT<Builder, ViewClass> {
// public:
// ViewBuilderT() = default;
// ViewBuilderT(const ViewBuilderT&&) = default;
// ViewBuilderT& operator=(const ViewBuilderT&&) = default;
// ~ViewBuilderT() override = default;
//
// Builder& SetEnabled(bool value) {
// auto setter = std::make_unique<
// PropertySetter<ViewClass, bool, decltype(&ViewClass::SetEnabled),
// &ViewClass::SetEnabled>>(value);
// ViewBuilderCore::AddPropertySetter(std::move(setter));
// return *static_cast<Builder*>(this);
// }
//
// Builder& SetVisible(bool value) {
// auto setter = std::make_unique<
// PropertySetter<ViewClass, bool, &ViewClass::SetVisible>>(value);
// ViewBuilderCore::AddPropertySetter(std::move(setter));
// return *static_cast<Builder*>(this);
// }
// };
//
// class VIEWS_EXPORT ViewBuilderTest
// : public ViewBuilderT<ViewBuilderTest, View> {};
//
// template <typename Builder, typename ViewClass>
// class LabelButtonBuilderT : public ViewBuilderT<Builder, ViewClass> {
// public:
// LabelButtonBuilderT() = default;
// LabelButtonBuilderT(LabelButtonBuilderT&&) = default;
// LabelButtonBuilderT& operator=(LabelButtonBuilderT&&) = default;
// ~LabelButtonBuilderT() override = default;
//
// Builder& SetIsDefault(bool value) {
// auto setter = std::make_unique<
// PropertySetter<ViewClass, bool, decltype(&ViewClass::SetIsDefault),
// &ViewClass::SetIsDefault>>(value);
// ViewBuilderCore::AddPropertySetter(std::move(setter));
// return *static_cast<Builder*>(this);
// }
// };
//
// class VIEWS_EXPORT LabelButtonBuilder
// : public LabelButtonBuilderT<LabelButtonBuilder, LabelButton> {};
// BEGIN_VIEW_BUILDER, END_VIEW_BUILDER and VIEW_BUILDER_XXXX macros should
// be placed into the same namespace as the 'view_class' parameter.
#define BEGIN_VIEW_BUILDER(export, view_class, ancestor) \
template <typename BuilderT> \
class export view_class##BuilderT : public ancestor##BuilderT<BuilderT> { \
private: \
using ViewClass_ = view_class; \
\
public: \
view_class##BuilderT() = default; \
explicit view_class##BuilderT( \
typename ::views::internal::ViewClassTrait<BuilderT>::ViewClass_* \
root_view) \
: ancestor##BuilderT<BuilderT>(root_view) {} \
explicit view_class##BuilderT( \
std::unique_ptr< \
typename ::views::internal::ViewClassTrait<BuilderT>::ViewClass_> \
view) \
: ancestor##BuilderT<BuilderT>(std::move(view)) {} \
view_class##BuilderT(view_class##BuilderT&&) = default; \
view_class##BuilderT& operator=(view_class##BuilderT&&) = default; \
~view_class##BuilderT() override = default;
#define VIEW_BUILDER_PROPERTY2(property_type, property_name) \
BuilderT& Set##property_name( \
::ui::metadata::ArgType<property_type> value)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name( \
::ui::metadata::ArgType<property_type> value)&& { \
return std::move(this->Set##property_name(std::move(value))); \
}
#define VIEW_BUILDER_PROPERTY3(property_type, property_name, field_type) \
BuilderT& Set##property_name( \
::ui::metadata::ArgType<property_type> value)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name, field_type>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name( \
::ui::metadata::ArgType<property_type> value)&& { \
return std::move(this->Set##property_name(std::move(value))); \
}
#define GET_VB_MACRO(_1, _2, _3, macro_name, ...) macro_name
#define VIEW_BUILDER_PROPERTY(...) \
GET_VB_MACRO(__VA_ARGS__, VIEW_BUILDER_PROPERTY3, VIEW_BUILDER_PROPERTY2) \
(__VA_ARGS__)
#define VIEW_BUILDER_METHOD(method_name, ...) \
template <typename... Args> \
BuilderT& method_name(Args&&... args)& { \
auto caller = std::make_unique<::views::internal::ClassMethodCaller< \
ViewClass_, decltype(&ViewClass_::method_name), \
&ViewClass_::method_name, __VA_ARGS__>>(std::forward<Args>(args)...); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(caller)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename... Args> \
BuilderT&& method_name(Args&&... args)&& { \
return std::move(this->method_name(std::forward<Args>(args)...)); \
}
#define VIEW_BUILDER_VIEW_TYPE_PROPERTY(property_type, property_name) \
template <typename _View> \
BuilderT& Set##property_name(_View&& view)& { \
auto setter = std::make_unique<::views::internal::ViewBuilderSetter< \
ViewClass_, property_type, \
decltype(&ViewClass_::Set##property_name<property_type>), \
&ViewClass_::Set##property_name<property_type>>>(view.Release()); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename _View> \
BuilderT&& Set##property_name(_View&& view)&& { \
return std::move(this->Set##property_name(std::move(view))); \
}
#define VIEW_BUILDER_VIEW_PROPERTY(property_type, property_name) \
template <typename _View> \
BuilderT& Set##property_name(_View&& view)& { \
auto setter = std::make_unique<::views::internal::ViewBuilderSetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(view.Release()); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename _View> \
BuilderT&& Set##property_name(_View&& view)&& { \
return std::move(this->Set##property_name(std::move(view))); \
}
#define VIEW_BUILDER_PROPERTY_DEFAULT(property_type, property_name, default) \
BuilderT& Set##property_name(::ui::metadata::ArgType<property_type> value = \
default)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name(::ui::metadata::ArgType<property_type> value = \
default)&& { \
return std::move(this->Set##property_name(value)); \
}
// Turn off clang-format due to it messing up the following macro. Places the
// semi-colon on a separate line.
// clang-format off
#define END_VIEW_BUILDER };
// Unlike the above macros, DEFINE_VIEW_BUILDER must be placed in the global
// namespace. Unless 'view_class' is already in the 'views' namespace, it should
// be fully qualified with the namespace in which it lives.
#define DEFINE_VIEW_BUILDER(export, view_class) \
namespace views { \
template <> \
class export Builder<view_class> \
: public view_class##BuilderT<Builder<view_class>> { \
private: \
using ViewClass_ = view_class; \
public: \
Builder<ViewClass_>() = default; \
explicit Builder<ViewClass_>(ViewClass_* root_view) \
: view_class##BuilderT<Builder<ViewClass_>>(root_view) {} \
explicit Builder<ViewClass_>(std::unique_ptr<ViewClass_> view) \
: view_class##BuilderT<Builder<ViewClass_>>(std::move(view)) {} \
Builder<ViewClass_>(Builder&&) = default; \
Builder<ViewClass_>& operator=(Builder<ViewClass_>&&) = default; \
~Builder<ViewClass_>() = default; \
[[nodiscard]] std::unique_ptr<internal::ViewBuilderCore> Release() \
override { \
return std::make_unique<Builder<view_class>>(std::move(*this)); \
} \
}; \
} // namespace views
// clang-format on
#endif // UI_VIEWS_METADATA_VIEW_FACTORY_H_