tdesktop/Telegram/SourceFiles/boxes/generic_box.h

155 lines
3.8 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "boxes/abstract_box.h"
#include "ui/wrap/vertical_layout.h"
#include <tuple>
namespace st {
extern const style::margins &boxRowPadding;
} // namespace st
class GenericBox : public BoxContent {
public:
// InitMethod::operator()(not_null<GenericBox*> box, InitArgs...)
// init(box, args...)
template <
typename InitMethod,
typename ...InitArgs,
typename = decltype(std::declval<std::decay_t<InitMethod>>()(
std::declval<not_null<GenericBox*>>(),
std::declval<std::decay_t<InitArgs>>()...))>
GenericBox(
QWidget*,
InitMethod &&init,
InitArgs &&...args);
void setWidth(int width) {
_width = width;
}
void setFocusCallback(Fn<void()> callback) {
_focus = callback;
}
int rowsCount() const {
return _content->count();
}
template <
typename Widget,
typename = std::enable_if_t<
std::is_base_of_v<RpWidget, Widget>>>
Widget *insertRow(
int atPosition,
object_ptr<Widget> &&child,
const style::margins &margin = st::boxRowPadding) {
return _content->insert(
atPosition,
std::move(child),
margin);
}
template <
typename Widget,
typename = std::enable_if_t<
std::is_base_of_v<RpWidget, Widget>>>
Widget *addRow(
object_ptr<Widget> &&child,
const style::margins &margin = st::boxRowPadding) {
return _content->add(std::move(child), margin);
}
void addSkip(int height);
void setInnerFocus() override {
if (_focus) {
_focus();
}
}
protected:
void prepare() override;
private:
template <typename InitMethod, typename ...InitArgs>
struct Initer {
template <
typename OtherMethod,
typename ...OtherArgs,
typename = std::enable_if_t<
std::is_constructible_v<InitMethod, OtherMethod&&>>>
Initer(OtherMethod &&method, OtherArgs &&...args);
void operator()(not_null<GenericBox*> box);
template <std::size_t... I>
void call(
not_null<GenericBox*> box,
std::index_sequence<I...>);
InitMethod method;
std::tuple<InitArgs...> args;
};
template <typename InitMethod, typename ...InitArgs>
auto MakeIniter(InitMethod &&method, InitArgs &&...args)
-> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...>;
FnMut<void(not_null<GenericBox*>)> _init;
Fn<void()> _focus;
object_ptr<Ui::VerticalLayout> _content;
int _width = 0;
};
template <typename InitMethod, typename ...InitArgs>
template <typename OtherMethod, typename ...OtherArgs, typename>
GenericBox::Initer<InitMethod, InitArgs...>::Initer(
OtherMethod &&method,
OtherArgs &&...args)
: method(std::forward<OtherMethod>(method))
, args(std::forward<OtherArgs>(args)...) {
}
template <typename InitMethod, typename ...InitArgs>
inline void GenericBox::Initer<InitMethod, InitArgs...>::operator()(
not_null<GenericBox*> box) {
call(box, std::make_index_sequence<sizeof...(InitArgs)>());
}
template <typename InitMethod, typename ...InitArgs>
template <std::size_t... I>
inline void GenericBox::Initer<InitMethod, InitArgs...>::call(
not_null<GenericBox*> box,
std::index_sequence<I...>) {
std::invoke(method, box, std::get<I>(args)...);
}
template <typename InitMethod, typename ...InitArgs>
inline auto GenericBox::MakeIniter(InitMethod &&method, InitArgs &&...args)
-> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...> {
return {
std::forward<InitMethod>(method),
std::forward<InitArgs>(args)...
};
}
template <typename InitMethod, typename ...InitArgs, typename>
inline GenericBox::GenericBox(
QWidget*,
InitMethod &&init,
InitArgs &&...args)
: _init(
MakeIniter(
std::forward<InitMethod>(init),
std::forward<InitArgs>(args)...))
, _content(this) {
}