class library: Pipe, return the exit status when closing
[supercollider.git] / QtCollider / QWidgetProxy.cpp
blobb3eeae9487d3b1a45c1fffd032e5a2b15c5be4e3
1 /************************************************************************
3 * Copyright 2010-2011 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 "QWidgetProxy.h"
23 #include "painting.h"
24 #include "Common.h"
26 #include <QApplication>
27 #include <QLayout>
28 #include <QMouseEvent>
29 #include <QKeyEvent>
30 #include <QPainter>
31 #include <QFontMetrics>
32 #include <QUrl>
34 using namespace QtCollider;
36 QAtomicInt QWidgetProxy::_globalEventMask = 0;
38 QWidgetProxy::QWidgetProxy( QWidget *w, PyrObject *po )
39 : QObjectProxy( w, po ), _keyEventWidget( w ), _mouseEventWidget( w )
40 { }
42 void QWidgetProxy::setKeyEventWidget( QWidget *w )
44 if( w == 0 || w == _keyEventWidget ) return;
46 QWidget *me = widget();
48 if( _keyEventWidget != me )
49 _keyEventWidget->removeEventFilter( this );
51 _keyEventWidget = w;
53 if( _keyEventWidget != me ) {
54 _keyEventWidget->installEventFilter( this );
58 void QWidgetProxy::setMouseEventWidget( QWidget *w )
60 if( w == 0 || w == _mouseEventWidget ) return;
62 QWidget *me = widget();
64 if( _mouseEventWidget != me )
65 _mouseEventWidget->removeEventFilter( this );
67 _mouseEventWidget = w;
69 if( _mouseEventWidget != me ) {
70 _mouseEventWidget->installEventFilter( this );
74 bool QWidgetProxy::alwaysOnTop()
76 QWidget *w = widget();
77 if(!w) return false;
79 Qt::WindowFlags flags = w->windowFlags();
80 if( flags & Qt::Window && flags & Qt::WindowStaysOnTopHint ) return true;
81 else return false;
84 void QWidgetProxy::refresh() {
85 QWidget *w = widget();
86 if( w ) sendRefreshEventRecursive( w );
89 void QWidgetProxy::setLayout ( QObjectProxy *layoutProxy ) {
91 QWidget *w = widget();
92 QLayout *l = qobject_cast<QLayout*>( layoutProxy->object() );
93 if( !w || !l ) return;
95 QLayout *exLayout = w->layout();
96 if( exLayout != l ) {
97 if( exLayout != 0 ) {
98 qcDebugMsg( 2, QString("Deleting old layout.") );
99 delete exLayout;
101 qcDebugMsg( 2, QString("Setting layout.") );
102 w->setLayout( l );
103 l->activate();
105 else {
106 qcDebugMsg( 2, QString("Layout same as existing. Will do nothing.") );
110 bool QWidgetProxy::setParent( QObjectProxy *parentProxy )
112 QObject *parent = parentProxy->object();
113 if( !parent || !widget() ) return true;
115 if( parent->isWidgetType() ) {
116 QWidget *pw = qobject_cast<QWidget*>(parent);
117 bool ok = pw->metaObject()->invokeMethod( pw, "addChild", Q_ARG( QWidget*, widget() ) );
118 if( !ok ) widget()->setParent( pw );
119 return true;
121 return false;
124 void QWidgetProxy::customEvent( QEvent *e )
126 int type = e->type();
127 switch( type ) {
128 case QtCollider::Event_Proxy_BringFront:
129 bringFrontEvent();
130 return;
131 case QtCollider::Event_Proxy_SetFocus:
132 setFocusEvent( static_cast<SetFocusEvent*>(e) );
133 return;
134 case QtCollider::Event_Proxy_SetAlwaysOnTop:
135 setAlwaysOnTopEvent( static_cast<SetAlwaysOnTopEvent*>(e) );
136 return;
137 case QtCollider::Event_Proxy_StartDrag:
138 startDragEvent( static_cast<StartDragEvent*>(e) );
139 return;
140 default:
141 QObjectProxy::customEvent(e);
145 void QWidgetProxy::bringFrontEvent() {
146 QWidget *w = widget();
147 if( !w ) return;
149 w->setWindowState( w->windowState() & ~Qt::WindowMinimized
150 | Qt::WindowActive );
151 w->show();
152 w->raise();
154 return;
157 void QWidgetProxy::setFocusEvent( QtCollider::SetFocusEvent *e ) {
158 if( !widget() ) return;
160 if( e->focus )
161 widget()->setFocus( Qt::OtherFocusReason );
162 else
163 widget()->clearFocus();
166 void QWidgetProxy::setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent *e )
168 QWidget *w = widget();
169 if( !w ) return;
171 Qt::WindowFlags flags = w->windowFlags();
172 if( flags & Qt::Window ) {
173 if( e->alwaysOnTop ) flags |= Qt::WindowStaysOnTopHint;
174 else flags &= ~Qt::WindowStaysOnTopHint;
176 // record the initial state to restore it later
177 QPoint pos = w->pos();
178 bool visible = w->isVisible();
180 w->setWindowFlags( flags );
182 // setting window flags will move the window to (0,0) and hide it,
183 // so restore the initial state
184 w->move(pos);
185 if( visible ) w->show();
189 void QWidgetProxy::startDragEvent( StartDragEvent* e )
191 QWidget *w = widget();
192 if( !w ) return;
194 QFont f;
195 const QString & label = e->label;
196 QFontMetrics fm( f );
197 QSize size = fm.size( 0, label ) + QSize(8,4);
199 QPixmap pix( size );
200 QPainter p( &pix );
201 p.setBrush( QColor(255,255,255) );
202 QRect r( pix.rect() );
203 p.drawRect(r.adjusted(0,0,-1,-1));
204 p.drawText( r, Qt::AlignCenter, label );
205 p.end();
207 QMimeData *mime = new QMimeData();
208 mime->setData( "application/supercollider", QByteArray() );
210 QDrag *drag = new QDrag(w);
211 drag->setMimeData( mime );
212 drag->setPixmap( pix );
213 drag->setHotSpot( QPoint( 0, + r.height() + 2 ) );
214 drag->exec();
217 bool QWidgetProxy::filterEvent( QObject *o, QEvent *e, EventHandlerData &eh, QList<QVariant> & args )
219 // NOTE We assume that qObject need not be checked here, as we wouldn't get events if
220 // it wasn't existing
222 int type = e->type();
224 eh = eventHandlers().value( type );
225 if( eh.type != type ) return false;
227 switch( type ) {
229 case QEvent::KeyPress:
230 return ((_globalEventMask & KeyPress) || eh.enabled)
231 && interpretKeyEvent( o, e, args );
233 case QEvent::KeyRelease:
234 return ((_globalEventMask & KeyRelease) || eh.enabled)
235 && interpretKeyEvent( o, e, args );
237 case QEvent::MouseButtonPress:
238 case QEvent::MouseMove:
239 case QEvent::MouseButtonRelease:
240 case QEvent::MouseButtonDblClick:
241 case QEvent::Enter:
242 return eh.enabled && interpretMouseEvent( o, e, args );
244 case QEvent::Wheel:
245 return interpretMouseWheelEvent( o, e, args );
247 case QEvent::DragEnter:
248 case QEvent::DragMove:
249 case QEvent::Drop:
250 return eh.enabled && interpretDragEvent( o, e, args );
252 default:
253 return eh.enabled;
258 bool QWidgetProxy::interpretMouseEvent( QObject *o, QEvent *e, QList<QVariant> &args )
260 if( o != _mouseEventWidget || !_mouseEventWidget->isEnabled() ) return false;
262 QWidget *w = widget();
264 if( e->type() == QEvent::Enter ) {
265 QPoint pos = QCursor::pos();
268 if( w ) pos = w->mapFromGlobal( pos );
270 args << pos.x();
271 args << pos.y();
272 return true;
275 QMouseEvent *mouse = static_cast<QMouseEvent*>( e );
276 QPoint pt = ( _mouseEventWidget == w ?
277 mouse->pos() :
278 _mouseEventWidget->mapTo( w, mouse->pos() ) );
279 args << pt.x();
280 args << pt.y();
282 args << (int) mouse->modifiers();
284 if( e->type() == QEvent::MouseMove ) return true;
286 int button;
287 switch( mouse->button() ) {
288 case Qt::LeftButton:
289 button = 0; break;
290 case Qt::RightButton:
291 button = 1; break;
292 case Qt::MidButton:
293 button = 2; break;
294 default:
295 button = -1;
298 args << button;
300 switch( e->type() ) {
301 case QEvent::MouseButtonPress:
302 args << 1; break;
303 case QEvent::MouseButtonDblClick:
304 args << 2; break;
305 default: ;
308 return true;
311 bool QWidgetProxy::interpretMouseWheelEvent( QObject *o, QEvent *e, QList<QVariant> &args )
313 // NOTE: There seems to be a bug in wheel event propagation:
314 // the event is propagated to parent twice!
315 // Therefore we do not let the propagated events through to SC,
316 // (we only let the "spontaneous" ones).
318 if( o != _mouseEventWidget || !e->spontaneous() || !_mouseEventWidget->isEnabled() ) return false;
320 QWheelEvent *we = static_cast<QWheelEvent*>(e);
322 QWidget *w = widget();
323 QPoint pt = _mouseEventWidget == w ?
324 we->pos() :
325 _mouseEventWidget->mapTo( w, we->pos() );
326 Qt::Orientation ort = we->orientation();
327 // calculate degrees: delta is in 1/8 of a degree.
328 int deg = we->delta() / 8;
330 args << pt.x();
331 args << pt.y();
332 args << (int) we->modifiers();
333 args << (ort == Qt::Horizontal ? deg : 0);
334 args << (ort == Qt::Vertical ? deg : 0);
336 return true;
339 bool QWidgetProxy::interpretKeyEvent( QObject *o, QEvent *e, QList<QVariant> &args )
341 if( o != _keyEventWidget || !_keyEventWidget->isEnabled() ) return false;
343 QKeyEvent *ke = static_cast<QKeyEvent*>( e );
345 QString text = ke->text();
346 int unicode = ( text.count() == 1 ? text[0].unicode() : 0 );
348 args << text;
349 args << (int) ke->modifiers();
350 args << unicode;
351 args << ke->key();
352 args << ke->spontaneous();
354 return true;
357 bool QWidgetProxy::interpretDragEvent( QObject *o, QEvent *e, QList<QVariant> &args )
359 if( o != _mouseEventWidget ) return false;
361 QDropEvent *dnd = static_cast<QDropEvent*>(e);
363 if( dnd->type() == QEvent::DragEnter ) {
364 const QMimeData *data = dnd->mimeData();
365 if( data->hasFormat( "application/supercollider" ) ) {
366 // nothing to do; drag data is stored in QView.currentDrag
367 return true;
369 else if( data->hasColor() ) {
370 args << data->colorData();
372 else if( data->hasUrls() ) {
373 QList<QUrl> urls = data->urls();
374 if( urls.count() > 1 ) {
375 VariantList urlArray;
376 Q_FOREACH( QUrl url, data->urls() ) urlArray.data << url.toString();
377 args << QVariant::fromValue<VariantList>( urlArray );
379 else if( urls.count() == 1 ) {
380 args << urls[0].toString();
383 else if( data->hasText() ) {
384 args << data->text();
386 else {
387 // we can't use the data, let the widget handle DnD
388 return false;
391 else {
392 QPoint pos = dnd->pos();
393 args << pos.x() << pos.y();
396 return true;
400 void QWidgetProxy::customPaint( QPainter *painter )
402 if( QtCollider::paintingAnnounced() ) {
403 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
404 return;
407 QtCollider::announcePainting();
409 QtCollider::lockLang();
411 if( QtCollider::beginPainting( painter ) ) {
412 invokeScMethod( s_doDrawFunc, QList<QVariant>(), 0, true );
413 QtCollider::endPainting();
416 QtCollider::unlockLang();
419 void QWidgetProxy::sendRefreshEventRecursive( QWidget *w ) {
420 QEvent event( static_cast<QEvent::Type>( QtCollider::Event_Refresh ) );
421 QApplication::sendEvent( w, &event );
423 const QObjectList &children = w->children();
424 Q_FOREACH( QObject *child, children ) {
425 if( child->isWidgetType() )
426 sendRefreshEventRecursive( static_cast<QWidget*>( child ) );