20 #include <QAbstractListModel> |
20 #include <QAbstractListModel> |
21 #include <memory> |
21 #include <memory> |
22 #include "src/basics.h" |
22 #include "src/basics.h" |
23 #include "src/colors.h" |
23 #include "src/colors.h" |
24 |
24 |
|
25 #include <QTextDocument> |
|
26 using Model = QTextDocument; |
|
27 |
25 struct SubfileReference |
28 struct SubfileReference |
26 { |
29 { |
27 QString name; |
30 QString name; |
28 glm::mat4 transformation; |
31 glm::mat4 transformation; |
29 bool inverted = false; |
|
30 }; |
32 }; |
31 |
33 |
32 template<typename T> |
34 template<typename T> |
33 struct Colored : T |
35 struct Colored : T |
34 { |
36 { |
114 Quadrilateral, |
116 Quadrilateral, |
115 ConditionalEdge>; |
117 ConditionalEdge>; |
116 |
118 |
117 using PolygonElement = Colored<PlainPolygonElement>; |
119 using PolygonElement = Colored<PlainPolygonElement>; |
118 |
120 |
119 template<typename T> |
|
120 struct remove_color {}; |
|
121 |
|
122 template<typename T> |
|
123 struct remove_color<Colored<T>> { using type = T; }; |
|
124 |
|
125 template<typename T> |
|
126 struct remove_color<Colored<T>&> { using type = T&; }; |
|
127 |
|
128 template<typename T> |
|
129 struct remove_color<const Colored<T>&> { using type = const T&; }; |
|
130 |
|
131 template<typename T> |
|
132 struct remove_color<Colored<T>&&> { using type = T&&; }; |
|
133 |
|
134 template<typename T> |
|
135 using remove_color_t = typename remove_color<T>::type; |
|
136 |
|
137 static_assert(std::is_same_v<remove_color_t<Colored<Triangle>>, Triangle>); |
|
138 static_assert(std::is_same_v<remove_color_t<Colored<Triangle>&>, Triangle&>); |
|
139 static_assert(std::is_same_v<remove_color_t<const Colored<Triangle>&>, const Triangle&>); |
|
140 |
|
141 template<typename T> |
|
142 constexpr remove_color_t<T&&> extract_colored(T&& x) |
|
143 { |
|
144 return static_cast<remove_color_t<T&&>>(x); |
|
145 } |
|
146 |
|
147 template<typename Ret, typename Fn1, typename Fn2, typename Fn3, typename Fn4, typename T> |
121 template<typename Ret, typename Fn1, typename Fn2, typename Fn3, typename Fn4, typename T> |
148 constexpr auto visitPolygon(Fn1&& f1, Fn2&& f2, Fn3&& f3, Fn4&& f4, T&& element) |
122 constexpr auto visitPolygon(Fn1&& f1, Fn2&& f2, Fn3&& f3, Fn4&& f4, T&& element) |
149 { |
123 { |
150 if (std::holds_alternative<LineSegment>(element)) { |
124 if (std::holds_alternative<LineSegment>(element)) { |
151 return f1(std::get<LineSegment>(element)); |
125 return f1(std::get<LineSegment>(element)); |
189 func(cedge.p2); |
163 func(cedge.p2); |
190 func(cedge.c1); |
164 func(cedge.c1); |
191 func(cedge.c2); |
165 func(cedge.c2); |
192 }, |
166 }, |
193 element); |
167 element); |
194 } |
|
195 |
|
196 QString modelElementToString(const ModelElement& element); |
|
197 struct ElementId |
|
198 { |
|
199 std::int32_t value; |
|
200 constexpr auto operator<=>(const ElementId& other) const = default; |
|
201 }; |
|
202 |
|
203 constexpr auto qHash(ElementId id) |
|
204 { |
|
205 return qHash(id.value); |
|
206 } |
|
207 |
|
208 class Model : public QAbstractListModel |
|
209 { |
|
210 Q_OBJECT |
|
211 struct Entry { |
|
212 ModelElement data; |
|
213 ElementId id; |
|
214 }; |
|
215 std::vector<Entry> body; |
|
216 std::map<ElementId, std::size_t> positions; |
|
217 ElementId runningId = {1}; |
|
218 public: |
|
219 explicit Model(QObject* parent); |
|
220 virtual ~Model(); |
|
221 ElementId append(const ModelElement& value); |
|
222 const ModelElement& at(std::size_t position) const; |
|
223 ElementId idAt(std::size_t position) const; |
|
224 void assignAt(std::size_t position, const ModelElement& element); |
|
225 std::optional<std::size_t> find(ElementId id) const; |
|
226 void remove(std::size_t index); |
|
227 int rowCount(const QModelIndex&) const override; |
|
228 QVariant data(const QModelIndex& index, int role) const override; |
|
229 const ModelElement& operator[](std::size_t index) const; |
|
230 std::size_t size() const; |
|
231 void clear(); |
|
232 auto operator[](const std::size_t index) { |
|
233 struct { |
|
234 Model& model; |
|
235 const std::size_t index; |
|
236 operator const ModelElement&() { |
|
237 return model.at(index); |
|
238 } |
|
239 auto& operator=(const ModelElement& newData) { |
|
240 model.assignAt(index, newData); |
|
241 return *this; |
|
242 } |
|
243 const auto* operator&() { |
|
244 return &(this->operator const ModelElement&()); |
|
245 } |
|
246 } result{*this, index}; |
|
247 return result; |
|
248 } |
|
249 }; |
|
250 |
|
251 void save(const Model& model, QTextStream* stream); |
|
252 void updateHeaderNameField(Model& model, const QString &name); |
|
253 |
|
254 template<typename T> |
|
255 void iterate(const Model& model, std::function<void(const T&)> fn) |
|
256 { |
|
257 for (std::size_t i = 0; i < model.size(); ++i) { |
|
258 if (std::holds_alternative<T>(model[i])) { |
|
259 fn(std::get<T>(model[i])); |
|
260 } |
|
261 } |
|
262 } |
168 } |
263 |
169 |
264 constexpr Colored<LineSegment> edge(const glm::vec3& p1, const glm::vec3& p2) |
170 constexpr Colored<LineSegment> edge(const glm::vec3& p1, const glm::vec3& p2) |
265 { |
171 { |
266 return Colored<LineSegment>{{.p1 = p1, .p2 = p2}, EDGE_COLOR}; |
172 return Colored<LineSegment>{{.p1 = p1, .p2 = p2}, EDGE_COLOR}; |