/* 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) { }