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 QEvent::Type etype
= e
->type();
277 if( etype
== QEvent::Enter
|| etype
== QEvent::Leave
)
280 QMouseEvent
*mouse
= static_cast<QMouseEvent
*>( e
);
281 QPoint pt
= ( _mouseEventWidget
== w
?
283 _mouseEventWidget
->mapTo( w
, mouse
->pos() ) );
287 args
<< (int) mouse
->modifiers();
289 if( etype
== QEvent::MouseMove
)
291 int buttons
= mouse
->buttons();
294 // Special treatment of mouse-tracking events.
296 QWidget
*win
= w
->window();
298 // Only accept if window has a special property enabled.
299 if( !(win
&& win
->property("_qc_win_mouse_tracking").toBool()) )
302 // Reject the events when mouse pointer leaves the window,
303 // resulting in out-of-bounds coordinates
305 if( pt
.x() < 0 || pt
.x() >= w
->width() || pt
.y() < 0 || pt
.y() >= w
->height() )
310 args
<< (int) mouse
->buttons();
314 // MouseButtonPress, MouseButtonDblClick, MouseButtonRelease
318 switch( mouse
->button() ) {
321 case Qt::RightButton
:
331 if( etype
== QEvent::MouseButtonPress
)
333 else if( etype
== QEvent::MouseButtonDblClick
)
340 bool QWidgetProxy::interpretMouseWheelEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
342 // NOTE: There seems to be a bug in wheel event propagation:
343 // the event is propagated to parent twice!
344 // Therefore we do not let the propagated events through to SC,
345 // (we only let the "spontaneous" ones).
347 if( o
!= _mouseEventWidget
|| !e
->spontaneous() || !_mouseEventWidget
->isEnabled() ) return false;
349 QWheelEvent
*we
= static_cast<QWheelEvent
*>(e
);
351 QWidget
*w
= widget();
352 QPoint pt
= _mouseEventWidget
== w
?
354 _mouseEventWidget
->mapTo( w
, we
->pos() );
355 Qt::Orientation ort
= we
->orientation();
356 // calculate degrees: delta is in 1/8 of a degree.
357 int deg
= we
->delta() / 8;
361 args
<< (int) we
->modifiers();
362 args
<< (ort
== Qt::Horizontal
? deg
: 0);
363 args
<< (ort
== Qt::Vertical
? deg
: 0);
368 bool QWidgetProxy::interpretKeyEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
370 if( o
!= _keyEventWidget
|| !_keyEventWidget
->isEnabled() ) return false;
372 QKeyEvent
*ke
= static_cast<QKeyEvent
*>( e
);
374 QString text
= ke
->text();
375 int unicode
= ( text
.count() == 1 ? text
[0].unicode() : 0 );
378 args
<< (int) ke
->modifiers();
381 args
<< ke
->spontaneous();
386 bool QWidgetProxy::interpretDragEvent( QObject
*o
, QEvent
*e
, QList
<QVariant
> &args
)
388 if( o
!= _mouseEventWidget
) return false;
390 QDropEvent
*dnd
= static_cast<QDropEvent
*>(e
);
392 const QMimeData
*data
= dnd
->mimeData();
393 if ( !data
->hasFormat( "application/supercollider" ) )
396 if( dnd
->type() != QEvent::DragEnter
) {
397 QPoint pos
= dnd
->pos();
398 args
<< pos
.x() << pos
.y();
405 void QWidgetProxy::customPaint( QPainter
*painter
)
407 if( QtCollider::paintingAnnounced() ) {
408 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
412 QtCollider::announcePainting();
414 QtCollider::lockLang();
416 if( QtCollider::beginPainting( painter
) ) {
417 invokeScMethod( s_doDrawFunc
, QList
<QVariant
>(), 0, true );
418 QtCollider::endPainting();
421 QtCollider::unlockLang();
424 void QWidgetProxy::sendRefreshEventRecursive( QWidget
*w
) {
425 QEvent
event( static_cast<QEvent::Type
>( QtCollider::Event_Refresh
) );
426 QApplication::sendEvent( w
, &event
);
428 const QObjectList
&children
= w
->children();
429 Q_FOREACH( QObject
*child
, children
) {
430 if( child
->isWidgetType() )
431 sendRefreshEventRecursive( static_cast<QWidget
*>( child
) );