70 lines
3.0 KiB
C++
70 lines
3.0 KiB
C++
#pragma once
|
|
#include "Renderable.h"
|
|
#include "../plot/Plot_Core.h"
|
|
#include <renderive/base/property/Concepts.hpp>
|
|
#include <renderive/base/property/Validators.hpp>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
namespace renderive {
|
|
template <Property_Product Product_Type, Property_Set Properties_Type, Property_Validator<Properties_Type> Validator_Type = No_Property_Validator<Properties_Type>>
|
|
class Renderable_Builder {
|
|
public:
|
|
using Product = Product_Type;
|
|
using Properties = Properties_Type;
|
|
using Validator = Validator_Type;
|
|
using Self = Renderable_Builder;
|
|
Renderable_Builder() requires std::default_initializable<Properties> && std::default_initializable<Validator> : properties{}, validator{} {}
|
|
explicit Renderable_Builder(Properties properties) requires std::default_initializable<Validator> : properties(std::move(properties)), validator{} {}
|
|
Renderable_Builder(Properties properties, Validator validator) : properties(std::move(properties)), validator(std::move(validator)) {}
|
|
template <auto Member, Property_Member_Assignable<Properties, Member> Value>
|
|
Self& set(Value&& value) {
|
|
properties.*Member = std::forward<Value>(value);
|
|
return *this;
|
|
}
|
|
template <Property_Configurator<Properties> Configure>
|
|
Self& configure(Configure&& configure) {
|
|
std::invoke(std::forward<Configure>(configure), properties);
|
|
return *this;
|
|
}
|
|
const Properties& properties_value() const noexcept {
|
|
return properties;
|
|
}
|
|
template <class... Args>
|
|
requires std::derived_from<Product, Renderable> && std::constructible_from<Product, Plot_Core&, const Properties&, Args&&...>
|
|
std::shared_ptr<Product> build(const std::shared_ptr<Renderable>& parent, Args&&... args) const {
|
|
if(!parent || !(valid_argument(args) && ...))
|
|
return {};
|
|
validator(properties);
|
|
if constexpr (requires(Product& product) { attach_renderable_dependencies(product, args...); } &&
|
|
(std::copy_constructible<std::decay_t<Args>> && ...)) {
|
|
auto dependency_args = std::make_tuple(args...);
|
|
auto result = parent->plot().make_renderable<Product>(parent, properties, std::forward<Args>(args)...);
|
|
try {
|
|
std::apply([&result](const auto&... values) {
|
|
attach_renderable_dependencies(*result, values...);
|
|
}, dependency_args);
|
|
} catch (...) {
|
|
result->scene().detach_renderable(*result);
|
|
throw;
|
|
}
|
|
return result;
|
|
}
|
|
return parent->plot().make_renderable<Product>(parent, properties, std::forward<Args>(args)...);
|
|
}
|
|
private:
|
|
template <class T>
|
|
static bool valid_argument(const std::shared_ptr<T>& value) {
|
|
return static_cast<bool>(value);
|
|
}
|
|
template <class T>
|
|
static bool valid_argument(const T&) {
|
|
return true;
|
|
}
|
|
Properties properties;
|
|
[[no_unique_address]] Validator validator;
|
|
};
|
|
}
|