bump version to 3.5beta1
[supercollider.git] / QtCollider / QWidgetProxy.cpp
blobc6d4a357ebde463469786899079b76c90f500abf
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 #ifdef Q_WS_X11
35 #include <QX11Info>
36 #include "hacks/hacks_x11.hpp"
37 #endif
39 using namespace QtCollider;
41 QAtomicInt QWidgetProxy::_globalEventMask = 0;
43 QWidgetProxy::QWidgetProxy( QWidget *w, PyrObject *po )
44 : QObjectProxy( w, po ), _keyEventWidget( w ), _mouseEventWidget( w )
45 { }
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 );
56 _keyEventWidget = w;
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();
82 if(!w) return false;
84 Qt::WindowFlags flags = w->windowFlags();
85 if( flags & Qt::Window && flags & Qt::WindowStaysOnTopHint ) return true;
86 else return false;
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.") );
104 delete exLayout;
106 qcDebugMsg( 2, QString("Setting layout.") );
107 w->setLayout( l );
108 l->activate();
110 else {
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 );
124 return true;
126 return false;
129 void QWidgetProxy::customEvent( QEvent *e )
131 int type = e->type();
132 switch( type ) {
133 case QtCollider::Event_Proxy_BringFront:
134 bringFrontEvent();
135 return;
136 case QtCollider::Event_Proxy_SetFocus:
137 setFocusEvent( static_cast<SetFocusEvent*>(e) );
138 return;
139 case QtCollider::Event_Proxy_SetAlwaysOnTop:
140 setAlwaysOnTopEvent( static_cast<SetAlwaysOnTopEvent*>(e) );
141 return;
142 case QtCollider::Event_Proxy_StartDrag:
143 startDragEvent( static_cast<StartDragEvent*>(e) );
144 return;
145 default:
146 QObjectProxy::customEvent(e);
153 void QWidgetProxy::bringFrontEvent() {
154 QWidget *w = widget();
155 if( !w ) return;
157 w->setWindowState( w->windowState() & ~Qt::WindowMinimized
158 | Qt::WindowActive );
159 w->show();
160 w->raise();
162 #ifdef Q_WS_X11
163 raise_window(QX11Info::display(), w);
164 #endif
167 void QWidgetProxy::setFocusEvent( QtCollider::SetFocusEvent *e ) {
168 if( !widget() ) return;
170 if( e->focus )
171 widget()->setFocus( Qt::OtherFocusReason );
172 else
173 widget()->clearFocus();
176 void QWidgetProxy::setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent *e )
178 QWidget *w = widget();
179 if( !w ) return;
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
194 w->move(pos);
195 if( visible ) w->show();
199 void QWidgetProxy::startDragEvent( StartDragEvent* e )
201 QWidget *w = widget();
202 if( !w ) return;
204 QFont f;
205 const QString & label = e->label;
206 QFontMetrics fm( f );
207 QSize size = fm.size( 0, label ) + QSize(8,4);
209 QPixmap pix( size );
210 QPainter p( &pix );
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 );
215 p.end();
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 ) );
224 drag->exec();
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;
237 switch( type ) {
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:
251 case QEvent::Enter:
252 case QEvent::Leave:
253 return eh.enabled && interpretMouseEvent( o, e, args );
255 case QEvent::Wheel:
256 return interpretMouseWheelEvent( o, e, args );
258 case QEvent::DragEnter:
259 case QEvent::DragMove:
260 case QEvent::Drop:
261 return eh.enabled && interpretDragEvent( o, e, args );
263 default:
264 return eh.enabled;
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 )
278 return true;
280 QMouseEvent *mouse = static_cast<QMouseEvent*>( e );
281 QPoint pt = ( _mouseEventWidget == w ?
282 mouse->pos() :
283 _mouseEventWidget->mapTo( w, mouse->pos() ) );
284 args << pt.x();
285 args << pt.y();
287 args << (int) mouse->modifiers();
289 if( etype == QEvent::MouseMove )
291 int buttons = mouse->buttons();
293 if( buttons == 0 ) {
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()) )
300 return false;
302 // Reject the events when mouse pointer leaves the window,
303 // resulting in out-of-bounds coordinates
304 if( win == w ) {
305 if( pt.x() < 0 || pt.x() >= w->width() || pt.y() < 0 || pt.y() >= w->height() )
306 return false;
310 args << (int) mouse->buttons();
312 else
314 // MouseButtonPress, MouseButtonDblClick, MouseButtonRelease
316 int button;
318 switch( mouse->button() ) {
319 case Qt::LeftButton:
320 button = 0; break;
321 case Qt::RightButton:
322 button = 1; break;
323 case Qt::MidButton:
324 button = 2; break;
325 default:
326 button = -1;
329 args << button;
331 if( etype == QEvent::MouseButtonPress )
332 args << 1;
333 else if( etype == QEvent::MouseButtonDblClick )
334 args << 2;
337 return true;
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 ?
353 we->pos() :
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;
359 args << pt.x();
360 args << pt.y();
361 args << (int) we->modifiers();
362 args << (ort == Qt::Horizontal ? deg : 0);
363 args << (ort == Qt::Vertical ? deg : 0);
365 return true;
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 );
377 args << text;
378 args << (int) ke->modifiers();
379 args << unicode;
380 args << ke->key();
381 args << ke->spontaneous();
383 return true;
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" ) )
394 return false;
396 if( dnd->type() != QEvent::DragEnter ) {
397 QPoint pos = dnd->pos();
398 args << pos.x() << pos.y();
401 return true;
405 void QWidgetProxy::customPaint( QPainter *painter )
407 if( QtCollider::paintingAnnounced() ) {
408 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
409 return;
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 ) );