1 /************************************************************************
2  *
3  * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com)
4  *
5  * This file is part of SuperCollider Qt GUI.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  ************************************************************************/
21 
22 #pragma once
23 
24 #include "widgets/QcTreeWidget.h"
25 #include "widgets/QcMenu.h"
26 #include "image.h"
27 
28 #include <PyrSlot.h>
29 #include <PyrKernel.h>
30 
31 #include <QDebug>
32 #include <QChar>
33 #include <QString>
34 #include <QPoint>
35 #include <QPointF>
36 #include <QSize>
37 #include <QSizeF>
38 #include <QRect>
39 #include <QRectF>
40 #include <QColor>
41 #include <QFont>
42 #include <QPalette>
43 #include <QWidget>
44 #include <QLayout>
45 #include <QVector>
46 #include <QUrl>
47 #include <QVariantList>
48 
49 class QObjectProxy;
50 
51 namespace QtCollider {
52 
53 template <typename T, typename EnabledT = void> struct TypeCodec {};
54 
55 // Forwarding from QtCollider namespace to TypeCodec
56 
read(PyrSlot * slot)57 template <typename T> inline T read(PyrSlot* slot) { return TypeCodec<T>::read(slot); }
58 
write(PyrSlot * slot,const T & val)59 template <typename T> inline void write(PyrSlot* slot, const T& val) { return TypeCodec<T>::write(slot, val); }
60 
61 // Lazy conversion, allows automatic codec deduction
62 
63 struct DecodableSlot {
64     PyrSlot* _slot;
DecodableSlotQtCollider::DecodableSlot65     DecodableSlot(PyrSlot* slot): _slot(slot) {}
operator TQtCollider::DecodableSlot66     template <typename T> operator T() { return TypeCodec<T>::safeRead(_slot); }
67 };
68 
get(PyrSlot * slot)69 inline DecodableSlot get(PyrSlot* slot) { return DecodableSlot(slot); }
70 
get(PyrSlot * slot)71 template <typename T> inline T get(PyrSlot* slot) { return TypeCodec<T>::safeRead(slot); }
72 
set(PyrSlot * slot,const T & val)73 template <typename T> inline void set(PyrSlot* slot, const T& val) {
74     // write is always type-safe
75     TypeCodec<T>::write(slot, val);
76 }
77 
setObjectList(PyrSlot * slot,int size,IteratorT iter,IteratorT end)78 template <typename IteratorT> static void setObjectList(PyrSlot* slot, int size, IteratorT iter, IteratorT end) {
79     typedef typename IteratorT::value_type ValueT;
80     VMGlobals* g = gMainVMGlobals;
81 
82     PyrObject* array = newPyrArray(g->gc, size, 0, true);
83     SetObject(slot, array);
84 
85     PyrSlot* s = array->slots;
86     for (; iter != end; ++iter) {
87         if (size > 0) {
88             TypeCodec<ValueT>::write(s, *iter);
89             ++array->size;
90             ++s;
91             --size;
92         }
93     }
94 }
95 
96 
97 // TypeCodecs
98 
99 template <> struct TypeCodec<bool> {
readQtCollider::TypeCodec100     static bool read(PyrSlot* slot) { return IsTrue(slot); }
101 
safeReadQtCollider::TypeCodec102     static bool safeRead(PyrSlot* slot) { return read(slot); }
103 
writeQtCollider::TypeCodec104     static void write(PyrSlot* slot, const bool val) {
105         if (val)
106             SetTrue(slot);
107         else
108             SetFalse(slot);
109     }
110 };
111 
112 template <> struct TypeCodec<int> {
readQtCollider::TypeCodec113     static int read(PyrSlot* slot) { return slotRawInt(slot); }
114 
safeReadQtCollider::TypeCodec115     static int safeRead(PyrSlot* slot) {
116         int val;
117         if (slotIntVal(slot, &val))
118             return 0;
119         return val;
120     }
121 
writeQtCollider::TypeCodec122     static void write(PyrSlot* slot, const int val) { SetInt(slot, val); }
123 };
124 
125 template <> struct TypeCodec<float> {
readQtCollider::TypeCodec126     static float read(PyrSlot* slot) { return slotRawFloat(slot); }
127 
safeReadQtCollider::TypeCodec128     static float safeRead(PyrSlot* slot) {
129         float val;
130         if (slotFloatVal(slot, &val))
131             return 0.f;
132         return val;
133     }
134 
writeQtCollider::TypeCodec135     static void write(PyrSlot* slot, const float val) { SetFloat(slot, val); }
136 };
137 
138 template <> struct TypeCodec<double> {
readQtCollider::TypeCodec139     static double read(PyrSlot* slot) {
140         double d;
141         slotVal(slot, &d);
142         return d;
143     }
144 
safeReadQtCollider::TypeCodec145     static double safeRead(PyrSlot* slot) {
146         double val;
147         if (slotDoubleVal(slot, &val))
148             return 0.0;
149         return val;
150     }
151 
writeQtCollider::TypeCodec152     static void write(PyrSlot* slot, const double val) {
153         // NOTE: the signature actually reads SetFloat(PyrSlot*, double):
154         SetFloat(slot, val);
155     }
156 };
157 
158 template <> struct TypeCodec<QChar> {
readQtCollider::TypeCodec159     static QChar read(PyrSlot* slot) { return QChar(slotRawChar(slot)); }
160 
safeReadQtCollider::TypeCodec161     static QChar safeRead(PyrSlot* slot) {
162         if (GetTag(slot) == tagChar)
163             return QChar(slotRawChar(slot));
164         else
165             return QChar();
166     }
167 
writeQtCollider::TypeCodec168     static void write(PyrSlot* slot, const QChar& val) {
169         // FIXME: Should add support for unicode in PyrSlot!
170         SetChar(slot, val.toLatin1());
171     }
172 };
173 
174 template <> struct TypeCodec<QString> {
175     static QString read(PyrSlot* slot);
176 
safeReadQtCollider::TypeCodec177     static QString safeRead(PyrSlot* slot) { return read(slot); }
178 
179     static void write(PyrSlot* slot, const QString& val);
180 };
181 
182 template <> struct TypeCodec<QUrl> {
183     static QUrl read(PyrSlot* slot);
184 
safeReadQtCollider::TypeCodec185     static QUrl safeRead(PyrSlot* slot) { return read(slot); }
186 
187     static void write(PyrSlot* slot, const QUrl& val);
188 };
189 
190 template <> struct TypeCodec<QPointF> {
191     static QPointF read(PyrSlot* slot);
192 
193     static QPointF safeRead(PyrSlot* slot);
194 
195     static void write(PyrSlot* slot, const QPointF& pt);
196 };
197 
198 template <> struct TypeCodec<QPoint> {
readQtCollider::TypeCodec199     static QPoint read(PyrSlot* slot) { return TypeCodec<QPointF>::read(slot).toPoint(); }
200 
safeReadQtCollider::TypeCodec201     static QPoint safeRead(PyrSlot* slot) { return TypeCodec<QPointF>::safeRead(slot).toPoint(); }
202 
writeQtCollider::TypeCodec203     static void write(PyrSlot* slot, const QPoint& pt) { TypeCodec<QPointF>::write(slot, pt); }
204 };
205 
206 template <> struct TypeCodec<QRectF> {
207     static QRectF read(PyrSlot* slot);
208 
209     static QRectF safeRead(PyrSlot* slot);
210 
211     static void write(PyrSlot* slot, const QRectF& r);
212 };
213 
214 template <> struct TypeCodec<QRect> {
readQtCollider::TypeCodec215     static QRect read(PyrSlot* slot) { return TypeCodec<QRectF>::read(slot).toRect(); }
216 
safeReadQtCollider::TypeCodec217     static QRect safeRead(PyrSlot* slot) { return TypeCodec<QRectF>::safeRead(slot).toRect(); }
218 
writeQtCollider::TypeCodec219     static void write(PyrSlot* slot, const QRect& rect) { TypeCodec<QRectF>::write(slot, rect); }
220 };
221 
222 template <> struct TypeCodec<QSizeF> {
223     static QSizeF read(PyrSlot* slot);
224 
225     static QSizeF safeRead(PyrSlot* slot);
226 
227     static void write(PyrSlot* slot, const QSizeF& sz);
228 };
229 
230 template <> struct TypeCodec<QSize> {
readQtCollider::TypeCodec231     static QSize read(PyrSlot* slot) { return TypeCodec<QSizeF>::read(slot).toSize(); }
232 
safeReadQtCollider::TypeCodec233     static QSize safeRead(PyrSlot* slot) { return TypeCodec<QSizeF>::safeRead(slot).toSize(); }
234 
writeQtCollider::TypeCodec235     static void write(PyrSlot* slot, const QSize& size) { TypeCodec<QSizeF>::write(slot, size); }
236 };
237 
238 template <> struct TypeCodec<QColor> {
239     static QColor read(PyrSlot* slot);
240 
safeReadQtCollider::TypeCodec241     static QColor safeRead(PyrSlot* slot) {
242         if (IsObj(slot))
243             return read(slot);
244         return QColor();
245     }
246 
247     static void write(PyrSlot* slot, const QColor&);
248 };
249 
250 template <> struct TypeCodec<QFont> {
251     static QFont read(PyrSlot* slot);
252 
253     static QFont safeRead(PyrSlot* slot);
254 
writeQtCollider::TypeCodec255     static void write(PyrSlot* slot, const QFont&) {
256         qWarning("WARNING: QtCollider: writing QFont to PyrSlot not supported.");
257     }
258 };
259 
260 template <> struct TypeCodec<QPalette> {
261     static QPalette read(PyrSlot* slot);
262 
263     static QPalette safeRead(PyrSlot* slot);
264 
265     static void write(PyrSlot* slot, const QPalette&);
266 };
267 
268 template <> struct TypeCodec<QObjectProxy*> {
readQtCollider::TypeCodec269     static QObjectProxy* read(PyrSlot* slot) {
270         PyrSlot* proxySlot = slotRawObject(slot)->slots;
271         if (IsPtr(proxySlot))
272             return (QObjectProxy*)slotRawPtr(proxySlot);
273         else
274             return 0;
275     }
276 
277     static QObjectProxy* safeRead(PyrSlot* slot);
278 
writeQtCollider::TypeCodec279     static void write(PyrSlot*, QObjectProxy*) {
280         qWarning("WARNING: QtCollider: writing QObjectProxy* to PyrSlot not supported.");
281     }
282 };
283 
284 template <> struct TypeCodec<QObject*> {
readQtCollider::TypeCodec285     static QObject* read(PyrSlot*) {
286         qWarning("WARNING: QtCollider: reading QObject* from PyrSlot not supported.");
287         return 0;
288     }
289 
290     static void write(PyrSlot*, QObject*);
291 };
292 
293 
294 #define TYPE_IS_QOBJECT(type) std::is_convertible<QObjectT, QObject*>::value
295 template <> struct TypeCodec<PyrObject*> {
readQtCollider::TypeCodec296     static PyrObject* read(PyrSlot*) {
297         qWarning("WARNING: TypeCodec<PyrObject*>::read(PyrSlot*) = NO-OP");
298         return 0;
299     }
300 
writeQtCollider::TypeCodec301     static void write(PyrSlot* slot, PyrObject* object) { SetObject(slot, object); }
302 };
303 
304 template <> struct TypeCodec<QcTreeWidget::ItemPtr> {
305     static QcTreeWidget::ItemPtr read(PyrSlot* slot);
306 
307     static void write(PyrSlot* slot, const QcTreeWidget::ItemPtr&);
308 };
309 
310 template <> struct TypeCodec<SharedImage> {
311     static SharedImage read(PyrSlot* slot);
312     static SharedImage safeRead(PyrSlot* slot);
313     static void write(PyrSlot* slot, SharedImage image);
314 };
315 
316 template <> struct TypeCodec<QVector<int>> {
317     static QVector<int> read(PyrSlot* slot);
318 
319     static void write(PyrSlot* slot, const QVector<int>&);
320 };
321 
322 template <> struct TypeCodec<QVector<double>> {
323     static QVector<double> read(PyrSlot* slot);
324 
325     static void write(PyrSlot* slot, const QVector<double>&);
326 };
327 
328 template <typename ContainedT> struct TypeCodec<QVector<ContainedT>> {
readQtCollider::TypeCodec329     static QVector<ContainedT> read(PyrSlot* slot) {
330         qWarning("WARNING: TypeCodec<PyrObject*>::read(PyrSlot*) = NO-OP");
331         return QVector<ContainedT>();
332     }
333 
writeQtCollider::TypeCodec334     static void write(PyrSlot* slot, const QVector<ContainedT>& vec) {
335         setObjectList(slot, vec.size(), vec.begin(), vec.end());
336     }
337 };
338 
339 template <typename ContainedT> struct TypeCodec<QList<ContainedT>> {
readQtCollider::TypeCodec340     static QList<ContainedT> read(PyrSlot* slot) {
341         qWarning("WARNING: TypeCodec<PyrObject*>::read(PyrSlot*) = NO-OP");
342         return QList<ContainedT>();
343     }
344 
writeQtCollider::TypeCodec345     static void write(PyrSlot* slot, const QList<ContainedT>& vec) {
346         setObjectList(slot, vec.size(), vec.begin(), vec.end());
347     }
348 };
349 
350 template <> struct TypeCodec<QVariantList> {
351     static QVariantList read(PyrSlot* slot);
352 
safeReadQtCollider::TypeCodec353     static QVariantList safeRead(PyrSlot* slot) { return read(slot); }
354 
355     static void write(PyrSlot* slot, const QVariantList&);
356 };
357 
358 template <typename QObjectT> struct TypeCodec<QObjectT, void> {
readQtCollider::TypeCodec359     static QObjectT read(PyrSlot* slot) { return safeRead(slot); }
360 
safeReadQtCollider::TypeCodec361     static QObjectT safeRead(PyrSlot* slot) {
362         auto proxy = TypeCodec<QObjectProxy*>::safeRead(slot);
363 
364         if (proxy) {
365             auto action = qobject_cast<QObjectT>(proxy->object());
366             return action;
367         } else {
368             return 0;
369         }
370     }
371 
writeQtCollider::TypeCodec372     static void write(PyrSlot* slot, QObjectT object) {
373         auto qobject = qobject_cast<QObject*>(object);
374         TypeCodec<QObject*>::write(slot, qobject);
375     }
376 };
377 
378 } // namespace QtCollider
379