Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / QtCollider / Slot.cpp
bloba7880b57fa37d3ef74c982486c9b8f3f94ab6a96
1 /************************************************************************
3 * Copyright 2010 Jakob Leben (jakob.leben@gmail.com)
5 * This file is part of SuperCollider Qt GUI.
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 3 of the License, or
10 * (at your option) any later version.
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.
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/>.
20 ************************************************************************/
22 #include "Slot.h"
23 #include "QObjectProxy.h"
24 #include "Common.h"
25 #include "primitives/prim_QPalette.hpp"
27 #include <PyrObject.h>
28 #include <PyrKernel.h>
29 #include <GC.h>
30 #include <VMGlobals.h>
32 #include <QPalette>
33 #include <QWidget>
34 #include <QVector>
36 #include <qmath.h>
38 using namespace QtCollider;
40 static QPalette::ColorRole paletteColorRoles[] = {
41 QPalette::Window,
42 QPalette::WindowText,
43 QPalette::Button,
44 QPalette::ButtonText,
45 QPalette::Base,
46 QPalette::Text,
47 QPalette::Highlight,
48 QPalette::HighlightedText,
51 void Slot::setRect( PyrSlot *slot, const QRectF &r )
53 PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Rect), 0, true, true );
54 SetObject( slot, obj );
56 PyrSlot *slots = obj->slots;
57 SetFloat( slots+0, r.x() );
58 SetFloat( slots+1, r.y() );
59 SetFloat( slots+2, r.width() );
60 SetFloat( slots+3, r.height() );
63 void Slot::setPoint( PyrSlot *slot, const QPointF &pt )
65 PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Point), 0, true, true );
66 SetObject( slot, obj );
68 PyrSlot *slots = obj->slots;
69 SetFloat( slots+0, pt.x() );
70 SetFloat( slots+1, pt.y() );
73 void Slot::setSize( PyrSlot *slot, const QSizeF &sz )
75 PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Size), 0, true, true );
76 SetObject( slot, obj );
78 PyrSlot *slots = obj->slots;
79 SetFloat( slots+0, sz.width() );
80 SetFloat( slots+1, sz.height() );
83 void Slot::setString( PyrSlot *slot, const QString& arg )
85 PyrString *str = newPyrString( gMainVMGlobals->gc,
86 arg.toUtf8().constData(), 0, true );
87 SetObject( slot, str );
90 void Slot::setColor( PyrSlot *slot, const QColor &c )
92 if(!c.isValid()) {
93 SetNil(slot);
94 return;
97 PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Color), 0, true, true );
98 SetObject( slot, obj );
100 PyrSlot *slots = obj->slots;
101 SetFloat( slots+0, c.red() / 255.0 );
102 SetFloat( slots+1, c.green() / 255.0 );
103 SetFloat( slots+2, c.blue() / 255.0 );
104 SetFloat( slots+3, c.alpha() / 255.0 );
107 void Slot::setPalette( PyrSlot *slot, const QPalette &plt )
109 PyrGC *gc = gMainVMGlobals->gc;
110 PyrObject *obj = instantiateObject( gc, SC_CLASS(QPalette), 0, true, true );
111 SetObject( slot, obj );
113 QPalette_Init( gMainVMGlobals, obj, plt );
116 void Slot::setQObject( PyrSlot *s, QObject *o )
118 if( !o ) {
119 SetNil(s);
120 return;
123 QObjectProxy *proxy = QObjectProxy::fromObject(o);
124 if( proxy && proxy->scObject() )
125 SetObject( s, proxy->scObject() );
126 else
127 SetNil( s );
130 void Slot::setTreeWidgetItem( PyrSlot *s, const SafePtr<QcTreeWidget::Item> & itemPtr )
132 PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(QTreeViewItem), 0, true, true );
133 QcTreeWidget::Item::initialize( gMainVMGlobals, obj, itemPtr );
134 SetObject( s, obj );
137 void Slot::setVariantList( PyrSlot *slot, const VariantList& varList )
139 VMGlobals *g = gMainVMGlobals;
141 int count = varList.data.count();
143 PyrObject *array = newPyrArray( g->gc, count, 0, true );
144 SetObject( slot, array );
146 int i;
147 PyrSlot *s = array->slots;
148 for( i = 0; i < count; ++i, ++s ) {
149 if( !Slot::setVariant( s, varList.data[i] ) ) {
150 qcDebugMsg(1, "WARNING: Could not set one slot of array" );
152 array->size++;
153 g->gc->GCWrite( array, s );
157 template<typename numeric_type>
158 static void setNumeric( PyrSlot *, numeric_type );
161 template<> inline
162 void setNumeric<double>( PyrSlot *s, double val )
164 SetFloat( s, val );
167 template<> inline
168 void setNumeric<int>( PyrSlot *s, int val )
170 SetInt( s, val );
173 template<typename numeric_type>
174 static void setNumericVector( PyrSlot *slot, const QVector<numeric_type> & vec )
176 VMGlobals *g = gMainVMGlobals;
178 int count = vec.count();
180 PyrObject *array = newPyrArray( g->gc, count, 0, true );
181 SetObject( slot, array );
183 PyrSlot *s = array->slots;
184 Q_FOREACH( numeric_type val, vec ) {
185 setNumeric<numeric_type>( s, val );
186 ++array->size;
187 ++s;
191 bool Slot::setVariant( PyrSlot *slot, const QVariant &val )
193 bool b_val;
194 int type = val.userType();
196 switch( type ) {
197 case QMetaType::Bool:
198 b_val = val.toBool();
199 if( b_val ) SetTrue( slot );
200 else SetFalse( slot );
201 break;
203 case QMetaType::QPoint:
204 case QMetaType::QPointF:
205 Slot::setPoint( slot, val.toPointF() );
206 break;
208 case QMetaType::QSize:
209 case QMetaType::QSizeF:
210 Slot::setSize( slot, val.toSizeF() );
211 break;
213 case QMetaType::QRect:
214 case QMetaType::QRectF:
215 Slot::setRect( slot, val.toRectF() );
216 break;
218 case QMetaType::QChar:
219 SetChar( slot, val.toChar().toLatin1() );
220 break;
222 case QMetaType::QString:
223 Slot::setString( slot, val.toString() );
224 break;
226 case QMetaType::QColor:
227 Slot::setColor( slot, val.value<QColor>() );
228 break;
230 case QMetaType::QPalette:
231 Slot::setPalette( slot, val.value<QPalette>() );
232 break;
234 case QMetaType::Float:
235 case QMetaType::Double:
236 SetFloat( slot, val.value<double>() );
237 break;
239 case QMetaType::Int:
240 SetInt( slot, val.toInt() );
241 break;
243 case QMetaType::QObjectStar:
244 Slot::setQObject( slot, val.value<QObject*>() );
245 break;
247 case QMetaType::QWidgetStar:
248 Slot::setQObject( slot, val.value<QWidget*>() );
249 break;
251 case QMetaType::Void:
252 SetNil( slot );
253 break;
255 default:
256 if( type == qMetaTypeId<PyrObject*>() ) {
257 SetObject( slot, val.value<PyrObject*>() );
259 else if( type == qMetaTypeId<VariantList>() ) {
260 Slot::setVariantList( slot, val.value<VariantList>() );
262 else if( type == qMetaTypeId< QVector<double> >() ) {
263 setNumericVector( slot, val.value< QVector<double> >() );
265 else if( type == qMetaTypeId< QVector<int> >() ) {
266 setNumericVector( slot, val.value< QVector<int> >() );
268 else if( type == qMetaTypeId<QcTreeWidget::ItemPtr>() ) {
269 Slot::setTreeWidgetItem( slot, val.value< QtCollider::SafePtr<QcTreeWidget::Item> >() );
271 else {
272 qcErrorMsg( "the QVariant could not be interpreted!" );
273 return false;
277 return true;
280 bool Slot::toBool( PyrSlot *slot )
282 return IsTrue( slot );
285 int Slot::toInt( PyrSlot *slot )
287 int i;
288 if( slotIntVal( slot, &i ) ) return 0;
289 return i;
292 float Slot::toFloat( PyrSlot *slot )
294 float f;
295 if( slotFloatVal( slot, &f ) ) return 0.f;
296 return f;
299 double Slot::toDouble( PyrSlot *slot )
301 double d;
302 if( slotDoubleVal( slot, &d ) ) return 0.0;
303 return d;
306 QString Slot::toString( PyrSlot *slot )
308 if( IsSym(slot) ) {
309 return QString::fromUtf8( slotRawSymbol(slot)->name );
311 else if( isKindOfSlot( slot, class_string ) ) {
312 int len = slotRawObject( slot )->size;
313 return QString::fromUtf8( slotRawString(slot)->s, len );
315 return QString();
318 QPointF Slot::toPoint( PyrSlot *slot )
320 if( !isKindOfSlot( slot, SC_CLASS(Point) ) ) {
321 return QPointF();
323 PyrSlot *slots = slotRawObject( slot )->slots;
324 float x, y;
325 int err;
326 err = slotFloatVal( slots+0, &x ); if( err ) return QPointF();
327 err = slotFloatVal( slots+1, &y ); if( err ) return QPointF();
328 return QPointF( x, y );
331 QRectF Slot::toRect( PyrSlot *slot )
333 if( !isKindOfSlot( slot, SC_CLASS(Rect) ) ) {
334 return QRectF();
337 PyrSlot *slots = slotRawObject( slot )->slots;
338 float bounds[4];
339 for( int i=0; i<4; ++i )
341 int err = slotFloatVal(slots + i, &bounds[i]);
342 if( err ) return QRectF();
345 return QRectF( bounds[0], bounds[1], bounds[2], bounds[3] );
348 QSizeF Slot::toSize( PyrSlot *slot )
350 if( !isKindOfSlot( slot, SC_CLASS(Size) ) ) {
351 return QSizeF();
354 PyrSlot *slots = slotRawObject( slot )->slots;
355 float w = 0.f, h = 0.f;
356 slotFloatVal( slots+0, &w );
357 slotFloatVal( slots+1, &h );
359 return QSizeF( w, h );
362 namespace QtCollider {
363 namespace Slot {
365 QColor asColor( PyrObject *obj )
367 PyrSlot *slots = obj->slots;
369 float r,g,b,a;
370 r = g = b = a = 0.f;
371 int err;
372 err = slotFloatVal(slots+0, &r);
373 if (err) return QColor();
374 err = slotFloatVal(slots+1, &g);
375 if (err) return QColor();
376 err = slotFloatVal(slots+2, &b);
377 if (err) return QColor();
378 err = slotFloatVal(slots+3, &a);
379 if (err) return QColor();
380 return QColor( r*255, g*255, b*255, a*255 );
386 QColor Slot::toColor( PyrSlot *slot )
388 if( NotObj(slot) ) return QColor();
390 PyrObject *obj = slotRawObject(slot);
391 PyrClass *klass = obj->classptr;
393 if( klass == SC_CLASS(Color) )
394 return asColor(obj);
396 if( klass == SC_CLASS(Gradient) || klass == SC_CLASS(HiliteGradient) )
398 qcWarningMsg("WARNING: Gradient and HiliteGradient are not supported yet."
399 " Using the average gradient color instead.");
401 QColor c1( toColor(obj->slots+0) );
402 QColor c2( toColor(obj->slots+1) );
403 QColor mix( (c1.red() + c2.red()) / 2,
404 (c1.green() + c2.green()) / 2,
405 (c1.blue() + c2.blue()) / 2 );
406 return mix;
409 return QColor();
412 QFont Slot::toFont( PyrSlot *slot )
414 if( !isKindOfSlot( slot, SC_CLASS(QFont) ) )
415 return QFont();
417 PyrSlot *slots = slotRawObject(slot)->slots;
419 QString family = Slot::toString( slots+0 );
420 float fSize = Slot::toFloat( slots+1 );
421 bool bold = IsTrue( slots+2 );
422 bool italic = IsTrue( slots+3 );
423 bool isPtSize = IsTrue( slots+4 );
425 QFont f;
427 if( !family.isEmpty() ) f.setFamily( family );
429 if( fSize > 0.f ) {
430 if( isPtSize ) {
431 f.setPointSizeF( fSize );
433 else {
434 int pixSize = ( fSize > 1.f ? qRound(fSize) : 1 );
435 f.setPixelSize( pixSize );
439 f.setBold( bold );
441 f.setItalic( italic );
443 return f;
446 QPalette Slot::toPalette( PyrSlot *slot )
448 if( !isKindOfSlot( slot, SC_CLASS(QPalette) ) )
449 return QPalette();
451 QPalette *p = QPALETTE_FROM_OBJECT(slotRawObject(slot));
452 return *p;
455 VariantList Slot::toVariantList( PyrSlot *slot )
457 if( isKindOfSlot( slot, class_array ) ) {
458 PyrObject *obj = slotRawObject( slot );
459 PyrSlot *slots = obj->slots;
460 int size = obj->size;
461 VariantList list;
462 for( int i = 0; i < size; ++i, ++slots )
463 list.data << Slot::toVariant( slots );
464 return list;
466 else if( isKindOfSlot( slot, class_symbolarray ) ) {
467 PyrSymbolArray *symarray = slotRawSymbolArray( slot );
468 PyrSymbol **symbols = symarray->symbols;
469 int size = symarray->size;
470 VariantList list;
471 for( int i = 0; i < size; ++i, ++symbols )
472 list.data << QVariant( QString( (*symbols)->name) );
473 return list;
476 return VariantList();
479 #define WRONG_OBJECT_FORMAT false
481 template<typename DEST, typename ORIG>
482 inline static void copy( QVector<DEST> & dest, PyrSlot *orig, int size )
484 ORIG *array = (ORIG*) orig;
485 for( int i = 0; i < size; ++i )
486 dest << DEST(array[i]);
489 template<typename numeric_type>
490 static QVector<numeric_type> toNumericVector( PyrObject *obj )
492 int size = obj->size;
493 PyrSlot *slots = obj->slots;
495 QVector<numeric_type> vector;
496 vector.reserve(size);
498 switch (obj->obj_format) {
499 case obj_double:
500 copy<numeric_type, double>( vector, slots, size ); break;
501 case obj_float:
502 copy<numeric_type, float>( vector, slots, size ); break;
503 case obj_int32:
504 copy<numeric_type, int32>( vector, slots, size ); break;
505 case obj_int16:
506 copy<numeric_type, int16>( vector, slots, size ); break;
507 case obj_int8:
508 copy<numeric_type, int8>( vector, slots, size ); break;
509 default:
510 Q_ASSERT( WRONG_OBJECT_FORMAT );
513 return vector;
516 QObjectProxy* Slot::toObjectProxy( PyrSlot *slot )
518 if( !isKindOfSlot( slot, SC_CLASS(QObject) ) ) return 0;
519 QObjectProxy *proxy = 0;
520 PyrSlot *proxySlot = slotRawObject( slot )->slots;
521 if( IsPtr( proxySlot ) ) proxy = (QObjectProxy*) slotRawPtr( proxySlot );
522 return proxy;
525 QcTreeWidget::ItemPtr Slot::toTreeWidgetItem( PyrSlot *slot )
527 if( !isKindOfSlot( slot, SC_CLASS(QTreeViewItem) ) ) return QcTreeWidget::ItemPtr();
528 PyrSlot *ptrSlot = slotRawObject(slot)->slots+0;
529 if( IsPtr( ptrSlot ) ) {
530 QcTreeWidget::ItemPtr *safePtr = static_cast<QcTreeWidget::ItemPtr*>( slotRawPtr(ptrSlot) );
531 return *safePtr;
533 else {
534 return QcTreeWidget::ItemPtr();
538 QVariant Slot::toVariant( PyrSlot *slot )
540 QObjectProxy *proxy;
541 switch (GetTag(slot)) {
542 case tagNil :
543 return QVariant();
544 case tagInt :
545 return QVariant( toInt(slot) );
546 case tagSym :
547 return QVariant( toString(slot) );
548 case tagChar :
549 return QVariant( QChar(slotRawChar(slot)) );
550 case tagFalse :
551 return QVariant( false );
552 case tagTrue :
553 return QVariant( true );
554 case tagObj :
556 PyrObject *obj = slotRawObject(slot);
557 PyrClass *klass = obj->classptr;
558 unsigned char format = obj->obj_format;
560 if( format == obj_double || format == obj_float )
561 return QVariant::fromValue< QVector<double> >( toNumericVector<double>(obj) );
563 else if( format == obj_int32 || format == obj_int16 || format == obj_int8 )
564 return QVariant::fromValue< QVector<int> >( toNumericVector<int>(obj) );
566 else if( isKindOfSlot( slot, class_string ) ) {
567 return QVariant( toString(slot) );
569 else if( isKindOfSlot( slot, SC_CLASS(Point) ) ) {
570 return QVariant( toPoint( slot ) );
572 else if( isKindOfSlot( slot, SC_CLASS(Rect) ) ) {
573 return QVariant( toRect(slot) );
575 else if( isKindOfSlot( slot, SC_CLASS(Size) ) ) {
576 return QVariant( toSize(slot) );
578 else if( klass == SC_CLASS(Color) ||
579 klass == SC_CLASS(Gradient) ||
580 klass == SC_CLASS(HiliteGradient) )
582 return QVariant::fromValue<QColor>( toColor(slot) );
584 else if( isKindOfSlot( slot, SC_CLASS(QFont) ) ) {
585 return QVariant::fromValue<QFont>( toFont(slot) );
587 else if( isKindOfSlot( slot, SC_CLASS(QPalette) ) ) {
588 return QVariant::fromValue<QPalette>( toPalette(slot) );
590 else if( isKindOfSlot( slot, SC_CLASS(QObject) ) ) {
591 proxy = toObjectProxy(slot);
592 return QVariant::fromValue<QObjectProxy*>( proxy );
594 else if( isKindOfSlot( slot, class_array ) || isKindOfSlot( slot, class_symbolarray ) ) {
595 return QVariant::fromValue<VariantList>( toVariantList(slot) );
597 else if( isKindOfSlot( slot, SC_CLASS(QTreeViewItem) ) ) {
598 return QVariant::fromValue<QcTreeWidget::ItemPtr>( toTreeWidgetItem(slot) );
600 else {
601 QString className = Slot::toString( &slotRawObject(slot)->classptr->name );
602 qcWarningMsg(QString("WARNING: Do not know how to use an instance of class '%1'").arg(className));
603 return QVariant();
606 default:
607 return QVariant( toDouble( slot ) );
611 using namespace Slot;
613 void QtCollider::Variant::setData( PyrSlot *slot )
615 QObjectProxy *proxy;
616 switch (GetTag(slot)) {
617 case tagNil :
618 _type = QMetaType::Void;
619 _ptr = 0;
620 break;
621 case tagInt :
622 _type = QMetaType::Int;
623 _ptr = new int( toInt(slot) );
624 break;
625 case tagSym :
626 _type = QMetaType::QString;
627 _ptr = new QString( toString(slot) );
628 break;
629 case tagChar :
630 _type = QMetaType::QChar;
631 _ptr = new QChar( slotRawChar(slot) );
632 break;
633 case tagFalse :
634 _type = QMetaType::Bool;
635 _ptr = new bool( false );
636 break;
637 case tagTrue :
638 _type = QMetaType::Bool;
639 _ptr = new bool( true );
640 break;
641 case tagObj :
643 PyrObject *obj = slotRawObject(slot);
644 PyrClass *klass = obj->classptr;
645 unsigned char format = obj->obj_format;
647 if( format == obj_double || format == obj_float ) {
648 _type = qMetaTypeId< QVector<double> >();
649 _ptr = new QVector<double>( toNumericVector<double>(obj) );
651 else if( format == obj_int32 || format == obj_int16 || format == obj_int8 ) {
652 _type = qMetaTypeId< QVector<int> >();
653 _ptr = new QVector<int>( toNumericVector<int>(obj) );
655 else if( isKindOfSlot( slot, class_string ) ) {
656 _type = QMetaType::QString;
657 _ptr = new QString( toString(slot) );
659 else if( isKindOfSlot( slot, SC_CLASS(Point) ) ) {
660 _type = QMetaType::QPointF;
661 _ptr = new QPointF( toPoint(slot) );
663 else if( isKindOfSlot( slot, SC_CLASS(Rect) ) ) {
664 _type = QMetaType::QRectF;
665 _ptr = new QRectF( toRect(slot) );
667 else if( isKindOfSlot( slot, SC_CLASS(Size) ) ) {
668 _type = QMetaType::QSizeF;
669 _ptr = new QSizeF( toSize(slot) );
671 else if( klass == SC_CLASS(Color) ||
672 klass == SC_CLASS(Gradient) ||
673 klass == SC_CLASS(HiliteGradient) )
675 _type = QMetaType::QColor;
676 _ptr = new QColor( toColor(slot) );
678 else if( isKindOfSlot( slot, class_array ) || isKindOfSlot( slot, class_symbolarray ) ) {
679 _type = qMetaTypeId<VariantList>();
680 _ptr = new VariantList( toVariantList(slot) );
682 else if( isKindOfSlot( slot, SC_CLASS(QObject) ) ) {
683 proxy = toObjectProxy(slot);
684 if( !proxy ) {
685 _type = QMetaType::Void;
686 _ptr = 0;
688 else {
689 _type = qMetaTypeId<QObjectProxy*>();
690 _ptr = new QObjectProxy*( proxy );
693 else if( isKindOfSlot( slot, SC_CLASS(QTreeViewItem) ) ) {
694 _type = qMetaTypeId<QcTreeWidget::ItemPtr>();
695 _ptr = new QcTreeWidget::ItemPtr( toTreeWidgetItem(slot) );
697 else {
698 QString className = Slot::toString( &slotRawObject(slot)->classptr->name );
699 qcWarningMsg(QString("WARNING: Do not know how to use an instance of class '%1'").arg(className));
700 _type = QMetaType::Void;
701 _ptr = 0;
703 break;
705 default :
706 _type = QMetaType::Double;
707 _ptr = new double( toDouble(slot) );