Fix inconsistency in categories: "Internal" (1 file) vs "Internals" (2 files)
[supercollider.git] / QtCollider / QWidgetProxy.cpp
blob1bdf75988849a897d40de9d79596d3149df10a98
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 return eh.enabled && interpretMouseEvent( o, e, args );
254 case QEvent::Wheel:
255 return interpretMouseWheelEvent( o, e, args );
257 case QEvent::DragEnter:
258 case QEvent::DragMove:
259 case QEvent::Drop:
260 return eh.enabled && interpretDragEvent( o, e, args );
262 default:
263 return eh.enabled;
268 bool QWidgetProxy::interpretMouseEvent( QObject *o, QEvent *e, QList<QVariant> &args )
270 if( o != _mouseEventWidget || !_mouseEventWidget->isEnabled() ) return false;
272 QWidget *w = widget();
274 if( e->type() == QEvent::Enter ) {
275 QPoint pos = QCursor::pos();
278 if( w ) pos = w->mapFromGlobal( pos );
280 args << pos.x();
281 args << pos.y();
282 return true;
285 QMouseEvent *mouse = static_cast<QMouseEvent*>( e );
286 QPoint pt = ( _mouseEventWidget == w ?
287 mouse->pos() :
288 _mouseEventWidget->mapTo( w, mouse->pos() ) );
289 args << pt.x();
290 args << pt.y();
292 args << (int) mouse->modifiers();
294 if( e->type() == QEvent::MouseMove ) return true;
296 int button;
297 switch( mouse->button() ) {
298 case Qt::LeftButton:
299 button = 0; break;
300 case Qt::RightButton:
301 button = 1; break;
302 case Qt::MidButton:
303 button = 2; break;
304 default:
305 button = -1;
308 args << button;
310 switch( e->type() ) {
311 case QEvent::MouseButtonPress:
312 args << 1; break;
313 case QEvent::MouseButtonDblClick:
314 args << 2; break;
315 default: ;
318 return true;
321 bool QWidgetProxy::interpretMouseWheelEvent( QObject *o, QEvent *e, QList<QVariant> &args )
323 // NOTE: There seems to be a bug in wheel event propagation:
324 // the event is propagated to parent twice!
325 // Therefore we do not let the propagated events through to SC,
326 // (we only let the "spontaneous" ones).
328 if( o != _mouseEventWidget || !e->spontaneous() || !_mouseEventWidget->isEnabled() ) return false;
330 QWheelEvent *we = static_cast<QWheelEvent*>(e);
332 QWidget *w = widget();
333 QPoint pt = _mouseEventWidget == w ?
334 we->pos() :
335 _mouseEventWidget->mapTo( w, we->pos() );
336 Qt::Orientation ort = we->orientation();
337 // calculate degrees: delta is in 1/8 of a degree.
338 int deg = we->delta() / 8;
340 args << pt.x();
341 args << pt.y();
342 args << (int) we->modifiers();
343 args << (ort == Qt::Horizontal ? deg : 0);
344 args << (ort == Qt::Vertical ? deg : 0);
346 return true;
349 bool QWidgetProxy::interpretKeyEvent( QObject *o, QEvent *e, QList<QVariant> &args )
351 if( o != _keyEventWidget || !_keyEventWidget->isEnabled() ) return false;
353 QKeyEvent *ke = static_cast<QKeyEvent*>( e );
355 QString text = ke->text();
356 int unicode = ( text.count() == 1 ? text[0].unicode() : 0 );
358 args << text;
359 args << (int) ke->modifiers();
360 args << unicode;
361 args << ke->key();
362 args << ke->spontaneous();
364 return true;
367 bool QWidgetProxy::interpretDragEvent( QObject *o, QEvent *e, QList<QVariant> &args )
369 if( o != _mouseEventWidget ) return false;
371 QDropEvent *dnd = static_cast<QDropEvent*>(e);
373 const QMimeData *data = dnd->mimeData();
374 if ( !data->hasFormat( "application/supercollider" ) )
375 return false;
377 if( dnd->type() != QEvent::DragEnter ) {
378 QPoint pos = dnd->pos();
379 args << pos.x() << pos.y();
382 return true;
386 void QWidgetProxy::customPaint( QPainter *painter )
388 if( QtCollider::paintingAnnounced() ) {
389 qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." );
390 return;
393 QtCollider::announcePainting();
395 QtCollider::lockLang();
397 if( QtCollider::beginPainting( painter ) ) {
398 invokeScMethod( s_doDrawFunc, QList<QVariant>(), 0, true );
399 QtCollider::endPainting();
402 QtCollider::unlockLang();
405 void QWidgetProxy::sendRefreshEventRecursive( QWidget *w ) {
406 QEvent event( static_cast<QEvent::Type>( QtCollider::Event_Refresh ) );
407 QApplication::sendEvent( w, &event );
409 const QObjectList &children = w->children();
410 Q_FOREACH( QObject *child, children ) {
411 if( child->isWidgetType() )
412 sendRefreshEventRecursive( static_cast<QWidget*>( child ) );