125 lines
3.5 KiB
C++
125 lines
3.5 KiB
C++
#pragma once
|
||
#include "modern-qt/utility/trait/widget.hh"
|
||
#include "modern-qt/utility/wrapper/common.hh"
|
||
#include "modern-qt/utility/wrapper/property.hh"
|
||
|
||
namespace creeper::group::internal {
|
||
|
||
template <typename F, typename T>
|
||
concept foreach_invoke_item_trait = requires {
|
||
{ std::invoke(std::declval<F>(), std::declval<T const&>()) } -> widget_pointer_trait;
|
||
};
|
||
|
||
template <typename F, typename T>
|
||
concept foreach_apply_item_trait = requires {
|
||
{ std::apply(std::declval<F>(), std::declval<T const&>()) } -> widget_pointer_trait;
|
||
};
|
||
|
||
template <typename F, typename T>
|
||
concept foreach_item_trait = foreach_invoke_item_trait<F, T> || foreach_apply_item_trait<F, T>;
|
||
|
||
template <typename R, typename F>
|
||
concept foreach_invoke_ranges_trait = foreach_item_trait<F, std::ranges::range_value_t<R>>;
|
||
|
||
template <layout_trait T, widget_trait W>
|
||
struct Group : public T {
|
||
using T::T;
|
||
std::vector<W*> widgets;
|
||
|
||
template <std::ranges::range R, typename F>
|
||
requires foreach_invoke_ranges_trait<R, F>
|
||
constexpr auto compose(const R& ranges, F&& f, Qt::Alignment a = {}) noexcept -> void {
|
||
for (const auto& item : ranges) {
|
||
using ItemT = decltype(item);
|
||
|
||
auto widget_pointer = (W*) {};
|
||
|
||
if constexpr (foreach_invoke_item_trait<F, ItemT>)
|
||
widget_pointer = std::invoke(f, item);
|
||
|
||
else if constexpr (foreach_apply_item_trait<F, ItemT>)
|
||
widget_pointer = std::apply(f, item);
|
||
|
||
if (widget_pointer != nullptr) {
|
||
T::addWidget(widget_pointer, 0, a);
|
||
widgets.push_back(widget_pointer);
|
||
}
|
||
}
|
||
}
|
||
auto foreach_(this auto&& self, auto&& f) noexcept
|
||
requires std::invocable<decltype(f), W&>
|
||
{
|
||
for (auto widget : self.widgets)
|
||
std::invoke(f, *widget);
|
||
}
|
||
};
|
||
|
||
};
|
||
|
||
namespace creeper::group::pro {
|
||
|
||
using Token = common::Token<internal::Group<QLayout, QWidget>>;
|
||
|
||
/// @note
|
||
/// 一种典型的用法,委托构造时,所传函数只能接受常量引用,
|
||
/// 放心使用 auto,类型是可以被推导出来的
|
||
///
|
||
/// group::pro::Compose {
|
||
/// std::array {
|
||
/// std::tuple(1, "xxxxxx"),
|
||
/// ......
|
||
/// },
|
||
/// [](auto index, auto text) {
|
||
/// return new TextButton { ... };
|
||
/// },
|
||
/// }
|
||
///
|
||
template <typename R, typename F>
|
||
requires internal::foreach_invoke_ranges_trait<R, F>
|
||
struct Compose : Token {
|
||
const R& ranges;
|
||
F method;
|
||
Qt::Alignment alignment;
|
||
|
||
explicit Compose(const R& r, F f, Qt::Alignment a = {}) noexcept
|
||
: ranges { r }
|
||
, method { std::move(f) }
|
||
, alignment { a } { }
|
||
|
||
auto apply(auto& self) noexcept -> void { //
|
||
self.compose(ranges, std::move(method), alignment);
|
||
}
|
||
};
|
||
|
||
/// @note
|
||
/// 函数参数是组件的引用:
|
||
///
|
||
/// group::pro::Foreach { [](Widget& button) { ... } },
|
||
///
|
||
template <typename F>
|
||
requires(!std::invocable<F>)
|
||
struct Foreach : Token {
|
||
F function;
|
||
|
||
explicit Foreach(F&& f) noexcept
|
||
: function { std::forward<F>(f) } { }
|
||
|
||
auto apply(auto& self) const noexcept {
|
||
// 很遗憾,Qt 占用了 foreach 这个单词
|
||
self.foreach_(std::move(function));
|
||
}
|
||
};
|
||
|
||
template <class T>
|
||
concept trait = std::derived_from<T, Token>;
|
||
|
||
CREEPER_DEFINE_CHECKER(trait)
|
||
};
|
||
namespace creeper {
|
||
|
||
template <layout_trait T, widget_trait W>
|
||
using Group =
|
||
Declarative<group::internal::Group<T, W>, CheckerOr<group::pro::checker, typename T::Checker>>;
|
||
|
||
}
|