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>
36 #include "hacks/hacks_x11.hpp"
39 using namespace QtCollider
;
41 QAtomicInt
QWidgetProxy::_globalEventMask
= 0;
43 QWidgetProxy::QWidgetProxy( QWidget
*w
, PyrObject
*po
)
44 : QObjectProxy( w
, po
), _keyEventWidget( w
), _mouseEventWidget( w
)
47 void QWidgetProxy::setKeyEventWidget( QWidget
*w
)
49 if( w
== 0 || w
== _keyEventWidget
) return;
51 QWidget
*me
= widget();
53 if( _keyEventWidget
!= me
)
54 _keyEventWidget
->removeEventFilter( this );
58 if( _keyEventWidget
!= me
) {
59 _keyEventWidget
->installEventFilter( this );
63 void QWidgetProxy::setMouseEventWidget( QWidget
*w
)
65 if( w
== 0 || w
== _mouseEventWidget
) return;
67 QWidget
*me
= widget();
69 if( _mouseEventWidget
!= me
)
70 _mouseEventWidget
->removeEventFilter( this );
72 _mouseEventWidget
= w
;
74 if( _mouseEventWidget
!= me
) {
75 _mouseEventWidget
->installEventFilter( this );
79 bool QWidgetProxy::alwaysOnTop()
81 QWidget
*w
= widget();
84 Qt::WindowFlags flags
= w
->windowFlags();
85 if( flags
& Qt::Window
&& flags
& Qt::WindowStaysOnTopHint
) return true;
89 void QWidgetProxy::refresh() {
90 QWidget
*w
= widget();
91 if( w
) sendRefreshEventRecursive( w
);
94 void QWidgetProxy::setLayout ( QObjectProxy
*layoutProxy
) {
96 QWidget
*w
= widget();
97 QLayout
*l
= qobject_cast
<QLayout
*>( layoutProxy
->object() );
98 if( !w
|| !l
) return;
100 QLayout
*exLayout
= w
->layout();
101 if( exLayout
!= l
) {
102 if( exLayout
!= 0 ) {
103 qcDebugMsg( 2, QString("Deleting old layout.") );
106 qcDebugMsg( 2, QString("Setting layout.") );
111 qcDebugMsg( 2, QString("Layout same as existing. Will do nothing.") );
115 bool QWidgetProxy::setParent( QObjectProxy
*parentProxy
)
117 QObject
*parent
= parentProxy
->object();
118 if( !parent
|| !widget() ) return true;
120 if( parent
->isWidgetType() ) {
121 QWidget
*pw
= qobject_cast
<QWidget
*>(parent
);
122 bool ok
= pw
->metaObject()->invokeMethod( pw
, "addChild", Q_ARG( QWidget
*, widget() ) );
123 if( !ok
) widget()->setParent( pw
);
129 void QWidgetProxy::customEvent( QEvent
*e
)
131 int type
= e
->type();
133 case QtCollider::Event_Proxy_BringFront
:
136 case QtCollider::Event_Proxy_SetFocus
:
137 setFocusEvent( static_cast<SetFocusEvent
*>(e
) );
139 case QtCollider::Event_Proxy_SetAlwaysOnTop
:
140 setAlwaysOnTopEvent( static_cast<SetAlwaysOnTopEvent
*>(e
) );
142 case QtCollider::Event_Proxy_StartDrag
:
143 startDragEvent( static_cast<StartDragEvent
*>(e
) );
146 QObjectProxy::customEvent(e
);
153 void QWidgetProxy::bringFrontEvent() {
154 QWidget
*w
= widget();
157 w
->setWindowState( w
->windowState() & ~Qt::WindowMinimized
158 | Qt::WindowActive
);
163 raise_window(QX11Info::display(), w
);
167 void QWidgetProxy::setFocusEvent( QtCollider::SetFocusEvent
*e
) {
168 if( !widget() ) return;
171 widget()->setFocus( Qt::OtherFocusReason
);
173 widget()->clearFocus();
176 void QWidgetProxy::setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent
*e
)
178 QWidget
*w
= widget();
181 Qt::WindowFlags flags
= w
->windowFlags();
182 if( flags
& Qt::Window
) {
183 if( e
->alwaysOnTop
) flags
|= Qt::WindowStaysOnTopHint
;
184 else flags
&= ~Qt::WindowStaysOnTopHint
;
186 // record the initial state to restore it later
187 QPoint pos
= w
->pos();
188 bool visible
= w
->isVisible();
190 w
->setWindowFlags( flags
);
192 // setting window flags will move the window to (0,0) and hide it,
193 // so restore the initial state
195 if( visible
) w
->show();
199 void QWidgetProxy::startDragEvent( StartDragEvent
* e
)
201 QWidget
*w
= widget();
205 const QString
& label
= e
->label
;
206 QFontMetrics
fm( f
);
207 QSize size
= fm
.size( 0, label
) + QSize(8,4);
211 p
.setBrush( QColor(255,255,255) );
212 QRect
r( pix
.rect() );
213 p
.drawRect(r
.adjusted(0,0,-1,-1));
214 p
.drawText( r
, Qt::AlignCenter
, label
);
217 QMimeData
*mime
= e
->data
;
218 e
->data
= 0; // prevent deleting the data when event destroyed;
220 QDrag
*drag
= new QDrag(w
);
221 drag
->setMimeData( mime
);
222 drag
->setPixmap( pix
);
223 drag
->setHotSpot( QPoint( 0, + r
.height() + 2 ) );
227 bool QWidgetProxy::filterEvent( QObject
*o
, QEvent
*e
, EventHandlerData
&eh
, QList
<QVariant
> & args
)
229 // NOTE We assume that qObject need not be checked here, as we wouldn't get events if
230 // it wasn't existing
232 int type
= e
->type();
234 eh
= eventHandlers().value( type
);
235 if( eh
.type
!= type
) return false;
239 case QEvent::KeyPress
:
240 return ((_globalEventMask
& KeyPress
) || eh
.enabled
)
241 && interpretKeyEvent( o
, e
, args
);
243 case QEvent::KeyRelease
:
244 return ((_globalEventMask
& KeyRelease
) || eh
.enabled
)
245 && interpretKeyEvent( o
, e
, args
);
247 case QEvent::MouseButtonPress
:
248 case QEvent::MouseMove
:
249 case QEvent::MouseButtonRelease
:
250 case QEvent::MouseButtonDblClick
:
253 return eh
.enabled
&& interpretMouseEvent( o
, e
, args
);
256 return interpretMouseWheelEvent( o
, e
, args
);
258 case QEvent::DragEnter
:
259 case QEvent::DragMove
:
261 return eh
.enabled
&& interpretDragEvent( o
, e
, args
);
269 bool QWidgetProxy::interpretMouseEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
271 if( o
!= _mouseEventWidget
|| !_mouseEventWidget
->isEnabled() ) return false;
273 QWidget
*w
= widget();
275 if( e
->type() == QEvent::Enter
|| e
->type() == QEvent::Leave
) {
276 QPoint pos
= QCursor::pos();
279 if( w
) pos
= w
->mapFromGlobal( pos
);
286 QMouseEvent
*mouse
= static_cast<QMouseEvent
*>( e
);
287 QPoint pt
= ( _mouseEventWidget
== w
?
289 _mouseEventWidget
->mapTo( w
, mouse
->pos() ) );
293 args
<< (int) mouse
->modifiers();
295 if( e
->type() == QEvent::MouseMove
) return true;
298 switch( mouse
->button() ) {
301 case Qt::RightButton
:
311 switch( e
->type() ) {
312 case QEvent::MouseButtonPress
:
314 case QEvent::MouseButtonDblClick
:
322 bool QWidgetProxy::interpretMouseWheelEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
324 // NOTE: There seems to be a bug in wheel event propagation:
325 // the event is propagated to parent twice!
326 // Therefore we do not let the propagated events through to SC,
327 // (we only let the "spontaneous" ones).
329 if( o
!= _mouseEventWidget
|| !e
->spontaneous() || !_mouseEventWidget
->isEnabled() ) return false;
331 QWheelEvent
*we
= static_cast<QWheelEvent
*>(e
);
333 QWidget
*w
= widget();
334 QPoint pt
= _mouseEventWidget
== w
?
336 _mouseEventWidget
->mapTo( w
, we
->pos() );
337 Qt::Orientation ort
= we
->orientation();
338 // calculate degrees: delta is in 1/8 of a degree.
339 int deg
= we
->delta() / 8;
343 args
<< (int) we
->modifiers();
344 args
<< (ort
== Qt::Horizontal
? deg
: 0);
345 args
<< (ort
== Qt::Vertical
? deg
: 0);
350 bool QWidgetProxy::interpretKeyEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
352 if( o
!= _keyEventWidget
|| !_keyEventWidget
->isEnabled() ) return false;
354 QKeyEvent
*ke
= static_cast<QKeyEvent
*>( e
);
356 QString text
= ke
->text();
357 int unicode
= ( text
.count() == 1 ? text
[0].unicode() : 0 );
360 args
<< (int) ke
->modifiers();
363 args
<< ke
->spontaneous();
368 bool QWidgetProxy::interpretDragEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
370 if( o
!= _mouseEventWidget
) return false;
372 QDropEvent
*dnd
= static_cast<QDropEvent
*>(e
);
374 const QMimeData
*data
= dnd
->mimeData();
375 if ( !data
->hasFormat( "application/supercollider" ) )
378 if( dnd
->type() != QEvent::DragEnter
) {
379 QPoint pos
= dnd
->pos();
380 args
<< pos
.x() << pos
.y();
387 void QWidgetProxy::customPaint( QPainter
*painter
)
389 if( QtCollider::paintingAnnounced() ) {
390 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
394 QtCollider::announcePainting();
396 QtCollider::lockLang();
398 if( QtCollider::beginPainting( painter
) ) {
399 invokeScMethod( s_doDrawFunc
, QList
<QVariant
>(), 0, true );
400 QtCollider::endPainting();
403 QtCollider::unlockLang();
406 void QWidgetProxy::sendRefreshEventRecursive( QWidget
*w
) {
407 QEvent
event( static_cast<QEvent::Type
>( QtCollider::Event_Refresh
) );
408 QApplication::sendEvent( w
, &event
);
410 const QObjectList
&children
= w
->children();
411 Q_FOREACH( QObject
*child
, children
) {
412 if( child
->isWidgetType() )
413 sendRefreshEventRecursive( static_cast<QWidget
*>( child
) );