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