1 #pragma once
2 
3 #include <QHBoxLayout>
4 #include <QScrollArea>
5 #include <QTabWidget>
6 #include <QWidget>
7 
8 #include <cassert>
9 #include <type_traits>
10 
11 namespace chatterino {
12 
13 template <class T>
14 class LayoutCreator
15 {
16 public:
LayoutCreator(T * _item)17     LayoutCreator(T *_item)
18         : item_(_item)
19     {
20     }
21 
operator ->()22     T *operator->()
23     {
24         return this->item_;
25     }
26 
operator *()27     T &operator*()
28     {
29         return *this->item_;
30     }
31 
getElement()32     T *getElement()
33     {
34         return this->item_;
35     }
36 
37     template <typename T2>
append(T2 * _item)38     LayoutCreator<T2> append(T2 *_item)
39     {
40         this->addItem(this->getOrCreateLayout(), _item);
41 
42         return LayoutCreator<T2>(_item);
43     }
44 
45     template <typename T2, typename... Args>
emplace(Args &&...args)46     LayoutCreator<T2> emplace(Args &&... args)
47     {
48         T2 *t = new T2(std::forward<Args>(args)...);
49 
50         this->addItem(this->getOrCreateLayout(), t);
51 
52         return LayoutCreator<T2>(t);
53     }
54 
55     template <typename Q = T,
56               typename std::enable_if<std::is_base_of<QScrollArea, Q>::value,
57                                       int>::type = 0>
emplaceScrollAreaWidget()58     LayoutCreator<QWidget> emplaceScrollAreaWidget()
59     {
60         QWidget *widget = new QWidget;
61         this->item_->setWidget(widget);
62         return LayoutCreator<QWidget>(widget);
63     }
64 
65     template <typename T2, typename Q = T,
66               typename std::enable_if<std::is_base_of<QWidget, Q>::value,
67                                       int>::type = 0,
68               typename std::enable_if<std::is_base_of<QLayout, T2>::value,
69                                       int>::type = 0>
setLayoutType()70     LayoutCreator<T2> setLayoutType()
71     {
72         T2 *layout = new T2;
73 
74         this->item_->setLayout(layout);
75 
76         return LayoutCreator<T2>(layout);
77     }
78 
assign(T ** ptr)79     LayoutCreator<T> assign(T **ptr)
80     {
81         *ptr = this->item_;
82 
83         return *this;
84     }
85 
86     template <typename Q = T,
87               typename std::enable_if<std::is_base_of<QLayout, Q>::value,
88                                       int>::type = 0>
withoutMargin()89     LayoutCreator<T> withoutMargin()
90     {
91         this->item_->setContentsMargins(0, 0, 0, 0);
92 
93         return *this;
94     }
95 
withoutSpacing()96     LayoutCreator<T> withoutSpacing()
97     {
98         this->item_->setSpacing(0);
99 
100         return *this;
101     }
102 
103     template <typename Q = T,
104               typename std::enable_if<std::is_base_of<QWidget, Q>::value,
105                                       int>::type = 0>
hidden()106     LayoutCreator<T> hidden()
107     {
108         this->item_->setVisible(false);
109 
110         return *this;
111     }
112 
113     template <typename Q = T, typename T2,
114               typename std::enable_if<std::is_same<QTabWidget, Q>::value,
115                                       int>::type = 0>
appendTab(T2 * item,const QString & title)116     LayoutCreator<T2> appendTab(T2 *item, const QString &title)
117     {
118         static_assert(std::is_base_of<QLayout, T2>::value,
119                       "needs to be QLayout");
120 
121         QWidget *widget = new QWidget;
122         widget->setLayout(item);
123 
124         this->item_->addTab(widget, title);
125 
126         return LayoutCreator<T2>(item);
127     }
128 
129     template <typename Slot, typename Func>
connect(Slot slot,QObject * receiver,Func func)130     LayoutCreator<T> connect(Slot slot, QObject *receiver, Func func)
131     {
132         QObject::connect(this->getElement(), slot, receiver, func);
133         return *this;
134     }
135 
136     template <typename Func>
onClick(QObject * receiver,Func func)137     LayoutCreator<T> onClick(QObject *receiver, Func func)
138     {
139         QObject::connect(this->getElement(), &T::clicked, receiver, func);
140         return *this;
141     }
142 
143 private:
144     T *item_;
145 
146     template <typename T2,
147               typename std::enable_if<std::is_base_of<QWidget, T2>::value,
148                                       int>::type = 0>
addItem(QLayout * layout,T2 * item)149     void addItem(QLayout *layout, T2 *item)
150     {
151         layout->addWidget(item);
152     }
153 
154     template <typename T2,
155               typename std::enable_if<std::is_base_of<QLayout, T2>::value,
156                                       int>::type = 0>
addItem(QLayout * layout,T2 * item)157     void addItem(QLayout *layout, T2 *item)
158     {
159         QWidget *widget = new QWidget();
160         widget->setLayout(item);
161         layout->addWidget(widget);
162     }
163 
164     template <typename Q = T,
165               typename std::enable_if<std::is_base_of<QLayout, Q>::value,
166                                       int>::type = 0>
getOrCreateLayout()167     QLayout *getOrCreateLayout()
168     {
169         return this->item_;
170     }
171 
172     template <typename Q = T,
173               typename std::enable_if<std::is_base_of<QWidget, Q>::value,
174                                       int>::type = 0>
getOrCreateLayout()175     QLayout *getOrCreateLayout()
176     {
177         if (!this->item_->layout())
178         {
179             this->item_->setLayout(new QHBoxLayout());
180         }
181 
182         return this->item_->layout();
183     }
184 };
185 
186 template <typename T, typename... Args>
makeDialog(Args &&...args)187 LayoutCreator<T> makeDialog(Args &&... args)
188 {
189     T *t = new T(std::forward<Args>(args)...);
190     t->setAttribute(Qt::WA_DeleteOnClose);
191     return LayoutCreator<T>(t);
192 }
193 
194 }  // namespace chatterino
195