You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qt3/examples/tetrix/qdragapp.cpp

503 lines
11 KiB

/****************************************************************************
**
** 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<QWidget> hostWidget;
QCursor cursor;
QPopupMenu* menu;
QPoint clickOffset;
QColor dragBackground;
QColor dragForeground;
DraggedInfo dragInfo;
QIntDict<DraggedInfo> draggedDict;
QIntDict<DropInfo> 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<DraggedInfo> 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<DropInfo> 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<DraggedInfo> 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"