class library: PriorityQueue - implement removeValue, hide array
[supercollider.git] / QtCollider / QWidgetProxy.cpp
blobdb880b313d5e1fb71e81ec67dad75e69f2bedfe2
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 if( e->type() == QEvent::Enter || e->type() == QEvent::Leave ) {
276 QPoint pos = QCursor::pos();
279 if( w ) pos = w->mapFromGlobal( pos );
281 args << pos.x();
282 args << pos.y();
283 return true;
286 QMouseEvent *mouse = static_cast<QMouseEvent*>( e );
287 QPoint pt = ( _mouseEventWidget == w ?
288 mouse->pos() :
289 _mouseEventWidget->mapTo( w, mouse->pos() ) );
290 args << pt.x();
291 args << pt.y();
293 args << (int) mouse->modifiers();
295 if( e->type() == QEvent::MouseMove ) return true;
297 int button;
298 switch( mouse->button() ) {
299 case Qt::LeftButton:
300 button = 0; break;
301 case Qt::RightButton:
302 button = 1; break;
303 case Qt::MidButton:
304 button = 2; break;
305 default:
306 button = -1;
309 args << button;
311 switch( e->type() ) {
312 case QEvent::MouseButtonPress:
313 args << 1; break;
314 case QEvent::MouseButtonDblClick:
315 args << 2; break;
316 default: ;
319 return true;
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 ?
335 we->pos() :
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;
341 args << pt.x();
342 args << pt.y();
343 args << (int) we->modifiers();
344 args << (ort == Qt::Horizontal ? deg : 0);
345 args << (ort == Qt::Vertical ? deg : 0);
347 return true;
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 );
359 args << text;
360 args << (int) ke->modifiers();
361 args << unicode;
362 args << ke->key();
363 args << ke->spontaneous();
365 return true;
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" ) )
376 return false;
378 if( dnd->type() != QEvent::DragEnter ) {
379 QPoint pos = dnd->pos();
380 args << pos.x() << pos.y();
383 return true;
387 void QWidgetProxy::customPaint( QPainter *painter )
389 if( QtCollider::paintingAnnounced() ) {
390 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
391 return;
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 ) );