diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kdeui/kpassivepopup.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdeui/kpassivepopup.cpp')
-rw-r--r-- | kdeui/kpassivepopup.cpp | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/kdeui/kpassivepopup.cpp b/kdeui/kpassivepopup.cpp new file mode 100644 index 000000000..9da71013b --- /dev/null +++ b/kdeui/kpassivepopup.cpp @@ -0,0 +1,498 @@ +/* + * copyright : (C) 2001-2002 by Richard Moore + * copyright : (C) 2004-2005 by Sascha Cunz + * License : This file is released under the terms of the LGPL, version 2. + * email : rich@kde.org + * email : sascha.cunz@tiscali.de + */ + +#include <kconfig.h> + +#include <qapplication.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qvbox.h> +#include <qpainter.h> +#include <qtooltip.h> +#include <qbitmap.h> +#include <qpointarray.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <kpixmap.h> +#include <kpixmapeffect.h> +#include <kglobalsettings.h> + +#include "config.h" +#ifdef Q_WS_X11 +#include <netwm.h> +#endif + +#include "kpassivepopup.h" +#include "kpassivepopup.moc" + +class KPassivePopup::Private +{ +public: + int popupStyle; + QPointArray surround; + QPoint anchor; + QPoint fixedPosition; +}; + +static const int DEFAULT_POPUP_TYPE = KPassivePopup::Boxed; +static const int DEFAULT_POPUP_TIME = 6*1000; +static const int POPUP_FLAGS = Qt::WStyle_Customize | Qt::WDestructiveClose | Qt::WX11BypassWM + | Qt::WStyle_StaysOnTop | Qt::WStyle_Tool | Qt::WStyle_NoBorder; + +KPassivePopup::KPassivePopup( QWidget *parent, const char *name, WFlags f ) + : QFrame( 0, name, f ? f : POPUP_FLAGS ), + window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ), + hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ), + m_autoDelete( false ) +{ + init( DEFAULT_POPUP_TYPE ); +} + +KPassivePopup::KPassivePopup( WId win, const char *name, WFlags f ) + : QFrame( 0, name, f ? f : POPUP_FLAGS ), + window( win ), msgView( 0 ), topLayout( 0 ), + hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ), + m_autoDelete( false ) +{ + init( DEFAULT_POPUP_TYPE ); +} + +KPassivePopup::KPassivePopup( int popupStyle, QWidget *parent, const char *name, WFlags f ) + : QFrame( 0, name, f ? f : POPUP_FLAGS ), + window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ), + hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ), + m_autoDelete( false ) +{ + init( popupStyle ); +} + +KPassivePopup::KPassivePopup( int popupStyle, WId win, const char *name, WFlags f ) + : QFrame( 0, name, f ? f : POPUP_FLAGS ), + window( win ), msgView( 0 ), topLayout( 0 ), + hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new QTimer( this, "hide_timer" ) ), + m_autoDelete( false ) +{ + init( popupStyle ); +} + +void KPassivePopup::init( int popupStyle ) +{ + d = new Private; + d->popupStyle = popupStyle; + if( popupStyle == Boxed ) + { + setFrameStyle( QFrame::Box| QFrame::Plain ); + setLineWidth( 2 ); + } + else if( popupStyle == Balloon ) + { + setPalette(QToolTip::palette()); + setAutoMask(TRUE); + } + connect( hideTimer, SIGNAL( timeout() ), SLOT( hide() ) ); + connect( this, SIGNAL( clicked() ), SLOT( hide() ) ); +} + +KPassivePopup::~KPassivePopup() +{ + delete d; +} + +void KPassivePopup::setView( QWidget *child ) +{ + delete msgView; + msgView = child; + + delete topLayout; + topLayout = new QVBoxLayout( this, d->popupStyle == Balloon ? 22 : KDialog::marginHint(), KDialog::spacingHint() ); + topLayout->addWidget( msgView ); + topLayout->activate(); +} + +void KPassivePopup::setView( const QString &caption, const QString &text, + const QPixmap &icon ) +{ + // kdDebug() << "KPassivePopup::setView " << caption << ", " << text << endl; + setView( standardView( caption, text, icon, this ) ); +} + +QVBox * KPassivePopup::standardView( const QString& caption, + const QString& text, + const QPixmap& icon, + QWidget *parent ) +{ + QVBox *vb = new QVBox( parent ? parent : this ); + vb->setSpacing( KDialog::spacingHint() ); + + QHBox *hb=0; + if ( !icon.isNull() ) { + hb = new QHBox( vb ); + hb->setMargin( 0 ); + hb->setSpacing( KDialog::spacingHint() ); + ttlIcon = new QLabel( hb, "title_icon" ); + ttlIcon->setPixmap( icon ); + ttlIcon->setAlignment( AlignLeft ); + } + + if ( !caption.isEmpty() ) { + ttl = new QLabel( caption, hb ? hb : vb, "title_label" ); + QFont fnt = ttl->font(); + fnt.setBold( true ); + ttl->setFont( fnt ); + ttl->setAlignment( Qt::AlignHCenter ); + if ( hb ) + hb->setStretchFactor( ttl, 10 ); // enforce centering + } + + if ( !text.isEmpty() ) { + msg = new QLabel( text, vb, "msg_label" ); + msg->setAlignment( AlignLeft ); + } + + return vb; +} + +void KPassivePopup::setView( const QString &caption, const QString &text ) +{ + setView( caption, text, QPixmap() ); +} + +void KPassivePopup::setTimeout( int delay ) +{ + hideDelay = delay; + if( hideTimer->isActive() ) + { + if( delay ) { + hideTimer->changeInterval( delay ); + } else { + hideTimer->stop(); + } + } +} + +void KPassivePopup::setAutoDelete( bool autoDelete ) +{ + m_autoDelete = autoDelete; +} + +void KPassivePopup::mouseReleaseEvent( QMouseEvent *e ) +{ + emit clicked(); + emit clicked( e->pos() ); +} + +// +// Main Implementation +// + +void KPassivePopup::show() +{ + if ( size() != sizeHint() ) + resize( sizeHint() ); + + if ( d->fixedPosition.isNull() ) + positionSelf(); + else { + if( d->popupStyle == Balloon ) + setAnchor( d->fixedPosition ); + else + move( d->fixedPosition ); + } + QFrame::show(); + + int delay = hideDelay; + if ( delay < 0 ) { + delay = DEFAULT_POPUP_TIME; + } + + if ( delay > 0 ) { + hideTimer->start( delay ); + } +} + +void KPassivePopup::show(const QPoint &p) +{ + d->fixedPosition = p; + show(); +} + +void KPassivePopup::hideEvent( QHideEvent * ) +{ + hideTimer->stop(); + if ( m_autoDelete ) + deleteLater(); +} + +QRect KPassivePopup::defaultArea() const +{ +#ifdef Q_WS_X11 + NETRootInfo info( qt_xdisplay(), + NET::NumberOfDesktops | + NET::CurrentDesktop | + NET::WorkArea, + -1, false ); + info.activate(); + NETRect workArea = info.workArea( info.currentDesktop() ); + QRect r; + r.setRect( workArea.pos.x, workArea.pos.y, 0, 0 ); // top left +#else + // FIX IT + QRect r; + r.setRect( 100, 100, 200, 200 ); // top left +#endif + return r; +} + +void KPassivePopup::positionSelf() +{ + QRect target; + +#ifdef Q_WS_X11 + if ( !window ) { + target = defaultArea(); + } + + else { + NETWinInfo ni( qt_xdisplay(), window, qt_xrootwin(), + NET::WMIconGeometry | NET::WMKDESystemTrayWinFor ); + + // Figure out where to put the popup. Note that we must handle + // windows that skip the taskbar cleanly + if ( ni.kdeSystemTrayWinFor() ) { + NETRect frame, win; + ni.kdeGeometry( frame, win ); + target.setRect( win.pos.x, win.pos.y, + win.size.width, win.size.height ); + } + else if ( ni.state() & NET::SkipTaskbar ) { + target = defaultArea(); + } + else { + NETRect r = ni.iconGeometry(); + target.setRect( r.pos.x, r.pos.y, r.size.width, r.size.height ); + if ( target.isNull() ) { // bogus value, use the exact position + NETRect dummy; + ni.kdeGeometry( dummy, r ); + target.setRect( r.pos.x, r.pos.y, + r.size.width, r.size.height); + } + } + } +#else + target = defaultArea(); +#endif + moveNear( target ); +} + +void KPassivePopup::moveNear( QRect target ) +{ + QPoint pos = target.topLeft(); + int x = pos.x(); + int y = pos.y(); + int w = width(); + int h = height(); + + QRect r = KGlobalSettings::desktopGeometry(QPoint(x+w/2,y+h/2)); + + if( d->popupStyle == Balloon ) + { + // find a point to anchor to + if( x + w > r.width() ){ + x = x + target.width(); + } + + if( y + h > r.height() ){ + y = y + target.height(); + } + } else + { + if ( x < r.center().x() ) + x = x + target.width(); + else + x = x - w; + + // It's apparently trying to go off screen, so display it ALL at the bottom. + if ( (y + h) > r.bottom() ) + y = r.bottom() - h; + + if ( (x + w) > r.right() ) + x = r.right() - w; + } + if ( y < r.top() ) + y = r.top(); + + if ( x < r.left() ) + x = r.left(); + + if( d->popupStyle == Balloon ) + setAnchor( QPoint( x, y ) ); + else + move( x, y ); +} + +void KPassivePopup::setAnchor(const QPoint &anchor) +{ + d->anchor = anchor; + updateMask(); +} + +void KPassivePopup::paintEvent( QPaintEvent* pe ) +{ + if( d->popupStyle == Balloon ) + { + QPainter p; + p.begin( this ); + p.drawPolygon( d->surround ); + } else + QFrame::paintEvent( pe ); +} + +void KPassivePopup::updateMask() +{ + // get screen-geometry for screen our anchor is on + // (geometry can differ from screen to screen! + QRect deskRect = KGlobalSettings::desktopGeometry(d->anchor); + + int xh = 70, xl = 40; + if( width() < 80 ) + xh = xl = 40; + else if( width() < 110 ) + xh = width() - 40; + + bool bottom = (d->anchor.y() + height()) > ((deskRect.y() + deskRect.height()-48)); + bool right = (d->anchor.x() + width()) > ((deskRect.x() + deskRect.width()-48)); + + QPoint corners[4] = { + QPoint( width() - 50, 10 ), + QPoint( 10, 10 ), + QPoint( 10, height() - 50 ), + QPoint( width() - 50, height() - 50 ) + }; + + QBitmap mask( width(), height(), true ); + QPainter p( &mask ); + QBrush brush( Qt::white, Qt::SolidPattern ); + p.setBrush( brush ); + + int i = 0, z = 0; + for (; i < 4; ++i) { + QPointArray corner; + corner.makeArc(corners[i].x(), corners[i].y(), 40, 40, i * 16 * 90, 16 * 90); + + d->surround.resize( z + corner.count() ); + for (unsigned int s = 0; s < corner.count() - 1; s++) { + d->surround.setPoint( z++, corner[s] ); + } + + if (bottom && i == 2) { + if (right) { + d->surround.resize( z + 3 ); + d->surround.setPoint( z++, QPoint( width() - xh, height() - 11 ) ); + d->surround.setPoint( z++, QPoint( width() - 20, height() ) ); + d->surround.setPoint( z++, QPoint( width() - xl, height() - 11 ) ); + } else { + d->surround.resize( z + 3 ); + d->surround.setPoint( z++, QPoint( xl, height() - 11 ) ); + d->surround.setPoint( z++, QPoint( 20, height() ) ); + d->surround.setPoint( z++, QPoint( xh, height() - 11 ) ); + } + } else if (!bottom && i == 0) { + if (right) { + d->surround.resize( z + 3 ); + d->surround.setPoint( z++, QPoint( width() - xl, 10 ) ); + d->surround.setPoint( z++, QPoint( width() - 20, 0 ) ); + d->surround.setPoint( z++, QPoint( width() - xh, 10 ) ); + } else { + d->surround.resize( z + 3 ); + d->surround.setPoint( z++, QPoint( xh, 10 ) ); + d->surround.setPoint( z++, QPoint( 20, 0 ) ); + d->surround.setPoint( z++, QPoint( xl, 10 ) ); + } + } + } + + d->surround.resize( z + 1 ); + d->surround.setPoint( z, d->surround[0] ); + p.drawPolygon( d->surround ); + setMask(mask); + + move( right ? d->anchor.x() - width() + 20 : ( d->anchor.x() < 11 ? 11 : d->anchor.x() - 20 ), + bottom ? d->anchor.y() - height() : ( d->anchor.y() < 11 ? 11 : d->anchor.y() ) ); + + update(); +} + +// +// Convenience Methods +// + +KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text, + const QPixmap &icon, + QWidget *parent, const char *name, int timeout ) +{ + return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout ); +} + +KPassivePopup *KPassivePopup::message( const QString &text, QWidget *parent, const char *name ) +{ + return message( DEFAULT_POPUP_TYPE, QString::null, text, QPixmap(), parent, name ); +} + +KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text, + QWidget *parent, const char *name ) +{ + return message( DEFAULT_POPUP_TYPE, caption, text, QPixmap(), parent, name ); +} + +KPassivePopup *KPassivePopup::message( const QString &caption, const QString &text, + const QPixmap &icon, WId parent, const char *name, int timeout ) +{ + return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout ); +} + +KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text, + const QPixmap &icon, + QWidget *parent, const char *name, int timeout ) +{ + KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name ); + pop->setAutoDelete( true ); + pop->setView( caption, text, icon ); + pop->hideDelay = timeout; + pop->show(); + + return pop; +} + +KPassivePopup *KPassivePopup::message( int popupStyle, const QString &text, QWidget *parent, const char *name ) +{ + return message( popupStyle, QString::null, text, QPixmap(), parent, name ); +} + +KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text, + QWidget *parent, const char *name ) +{ + return message( popupStyle, caption, text, QPixmap(), parent, name ); +} + +KPassivePopup *KPassivePopup::message( int popupStyle, const QString &caption, const QString &text, + const QPixmap &icon, WId parent, const char *name, int timeout ) +{ + KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name ); + pop->setAutoDelete( true ); + pop->setView( caption, text, icon ); + pop->hideDelay = timeout; + pop->show(); + + return pop; +} + +// Local Variables: +// c-basic-offset: 4 +// End: |