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"
26 #include <QApplication>
28 #include <QMouseEvent>
31 #include <QFontMetrics>
34 using namespace QtCollider
;
36 QAtomicInt
QWidgetProxy::_globalEventMask
= 0;
38 QWidgetProxy::QWidgetProxy( QWidget
*w
, PyrObject
*po
)
39 : QObjectProxy( w
, po
), _keyEventWidget( w
), _mouseEventWidget( w
)
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 );
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();
79 Qt::WindowFlags flags
= w
->windowFlags();
80 if( flags
& Qt::Window
&& flags
& Qt::WindowStaysOnTopHint
) return true;
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();
98 qcDebugMsg( 2, QString("Deleting old layout.") );
101 qcDebugMsg( 2, QString("Setting layout.") );
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
);
124 void QWidgetProxy::customEvent( QEvent
*e
)
126 int type
= e
->type();
128 case QtCollider::Event_Proxy_BringFront
:
131 case QtCollider::Event_Proxy_SetFocus
:
132 setFocusEvent( static_cast<SetFocusEvent
*>(e
) );
134 case QtCollider::Event_Proxy_SetAlwaysOnTop
:
135 setAlwaysOnTopEvent( static_cast<SetAlwaysOnTopEvent
*>(e
) );
137 case QtCollider::Event_Proxy_StartDrag
:
138 startDragEvent( static_cast<StartDragEvent
*>(e
) );
141 QObjectProxy::customEvent(e
);
145 void QWidgetProxy::bringFrontEvent() {
146 QWidget
*w
= widget();
149 w
->setWindowState( w
->windowState() & ~Qt::WindowMinimized
150 | Qt::WindowActive
);
157 void QWidgetProxy::setFocusEvent( QtCollider::SetFocusEvent
*e
) {
158 if( !widget() ) return;
161 widget()->setFocus( Qt::OtherFocusReason
);
163 widget()->clearFocus();
166 void QWidgetProxy::setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent
*e
)
168 QWidget
*w
= widget();
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
185 if( visible
) w
->show();
189 void QWidgetProxy::startDragEvent( StartDragEvent
* e
)
191 QWidget
*w
= widget();
195 const QString
& label
= e
->label
;
196 QFontMetrics
fm( f
);
197 QSize size
= fm
.size( 0, label
) + QSize(8,4);
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
);
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 ) );
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;
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
:
242 return eh
.enabled
&& interpretMouseEvent( o
, e
, args
);
245 return interpretMouseWheelEvent( o
, e
, args
);
247 case QEvent::DragEnter
:
248 case QEvent::DragMove
:
250 return eh
.enabled
&& interpretDragEvent( o
, e
, args
);
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
);
275 QMouseEvent
*mouse
= static_cast<QMouseEvent
*>( e
);
276 QPoint pt
= ( _mouseEventWidget
== w
?
278 _mouseEventWidget
->mapTo( w
, mouse
->pos() ) );
282 args
<< (int) mouse
->modifiers();
284 if( e
->type() == QEvent::MouseMove
) return true;
287 switch( mouse
->button() ) {
290 case Qt::RightButton
:
300 switch( e
->type() ) {
301 case QEvent::MouseButtonPress
:
303 case QEvent::MouseButtonDblClick
:
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
?
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;
332 args
<< (int) we
->modifiers();
333 args
<< (ort
== Qt::Horizontal
? deg
: 0);
334 args
<< (ort
== Qt::Vertical
? deg
: 0);
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 );
349 args
<< (int) ke
->modifiers();
352 args
<< ke
->spontaneous();
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
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();
387 // we can't use the data, let the widget handle DnD
392 QPoint pos
= dnd
->pos();
393 args
<< pos
.x() << pos
.y();
400 void QWidgetProxy::customPaint( QPainter
*painter
)
402 if( QtCollider::paintingAnnounced() ) {
403 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
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
) );