/**************************************************************************** ** ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "qdragapp.h" #include "qptrlist.h" #include "qintdict.h" #include "qpopupmenu.h" #include "qguardedptr.h" #include "qcolor.h" #include "qwidget.h" #include "qfontmetrics.h" #include "qcursor.h" #include "qobjectlist.h" QWidget *cursorWidget( QPoint * = 0 ); class QDragger; class DropWindow : public QWidget { Q_OBJECT public: void paintEvent( QPaintEvent * ); void closeEvent( QCloseEvent * ); QDragger *master; }; struct DropInfo { DropInfo() { w=0; } ~DropInfo() { delete w; } DropWindow *w; bool userOpened; }; struct DraggedInfo { QWidget *w; QWidget *mother; QPoint pos; }; class QDragger : public QObject { Q_OBJECT public: QDragger(); ~QDragger(); bool notify( QObject *, QEvent * ); // event filter void closeDropWindow( DropWindow * ); public slots: void openDropWindow(); void killDropWindow(); void killAllDropWindows(); void sendChildHome(); void sendAllChildrenHome(); private: bool isParentToDragged( QWidget * ); bool noWidgets( QWidget * ); void killDropWindow( DropInfo * ); void killAllDropWindows( bool ); void sendChildHome( DraggedInfo * ); void sendAllChildrenHome( QWidget * ); QWidget *openDropWindow( const QRect&, bool ); bool startGrab(); void grabFinished(); bool dragEvent( QWidget *, QMouseEvent * ); bool killDropEvent( QMouseEvent * ); bool sendChildEvent( QMouseEvent * ); bool killingDrop; bool sendingChild; QWidget *clickedWidget; QGuardedPtr hostWidget; QCursor cursor; QPopupMenu* menu; QPoint clickOffset; QColor dragBackground; QColor dragForeground; DraggedInfo dragInfo; QIntDict draggedDict; QIntDict dropDict; }; QDragApplication::QDragApplication( int &argc, char **argv ) : QApplication( argc, argv ), dragger( 0 ) { dragger = new QDragger; } QDragApplication::~QDragApplication() { delete dragger; } bool QDragApplication::notify( QObject *o, QEvent *e ) { if ( dragger && !dragger->notify( o, e ) ) return QApplication::notify( o, e ); else return FALSE; } void DropWindow::paintEvent( QPaintEvent * ) { const char *msg = "Drag widgets and drop them here or anywhere!"; int startX = ( width() - fontMetrics().width( msg ) )/2; startX = startX < 0 ? 0 : startX; drawText( startX, height()/2, msg ); } void DropWindow::closeEvent( QCloseEvent *e ) { master->closeDropWindow( this ); e->ignore(); } QDragger::QDragger() { dragInfo.w = 0; killingDrop = FALSE; sendingChild = FALSE; draggedDict.setAutoDelete( TRUE ); dropDict .setAutoDelete( TRUE ); menu = new QPopupMenu; menu->insertItem( "Open drop window", 1 ); menu->insertItem( "Kill drop window", 2 ); menu->insertItem( "Kill all drop windows", 3 ); menu->insertSeparator(); // menu->insertItem( "Send child home", 4 ); menu->insertItem( "Send all children home", 5 ); menu->connectItem( 1, this, SLOT(openDropWindow()) ); menu->connectItem( 2, this, SLOT(killDropWindow()) ); menu->connectItem( 3, this, SLOT(killAllDropWindows()) ); // menu->connectItem( 4, this, SLOT(sendChildHome()) ); menu->connectItem( 5, this, SLOT(sendAllChildrenHome()) ); } QDragger::~QDragger() { delete menu; } bool QDragger::notify( QObject *o, QEvent *e ) { if ( !o->isWidgetType() || o == menu ) return FALSE; switch( e->type() ) { case QEvent::MouseMove: { QMouseEvent *tmp = (QMouseEvent*) e; if ( killingDrop ) return killDropEvent( tmp ); if ( sendingChild ) return sendChildEvent( tmp ); if ( tmp->state() & QMouseEvent::RightButton ) return dragEvent( (QWidget*) o, tmp ); break; } case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: { QMouseEvent *tmp = (QMouseEvent*) e; if ( killingDrop ) return killDropEvent( tmp ); if ( sendingChild ) return sendChildEvent( tmp ); if ( tmp->button() == QMouseEvent::RightButton ) return dragEvent( (QWidget*) o, tmp ); } break; default: break; } return FALSE; } bool QDragger::isParentToDragged( QWidget *w ) { QIntDictIterator iter( draggedDict ); DraggedInfo *tmp; while( (tmp = iter.current()) ) { ++iter; if ( tmp->mother == w ) return TRUE; } return FALSE; } bool QDragger::noWidgets( QWidget *w ) { const QObjectList *l = w->children(); if ( !l ) return TRUE; QObjectListIt iter( *l ); QObject *tmp; while( (tmp = iter.current()) ) { ++iter; if ( tmp->isWidgetType() ) return FALSE; } return TRUE; } void QDragger::sendAllChildrenHome( QWidget *w ) { const QObjectList *l = w->children(); if ( !l ) return; QObjectListIt iter( *l ); QObject *tmp; while( (tmp = iter.current()) ) { ++iter; if ( tmp->isWidgetType() ) { sendAllChildrenHome( (QWidget*) tmp ); DraggedInfo *di = draggedDict.find( (long) tmp ); if ( di ) sendChildHome( di ); } } } bool QDragger::dragEvent( QWidget *w, QMouseEvent *e ) { switch( e->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: { if ( !noWidgets( w ) || // has widget children isParentToDragged( w ) || // has had widget children w->parentWidget() == 0 ) { // is top level window hostWidget = w; menu->popup( w->mapToGlobal( e->pos() ) ); return TRUE; } if ( !draggedDict.find( (long) w ) ) { DraggedInfo *tmp = new DraggedInfo; tmp->w = w; tmp->mother = w->parentWidget(); tmp->pos = w->frameGeometry().topLeft(); draggedDict.insert( (long) w, tmp ); } dragBackground = w->backgroundColor(); dragForeground = w->foregroundColor(); dragInfo.w = w; dragInfo.mother = w->parentWidget(); dragInfo.pos = w->frameGeometry().topLeft(); clickOffset = e->pos(); dragInfo.w = w; QPoint p = w->mapToGlobal(QPoint(0,0)); w->reparent( 0, WType_Popup, p, TRUE ); return TRUE; } case QEvent::MouseButtonRelease: case QEvent::MouseMove: { if ( dragInfo.w != 0 ) { QPoint p = QCursor::pos() - clickOffset; dragInfo.w->move( p ); if ( e->type() == QEvent::MouseMove ) return TRUE; } else { return FALSE; } if ( !dragInfo.w ) return FALSE; if ( w != dragInfo.w ) w = dragInfo.w; dragInfo.w = 0; w->hide(); QPoint pos; QWidget *target = cursorWidget( &pos ); pos = pos - clickOffset; QPoint p; if ( !target ) { target = openDropWindow( QRect( pos, w->size() ), FALSE); p = QPoint( 0, 0 ); } else p = target->mapFromGlobal( pos ); w->reparent( target, 0, p, TRUE ); DropInfo *tmp = dropDict.find( (long) dragInfo.mother ); if ( tmp ) { if ( !tmp->userOpened && noWidgets( tmp->w ) ) dropDict.remove( (long) tmp->w ); } if ( !target->isVisible() ) target->show(); } return TRUE; default: return FALSE; } } bool QDragger::killDropEvent( QMouseEvent *e ) { switch( e->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: clickedWidget = cursorWidget(); return TRUE; case QEvent::MouseButtonRelease: hostWidget->releaseMouse(); if ( clickedWidget ) { DropInfo *tmp = dropDict.find( (long) clickedWidget ); if( tmp ) { killDropWindow( tmp ); dropDict.remove( (long) tmp->w ); } } grabFinished(); return TRUE; case QEvent::MouseMove: return TRUE; default: break; } return FALSE; } bool QDragger::sendChildEvent( QMouseEvent *e ) { switch( e->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: clickedWidget = cursorWidget(); return TRUE; case QEvent::MouseButtonRelease: hostWidget->releaseMouse(); if ( clickedWidget ) { DraggedInfo *tmp = draggedDict.find((long) clickedWidget); if( tmp ) { QWidget *parent = tmp->w->parentWidget(); sendChildHome( tmp ); DropInfo *dri = dropDict.find( (long) parent ); if ( dri && noWidgets(dri->w) && !dri->userOpened ) { killDropWindow( dri ); dropDict.remove( (long) dri ); } } grabFinished(); } return TRUE; case QEvent::MouseMove: return TRUE; default: break; } return FALSE; } bool QDragger::startGrab() { if ( !hostWidget ) return FALSE; clickedWidget = 0; cursor = hostWidget->cursor(); hostWidget->grabMouse(); hostWidget->setCursor( QCursor( CrossCursor ) ); return TRUE; } void QDragger::grabFinished() { killingDrop = FALSE; sendingChild = FALSE; if(hostWidget) hostWidget->setCursor( cursor ); } void QDragger::closeDropWindow( DropWindow *w ) { DropInfo *tmp = dropDict.find( (long) w); if( tmp ) killDropWindow( tmp ); } void QDragger::openDropWindow() { QWidget *tmp = openDropWindow( QRect(100, 100, 300, 200), TRUE ); tmp->show(); } QWidget *QDragger::openDropWindow( const QRect &r, bool user ) { DropInfo *tmp = new DropInfo; DropWindow *w = new DropWindow; if ( user ) { tmp->userOpened = TRUE; w->setCaption( "Drop window" ); } else { tmp->userOpened = FALSE; w->setCaption( "Auto drop window" ); } tmp->w = w; w->master = this; w->setGeometry( r ); dropDict.insert( (long) w, tmp ); w->show(); return w; } void QDragger::killDropWindow() { if ( startGrab() ) killingDrop = TRUE; } void QDragger::killDropWindow( DropInfo *di ) { const QObjectList *l = di->w->children(); if ( !l ) return; QObjectListIt iter( *l ); QObject *tmp; while( (tmp = iter.current()) ) { ++iter; if ( tmp->isWidgetType() ) { DraggedInfo *dri = draggedDict.find( (long) tmp ); if ( dri ) { sendChildHome( dri ); draggedDict.remove( (long) tmp ); } } } di->w->hide(); } void QDragger::killAllDropWindows() { killAllDropWindows( FALSE ); } void QDragger::killAllDropWindows( bool autoOnly ) { QIntDictIterator iter( dropDict ); DropInfo *tmp; while( (tmp = iter.current()) ) { ++iter; if( !autoOnly || !tmp->userOpened ) { killDropWindow( tmp ); dropDict.remove( (long) tmp->w ); } } } void QDragger::sendChildHome( DraggedInfo *i ) { i->w->reparent( i->mother, 0, i->pos, TRUE ); } void QDragger::sendChildHome() { if ( startGrab() ) sendingChild = TRUE; } void QDragger::sendAllChildrenHome() { QIntDictIterator iter( draggedDict ); DraggedInfo *tmp; while( (tmp = iter.current()) ) { ++iter; sendChildHome( tmp ); draggedDict.remove( (long) tmp->w ); } killAllDropWindows( TRUE ); draggedDict.clear(); } QWidget *cursorWidget( QPoint *p ) { QPoint curpos = QCursor::pos(); if ( p ) *p = curpos; return QApplication::widgetAt( curpos ); } #include "qdragapp.moc"