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 #include "type_codec.hpp"
23 #include "metatype.hpp"
24 
25 #include "QObjectProxy.h"
26 #include "widgets/QcTreeWidget.h"
27 #include "primitives/prim_QPalette.hpp"
28 #include "image.h"
29 
30 #include <PyrObject.h>
31 #include <PyrKernel.h>
32 #include <GC.h>
33 #include <VMGlobals.h>
34 
35 #include <qmath.h>
36 
37 namespace QtCollider {
38 
39 
read(PyrSlot * slot)40 QString TypeCodec<QString>::read(PyrSlot* slot) {
41     if (IsSym(slot)) {
42         return QString::fromUtf8(slotRawSymbol(slot)->name);
43     } else if (isKindOfSlot(slot, class_string)) {
44         int len = slotRawObject(slot)->size;
45         return QString::fromUtf8(slotRawString(slot)->s, len);
46     }
47     return QString();
48 }
49 
50 
write(PyrSlot * slot,const QString & val)51 void TypeCodec<QString>::write(PyrSlot* slot, const QString& val) {
52     PyrString* str = newPyrString(gMainVMGlobals->gc, val.toUtf8().constData(), 0, true);
53     SetObject(slot, str);
54 }
55 
56 
read(PyrSlot * slot)57 QUrl TypeCodec<QUrl>::read(PyrSlot* slot) {
58     if (IsSym(slot)) {
59         return QUrl(QString::fromUtf8(slotRawSymbol(slot)->name));
60     } else if (isKindOfSlot(slot, class_string)) {
61         int len = slotRawObject(slot)->size;
62         return QUrl(QString::fromUtf8(slotRawString(slot)->s, len));
63     } else {
64         return QUrl();
65     }
66 }
67 
68 
write(PyrSlot * slot,const QUrl & val)69 void TypeCodec<QUrl>::write(PyrSlot* slot, const QUrl& val) {
70     PyrString* str = newPyrString(gMainVMGlobals->gc, val.toString(QUrl::None).toUtf8().constData(), 0, true);
71     SetObject(slot, str);
72 }
73 
read(PyrSlot * slot)74 QPointF TypeCodec<QPointF>::read(PyrSlot* slot) {
75     PyrSlot* slots = slotRawObject(slot)->slots;
76     float x, y;
77     int err;
78     err = slotFloatVal(slots + 0, &x);
79     if (err)
80         return QPointF();
81     err = slotFloatVal(slots + 1, &y);
82     if (err)
83         return QPointF();
84     return QPointF(x, y);
85 }
86 
87 
safeRead(PyrSlot * slot)88 QPointF TypeCodec<QPointF>::safeRead(PyrSlot* slot) {
89     if (isKindOfSlot(slot, SC_CLASS(Point)))
90         return read(slot);
91     else
92         return QPointF();
93 }
94 
95 
write(PyrSlot * slot,const QPointF & pt)96 void TypeCodec<QPointF>::write(PyrSlot* slot, const QPointF& pt) {
97     PyrObject* obj = instantiateObject(gMainVMGlobals->gc, SC_CLASS(Point), 0, true, true);
98     SetObject(slot, obj);
99 
100     PyrSlot* slots = obj->slots;
101     SetFloat(slots + 0, pt.x());
102     SetFloat(slots + 1, pt.y());
103 }
104 
105 
read(PyrSlot * slot)106 QRectF TypeCodec<QRectF>::read(PyrSlot* slot) {
107     PyrSlot* slots = slotRawObject(slot)->slots;
108     float bounds[4];
109     for (int i = 0; i < 4; ++i) {
110         int err = slotFloatVal(slots + i, &bounds[i]);
111         if (err)
112             return QRectF();
113     }
114 
115     return QRectF(bounds[0], bounds[1], bounds[2], bounds[3]);
116 }
117 
118 
safeRead(PyrSlot * slot)119 QRectF TypeCodec<QRectF>::safeRead(PyrSlot* slot) {
120     if (isKindOfSlot(slot, SC_CLASS(Rect)))
121         return read(slot);
122     else
123         return QRectF();
124 }
125 
126 
write(PyrSlot * slot,const QRectF & r)127 void TypeCodec<QRectF>::write(PyrSlot* slot, const QRectF& r) {
128     PyrObject* obj = instantiateObject(gMainVMGlobals->gc, SC_CLASS(Rect), 0, true, true);
129     SetObject(slot, obj);
130 
131     PyrSlot* slots = obj->slots;
132     SetFloat(slots + 0, r.x());
133     SetFloat(slots + 1, r.y());
134     SetFloat(slots + 2, r.width());
135     SetFloat(slots + 3, r.height());
136 }
137 
138 
read(PyrSlot * slot)139 QSizeF TypeCodec<QSizeF>::read(PyrSlot* slot) {
140     PyrSlot* slots = slotRawObject(slot)->slots;
141     float w = 0.f, h = 0.f;
142     slotFloatVal(slots + 0, &w);
143     slotFloatVal(slots + 1, &h);
144 
145     return QSizeF(w, h);
146 }
147 
148 
safeRead(PyrSlot * slot)149 QSizeF TypeCodec<QSizeF>::safeRead(PyrSlot* slot) {
150     if (isKindOfSlot(slot, SC_CLASS(Size)))
151         return read(slot);
152     else
153         return QSizeF();
154 }
155 
156 
write(PyrSlot * slot,const QSizeF & sz)157 void TypeCodec<QSizeF>::write(PyrSlot* slot, const QSizeF& sz) {
158     PyrObject* obj = instantiateObject(gMainVMGlobals->gc, SC_CLASS(Size), 0, true, true);
159     SetObject(slot, obj);
160 
161     PyrSlot* slots = obj->slots;
162     SetFloat(slots + 0, sz.width());
163     SetFloat(slots + 1, sz.height());
164 }
165 
asColor(PyrObject * obj)166 inline QColor asColor(PyrObject* obj) {
167     PyrSlot* slots = obj->slots;
168 
169     float r, g, b, a;
170     r = g = b = a = 0.f;
171     slotFloatVal(slots + 0, &r);
172     slotFloatVal(slots + 1, &g);
173     slotFloatVal(slots + 2, &b);
174     slotFloatVal(slots + 3, &a);
175     return QColor(r * 255, g * 255, b * 255, a * 255);
176 }
177 
178 
read(PyrSlot * slot)179 QColor TypeCodec<QColor>::read(PyrSlot* slot) {
180     PyrObject* obj = slotRawObject(slot);
181     PyrClass* klass = obj->classptr;
182 
183     if (klass == SC_CLASS(Color))
184         return asColor(obj);
185 
186     if (klass == SC_CLASS(Gradient) || klass == SC_CLASS(HiliteGradient)) {
187         qcWarningMsg("WARNING: Gradient and HiliteGradient are not supported yet."
188                      " Using the average gradient color instead.");
189 
190         QColor c1(safeRead(obj->slots + 0));
191         QColor c2(safeRead(obj->slots + 1));
192         QColor mix((c1.red() + c2.red()) / 2, (c1.green() + c2.green()) / 2, (c1.blue() + c2.blue()) / 2);
193         return mix;
194     }
195 
196     return QColor();
197 }
198 
199 
write(PyrSlot * slot,const QColor & c)200 void TypeCodec<QColor>::write(PyrSlot* slot, const QColor& c) {
201     if (!c.isValid()) {
202         SetNil(slot);
203         return;
204     }
205 
206     PyrObject* obj = instantiateObject(gMainVMGlobals->gc, SC_CLASS(Color), 0, true, true);
207     SetObject(slot, obj);
208 
209     PyrSlot* slots = obj->slots;
210     SetFloat(slots + 0, c.red() / 255.0);
211     SetFloat(slots + 1, c.green() / 255.0);
212     SetFloat(slots + 2, c.blue() / 255.0);
213     SetFloat(slots + 3, c.alpha() / 255.0);
214 }
215 
216 
read(PyrSlot * slot)217 QFont TypeCodec<QFont>::read(PyrSlot* slot) {
218     PyrSlot* slots = slotRawObject(slot)->slots;
219 
220     QString family = TypeCodec<QString>::safeRead(slots + 0);
221     float fSize = TypeCodec<float>::safeRead(slots + 1);
222     bool bold = TypeCodec<bool>::safeRead(slots + 2);
223     bool italic = TypeCodec<bool>::safeRead(slots + 3);
224     bool isPtSize = TypeCodec<bool>::safeRead(slots + 4);
225 
226     QFont f;
227 
228     if (!family.isEmpty())
229         f.setFamily(family);
230 
231     if (fSize > 0.f) {
232         if (isPtSize) {
233             f.setPointSizeF(fSize);
234         } else {
235             int pixSize = (fSize > 1.f ? qRound(fSize) : 1);
236             f.setPixelSize(pixSize);
237         }
238     }
239 
240     f.setBold(bold);
241 
242     f.setItalic(italic);
243 
244     return f;
245 }
246 
247 
safeRead(PyrSlot * slot)248 QFont TypeCodec<QFont>::safeRead(PyrSlot* slot) {
249     if (isKindOfSlot(slot, SC_CLASS(Font)))
250         return TypeCodec<QFont>::read(slot);
251     else
252         return QFont();
253 }
254 
read(PyrSlot * slot)255 QPalette TypeCodec<QPalette>::read(PyrSlot* slot) {
256     QPalette* p = QPALETTE_FROM_OBJECT(slotRawObject(slot));
257     return *p;
258 }
259 
260 
safeRead(PyrSlot * slot)261 QPalette TypeCodec<QPalette>::safeRead(PyrSlot* slot) {
262     if (isKindOfSlot(slot, SC_CLASS(QPalette)))
263         return TypeCodec<QPalette>::read(slot);
264     else
265         return QPalette();
266 }
267 
268 
write(PyrSlot * slot,const QPalette & plt)269 void TypeCodec<QPalette>::write(PyrSlot* slot, const QPalette& plt) {
270     PyrGC* gc = gMainVMGlobals->gc;
271     PyrObject* obj = instantiateObject(gc, SC_CLASS(QPalette), 0, true, true);
272     SetObject(slot, obj);
273 
274     QPalette_Init(gMainVMGlobals, obj, plt);
275 }
276 
277 
safeRead(PyrSlot * slot)278 QObjectProxy* TypeCodec<QObjectProxy*>::safeRead(PyrSlot* slot) {
279     if (!isKindOfSlot(slot, SC_CLASS(QObject)))
280         return 0;
281     return read(slot);
282 }
283 
write(PyrSlot * slot,QObject * obj)284 void TypeCodec<QObject*>::write(PyrSlot* slot, QObject* obj) {
285     QObjectProxy* proxy = QObjectProxy::fromObject(obj);
286 
287     if (proxy && proxy->scObject())
288         SetObject(slot, proxy->scObject());
289     else
290         SetNil(slot);
291 }
292 
293 
read(PyrSlot * slot)294 QVariantList TypeCodec<QVariantList>::read(PyrSlot* slot) {
295     if (isKindOfSlot(slot, class_array)) {
296         PyrObject* obj = slotRawObject(slot);
297         PyrSlot* slots = obj->slots;
298         int size = obj->size;
299         QVariantList list;
300         for (int i = 0; i < size; ++i, ++slots) {
301             list << QtCollider::get<QVariant>(slots);
302         }
303         return list;
304     } else if (isKindOfSlot(slot, class_symbolarray)) {
305         PyrSymbolArray* symarray = slotRawSymbolArray(slot);
306         PyrSymbol** symbols = symarray->symbols;
307         int size = symarray->size;
308         QVariantList list;
309         for (int i = 0; i < size; ++i, ++symbols)
310             list << QVariant(QString((*symbols)->name));
311         return list;
312     }
313 
314     return QVariantList();
315 }
316 
317 
write(PyrSlot * slot,const QVariantList & varList)318 void TypeCodec<QVariantList>::write(PyrSlot* slot, const QVariantList& varList) {
319     VMGlobals* g = gMainVMGlobals;
320 
321     int count = varList.count();
322 
323     PyrObject* array = newPyrArray(g->gc, count, 0, true);
324     SetObject(slot, array);
325 
326     int i;
327     PyrSlot* s = array->slots;
328     for (i = 0; i < count; ++i, ++s) {
329         if (!QtCollider::set(s, varList[i])) {
330             qcDebugMsg(1, "WARNING: Could not set one slot of array");
331         }
332         array->size++;
333         g->gc->GCWrite(array, s);
334     }
335 }
336 
337 
338 #define WRONG_OBJECT_FORMAT false
339 
copy(QVector<DEST> & dest,PyrSlot * orig,int size)340 template <typename DEST, typename ORIG> inline static void copy(QVector<DEST>& dest, PyrSlot* orig, int size) {
341     ORIG* array = (ORIG*)orig;
342     for (int i = 0; i < size; ++i)
343         dest << DEST(array[i]);
344 }
345 
toNumericVector(PyrObject * obj)346 template <typename numeric_type> static QVector<numeric_type> toNumericVector(PyrObject* obj) {
347     int size = obj->size;
348     PyrSlot* slots = obj->slots;
349 
350     QVector<numeric_type> vector;
351     vector.reserve(size);
352 
353     switch (obj->obj_format) {
354     case obj_double:
355         copy<numeric_type, double>(vector, slots, size);
356         break;
357     case obj_float:
358         copy<numeric_type, float>(vector, slots, size);
359         break;
360     case obj_int32:
361         copy<numeric_type, int32>(vector, slots, size);
362         break;
363     case obj_int16:
364         copy<numeric_type, int16>(vector, slots, size);
365         break;
366     case obj_int8:
367         copy<numeric_type, int8>(vector, slots, size);
368         break;
369     default:
370         Q_ASSERT(WRONG_OBJECT_FORMAT);
371     }
372 
373     return vector;
374 }
375 
376 template <typename numeric_type> static void setNumeric(PyrSlot*, numeric_type);
377 
378 
setNumeric(PyrSlot * s,double val)379 template <> inline void setNumeric<double>(PyrSlot* s, double val) { SetFloat(s, val); }
380 
setNumeric(PyrSlot * s,int val)381 template <> inline void setNumeric<int>(PyrSlot* s, int val) { SetInt(s, val); }
382 
setNumericVector(PyrSlot * slot,const QVector<numeric_type> & vec)383 template <typename numeric_type> static void setNumericVector(PyrSlot* slot, const QVector<numeric_type>& vec) {
384     VMGlobals* g = gMainVMGlobals;
385 
386     int count = vec.count();
387 
388     PyrObject* array = newPyrArray(g->gc, count, 0, true);
389     SetObject(slot, array);
390 
391     PyrSlot* s = array->slots;
392     Q_FOREACH (numeric_type val, vec) {
393         setNumeric<numeric_type>(s, val);
394         ++array->size;
395         ++s;
396     }
397 }
398 
read(PyrSlot * slot)399 QVector<double> TypeCodec<QVector<double>>::read(PyrSlot* slot) { return toNumericVector<double>(slotRawObject(slot)); }
400 
401 
write(PyrSlot * slot,const QVector<double> & vec)402 void TypeCodec<QVector<double>>::write(PyrSlot* slot, const QVector<double>& vec) {
403     setNumericVector<double>(slot, vec);
404 }
405 
406 
read(PyrSlot * slot)407 QVector<int> TypeCodec<QVector<int>>::read(PyrSlot* slot) { return toNumericVector<int>(slotRawObject(slot)); }
408 
409 
write(PyrSlot * slot,const QVector<int> & vec)410 void TypeCodec<QVector<int>>::write(PyrSlot* slot, const QVector<int>& vec) { setNumericVector<int>(slot, vec); }
411 
read(PyrSlot * slot)412 QcTreeWidget::ItemPtr TypeCodec<QcTreeWidget::ItemPtr>::read(PyrSlot* slot) {
413     PyrSlot* ptrSlot = slotRawObject(slot)->slots + 0;
414     if (IsPtr(ptrSlot)) {
415         QcTreeWidget::ItemPtr* safePtr = static_cast<QcTreeWidget::ItemPtr*>(slotRawPtr(ptrSlot));
416         return *safePtr;
417     } else {
418         return QcTreeWidget::ItemPtr();
419     }
420 }
421 
422 
write(PyrSlot * slot,const QcTreeWidget::ItemPtr & item)423 void TypeCodec<QcTreeWidget::ItemPtr>::write(PyrSlot* slot, const QcTreeWidget::ItemPtr& item) {
424     PyrObject* obj = instantiateObject(gMainVMGlobals->gc, SC_CLASS(TreeViewItem), 0, true, true);
425     QcTreeWidget::Item::initialize(gMainVMGlobals, obj, item);
426     SetObject(slot, obj);
427 }
428 
read(PyrSlot * slot)429 SharedImage TypeCodec<SharedImage>::read(PyrSlot* slot) {
430     SharedImage* ptr = reinterpret_cast<SharedImage*>(slotRawPtr(slotRawObject(slot)->slots + 0));
431     return *ptr;
432 }
433 
safeRead(PyrSlot * slot)434 SharedImage TypeCodec<SharedImage>::safeRead(PyrSlot* slot) {
435     if (!isKindOfSlot(slot, SC_CLASS(Image)))
436         return SharedImage();
437     else
438         return read(slot);
439 }
440 
write(PyrSlot * slot,SharedImage image)441 void TypeCodec<SharedImage>::write(PyrSlot* slot, SharedImage image) {
442     qWarning("WARNING: QtCollider: writing SharedImage to PyrSlot not supported.");
443 }
444 
445 }
446 
447 // namespace QtCollider
448