• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libkdegames

kgamepopupitem.cpp

Go to the documentation of this file.
00001 /*******************************************************************
00002     Copyright 2007 Dmitry Suzdalev <dimsuz@gmail.com>
00003 
00004     This library is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00017  ********************************************************************/
00018 #include "kgamepopupitem.h"
00019 #include <QPainter>
00020 #include <QTimeLine>
00021 #include <QTimer>
00022 #include <QGraphicsScene>
00023 #include <QGraphicsView>
00024 #include <QGraphicsTextItem>
00025 
00026 #include <KIcon>
00027 #include <KDebug>
00028 #include <kcolorscheme.h>
00029 
00030 // margin on the sides of message box
00031 static const int MARGIN = 15;
00032 // offset of message from start of the scene
00033 static const int SHOW_OFFSET = 5;
00034 // space between pixmap and text
00035 static const int SOME_SPACE = 10;
00036 // width of the border in pixels
00037 static const qreal BORDER_PEN_WIDTH = 1.0;
00038 
00039 class TextItemWithOpacity : public QGraphicsTextItem
00040 {
00041 public:
00042     TextItemWithOpacity( QGraphicsItem* parent = 0 )
00043         :QGraphicsTextItem(parent), m_opacity(1.0) {}
00044     void setOpacity(qreal opa) { m_opacity = opa; }
00045     void setTextColor(KStatefulBrush brush) { m_brush = brush; }
00046     virtual void paint( QPainter* p, const QStyleOptionGraphicsItem *option, QWidget* widget )
00047         {
00048             // hope that it is ok to call this function here - i.e. I hope it won't be too expensive :)
00049             // we call it here (and not in setTextColor), because KstatefulBrush
00050             // absolutely needs QWidget parameter :)
00051             setDefaultTextColor(m_brush.brush(widget).color());
00052             p->save();
00053             p->setOpacity(m_opacity);
00054             QGraphicsTextItem::paint(p,option,widget);
00055             p->restore();
00056         }
00057 private:
00058     qreal m_opacity;
00059     KStatefulBrush m_brush;
00060 };
00061 
00062 class KGamePopupItemPrivate
00063 {
00064 private:
00065     KGamePopupItemPrivate(const KGamePopupItemPrivate&);
00066     const KGamePopupItemPrivate& operator=(const KGamePopupItemPrivate&);
00067 public:
00068     KGamePopupItemPrivate()
00069         : m_position( KGamePopupItem::BottomLeft ), m_timeout(2000),
00070           m_opacity(1.0), m_animOpacity(-1), m_hoveredByMouse(false),
00071           m_hideOnClick(false), m_textChildItem(0),
00072           m_sharpness(KGamePopupItem::Square) {}
00076     QTimeLine m_timeLine;
00080     QTimer m_timer;
00084     QRectF m_boundRect;
00088     KGamePopupItem::Position m_position;
00092     int m_timeout;
00096     qreal m_opacity;
00100     qreal m_animOpacity;
00104     QPixmap m_iconPix;
00108     bool m_hoveredByMouse;
00112     bool m_hideOnClick;
00116     TextItemWithOpacity* m_textChildItem;
00122     QRectF m_visibleSceneRect;
00126     KStatefulBrush m_brush;
00130     KGamePopupItem::Sharpness m_sharpness;
00134     QPainterPath m_path;
00135 };
00136 
00137 KGamePopupItem::KGamePopupItem(QGraphicsItem * parent)
00138     : QGraphicsItem(parent), d(new KGamePopupItemPrivate)
00139 {
00140     hide();
00141     d->m_textChildItem = new TextItemWithOpacity(this);
00142     d->m_textChildItem->setTextInteractionFlags( Qt::LinksAccessibleByMouse );
00143     // above call said to enable ItemIsFocusable which we don't need.
00144     // So disabling it
00145     d->m_textChildItem->setFlag( QGraphicsItem::ItemIsFocusable, false );
00146 
00147     connect( d->m_textChildItem, SIGNAL(linkActivated(const QString&)),
00148                                  SIGNAL(linkActivated(const QString&)));
00149     connect( d->m_textChildItem, SIGNAL(linkHovered(const QString&)),
00150                                  SLOT(onLinkHovered(const QString&)));
00151 
00152     setZValue(100); // is 100 high enough???
00153     d->m_textChildItem->setZValue(100);
00154 
00155     KIcon infoIcon("dialog-information");
00156     // default size is 32
00157     setMessageIcon( infoIcon.pixmap(32, 32) );
00158 
00159     d->m_timer.setSingleShot(true);
00160 
00161     setAcceptsHoverEvents(true);
00162     // ignore scene transformations
00163     setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
00164 
00165     // setup default colors
00166     d->m_brush = KStatefulBrush( KColorScheme::Tooltip, KColorScheme::NormalBackground );
00167     d->m_textChildItem->setTextColor( KStatefulBrush(KColorScheme::Tooltip, KColorScheme::NormalText) );
00168 
00169     connect( &d->m_timeLine, SIGNAL(frameChanged(int)), SLOT(animationFrame(int)) );
00170     connect( &d->m_timeLine, SIGNAL(finished()), SLOT(hideMe()));
00171     connect( &d->m_timer, SIGNAL(timeout()), SLOT(playHideAnimation()) );
00172 }
00173 
00174 void KGamePopupItem::paint( QPainter* p, const QStyleOptionGraphicsItem *option, QWidget* widget )
00175 {
00176     Q_UNUSED(option);
00177     Q_UNUSED(widget);
00178 
00179     p->save();
00180 
00181     QPen pen = p->pen();
00182     pen.setWidthF( BORDER_PEN_WIDTH );
00183     p->setPen(pen);
00184 
00185     if( d->m_animOpacity != -1) // playing Center animation
00186         p->setOpacity(d->m_animOpacity);
00187     else
00188         p->setOpacity(d->m_opacity);
00189     p->setBrush(d->m_brush.brush(widget));
00190     p->drawPath(d->m_path);
00191     p->drawPixmap( MARGIN, static_cast<int>(d->m_boundRect.height()/2) - d->m_iconPix.height()/2,
00192                    d->m_iconPix );
00193     p->restore();
00194 }
00195 
00196 void KGamePopupItem::showMessage( const QString& text, Position pos, ReplaceMode mode )
00197 {
00198     if(d->m_timeLine.state() == QTimeLine::Running || d->m_timer.isActive())
00199     {
00200         if (mode == ReplacePrevious)
00201             forceHide(InstantHide);
00202         else
00203             return;// we're already showing a message
00204     }
00205 
00206     // NOTE: we blindly take first visible view we found. I.e. we don't support
00207     // multiple views. If no visible scene is found, we simply pick the first one.
00208     QGraphicsView *sceneView = 0;
00209     foreach (QGraphicsView *view, scene()->views()) {
00210         if (view->isVisible()) {
00211             sceneView = view;
00212             break;
00213         }
00214     }
00215     if (!sceneView)
00216         sceneView = scene()->views().at(0);
00217 
00218     QPolygonF poly = sceneView->mapToScene( sceneView->viewport()->contentsRect() );
00219     d->m_visibleSceneRect = poly.boundingRect();
00220 
00221     d->m_textChildItem->setHtml(text);
00222 
00223     d->m_position = pos;
00224 
00225     // do as QGS docs say: notify the scene about rect change
00226     prepareGeometryChange();
00227 
00228     // recalculate bounding rect
00229     qreal w = d->m_textChildItem->boundingRect().width()+MARGIN*2+d->m_iconPix.width()+SOME_SPACE;
00230     qreal h = d->m_textChildItem->boundingRect().height()+MARGIN*2;
00231     if( d->m_iconPix.height() > h )
00232         h = d->m_iconPix.height() + MARGIN*2;
00233     d->m_boundRect = QRectF(0, 0, w, h);
00234 
00235     // adjust to take into account the width of the pen
00236     // used to draw the border
00237     const qreal borderRadius = BORDER_PEN_WIDTH / 2.0;
00238     d->m_boundRect.adjust( -borderRadius ,
00239                            -borderRadius ,
00240                             borderRadius ,
00241                             borderRadius );
00242 
00243     QPainterPath roundRectPath;
00244     roundRectPath.moveTo(w, d->m_sharpness);
00245     roundRectPath.arcTo(w-(2*d->m_sharpness), 0.0,(2*d->m_sharpness), (d->m_sharpness), 0.0, 90.0);
00246     roundRectPath.lineTo(d->m_sharpness, 0.0);
00247     roundRectPath.arcTo(0.0, 0.0, (2*d->m_sharpness), (2*d->m_sharpness), 90.0, 90.0);
00248     roundRectPath.lineTo(0.0, h-(d->m_sharpness));
00249     roundRectPath.arcTo(0.0, h-(2*d->m_sharpness), 2*d->m_sharpness, 2*d->m_sharpness, 180.0, 90.0);
00250     roundRectPath.lineTo(w-(d->m_sharpness), h);
00251     roundRectPath.arcTo(w-(2*d->m_sharpness), h-(2*d->m_sharpness), (2*d->m_sharpness), (2*d->m_sharpness), 270.0, 90.0);
00252     roundRectPath.closeSubpath();
00253 
00254     d->m_path = roundRectPath;
00255 
00256     // adjust y-pos of text item so it appears centered
00257     d->m_textChildItem->setPos( d->m_textChildItem->x(),
00258                                 d->m_boundRect.height()/2 - d->m_textChildItem->boundingRect().height()/2);
00259 
00260     // setup animation
00261     setupTimeline();
00262 
00263     // move to the start position
00264     animationFrame(d->m_timeLine.startFrame());
00265     show();
00266     d->m_timeLine.start();
00267 
00268     if(d->m_timeout != 0)
00269     {
00270         // 300 msec to animate showing message + d->m_timeout to stay visible => then hide
00271         d->m_timer.start( 300+d->m_timeout );
00272     }
00273 }
00274 
00275 void KGamePopupItem::setupTimeline()
00276 {
00277     d->m_timeLine.setDirection( QTimeLine::Forward );
00278     d->m_timeLine.setDuration(300);
00279     if( d->m_position == TopLeft || d->m_position == TopRight )
00280     {
00281         int start = static_cast<int>(d->m_visibleSceneRect.top() - d->m_boundRect.height() - SHOW_OFFSET);
00282         int end = static_cast<int>(d->m_visibleSceneRect.top() + SHOW_OFFSET);
00283         d->m_timeLine.setFrameRange( start, end );
00284     }
00285     else if( d->m_position == BottomLeft || d->m_position == BottomRight )
00286     {
00287         int start = static_cast<int>(d->m_visibleSceneRect.bottom()+SHOW_OFFSET);
00288         int end = static_cast<int>(d->m_visibleSceneRect.bottom() - d->m_boundRect.height() - SHOW_OFFSET);
00289         d->m_timeLine.setFrameRange( start, end );
00290     }
00291     else if( d->m_position == Center )
00292     {
00293         d->m_timeLine.setFrameRange(0, d->m_timeLine.duration());
00294         setPos( d->m_visibleSceneRect.left() +
00295                 d->m_visibleSceneRect.width()/2 - d->m_boundRect.width()/2,
00296                 d->m_visibleSceneRect.top() +
00297                 d->m_visibleSceneRect.height()/2 - d->m_boundRect.height()/2);
00298     }
00299 
00300 }
00301 
00302 void KGamePopupItem::animationFrame(int frame)
00303 {
00304     if( d->m_position == TopLeft || d->m_position == BottomLeft )
00305         setPos( d->m_visibleSceneRect.left()+SHOW_OFFSET, frame );
00306     else if( d->m_position == TopRight || d->m_position == BottomRight )
00307         setPos( d->m_visibleSceneRect.right()-d->m_boundRect.width()-SHOW_OFFSET, frame );
00308     else if( d->m_position == Center )
00309     {
00310         d->m_animOpacity = frame*d->m_opacity/d->m_timeLine.duration();
00311         d->m_textChildItem->setOpacity( d->m_animOpacity );
00312         update();
00313     }
00314 }
00315 
00316 void KGamePopupItem::playHideAnimation()
00317 {
00318     if( d->m_hoveredByMouse )
00319         return;
00320 
00321     // let's hide
00322     d->m_timeLine.setDirection( QTimeLine::Backward );
00323     d->m_timeLine.start();
00324 }
00325 
00326 void KGamePopupItem::setMessageTimeout( int msec )
00327 {
00328     d->m_timeout = msec;
00329 }
00330 
00331 void KGamePopupItem::setHideOnMouseClick( bool hide )
00332 {
00333     d->m_hideOnClick = hide;
00334 }
00335 
00336 bool KGamePopupItem::hidesOnMouseClick() const
00337 {
00338     return d->m_hideOnClick;
00339 }
00340 
00341 void KGamePopupItem::setMessageOpacity( qreal opacity )
00342 {
00343     d->m_opacity = opacity;
00344     d->m_textChildItem->setOpacity(opacity);
00345 }
00346 
00347 QRectF KGamePopupItem::boundingRect() const
00348 {
00349     return d->m_boundRect;
00350 }
00351 
00352 KGamePopupItem::~KGamePopupItem()
00353 {
00354     delete d;
00355 }
00356 
00357 void KGamePopupItem::hideMe()
00358 {
00359     d->m_animOpacity = -1;
00360     // and restore child's opacity too
00361     d->m_textChildItem->setOpacity(d->m_opacity);
00362 
00363     // if we just got moved out of visibility, let's do more - let's hide :)
00364     if( d->m_timeLine.direction() == QTimeLine::Backward )
00365     {
00366         hide();
00367         emit hidden();
00368     }
00369 }
00370 
00371 void KGamePopupItem::hoverEnterEvent( QGraphicsSceneHoverEvent* )
00372 {
00373     d->m_hoveredByMouse = true;
00374 }
00375 
00376 void KGamePopupItem::hoverLeaveEvent( QGraphicsSceneHoverEvent* )
00377 {
00378     d->m_hoveredByMouse = false;
00379 
00380     if( d->m_timeout != 0 && !d->m_timer.isActive() && d->m_timeLine.state() != QTimeLine::Running )
00381         playHideAnimation(); // let's hide
00382 }
00383 
00384 void KGamePopupItem::setMessageIcon( const QPixmap& pix )
00385 {
00386     d->m_iconPix = pix;
00387     d->m_textChildItem->setPos( MARGIN+pix.width()+SOME_SPACE, MARGIN );
00388     // bounding rect is updated in showMessage()
00389 }
00390 
00391 int KGamePopupItem::messageTimeout() const
00392 {
00393     return d->m_timeout;
00394 }
00395 
00396 void KGamePopupItem::forceHide(HideType howToHide)
00397 {
00398     if(!isVisible())
00399         return;
00400 
00401     if(howToHide == InstantHide)
00402     {
00403         d->m_timeLine.stop();
00404         d->m_timer.stop();
00405         hide();
00406         emit hidden();
00407     }
00408     else if(howToHide == AnimatedHide)
00409     {
00410         // forcefully unset it even if it is set
00411         // so we'll hide in any event
00412         d->m_hoveredByMouse = false;
00413         d->m_timer.stop();
00414         playHideAnimation();
00415     }
00416 }
00417 
00418 qreal KGamePopupItem::messageOpacity() const
00419 {
00420     return d->m_opacity;
00421 }
00422 
00423 void KGamePopupItem::setBackgroundBrush( const QBrush& brush )
00424 {
00425     d->m_brush = KStatefulBrush(brush);
00426 }
00427 
00428 void KGamePopupItem::setTextColor( const QColor& color )
00429 {
00430     KStatefulBrush brush(color, d->m_brush.brush(QPalette::Active));
00431     d->m_textChildItem->setTextColor(brush);
00432 }
00433 
00434 void KGamePopupItem::onLinkHovered(const QString& link)
00435 {
00436     if(link.isEmpty())
00437         d->m_textChildItem->setCursor( Qt::ArrowCursor );
00438     else
00439         d->m_textChildItem->setCursor( Qt::PointingHandCursor );
00440     emit linkHovered(link);
00441 }
00442 
00443 void KGamePopupItem::setSharpness( Sharpness sharpness )
00444 {
00445     d->m_sharpness = sharpness;
00446 }
00447 
00448 KGamePopupItem::Sharpness KGamePopupItem::sharpness() const
00449 {
00450     return d->m_sharpness;
00451 }
00452 
00453 void KGamePopupItem::mousePressEvent( QGraphicsSceneMouseEvent* )
00454 {
00455     // it is needed to reimplement this function to receive future
00456     // mouse release events
00457 }
00458 
00459 void KGamePopupItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* )
00460 {
00461     if (d->m_hideOnClick)
00462         forceHide();
00463 }
00464 
00465 
00466 #include "kgamepopupitem.moc"

libkdegames

Skip menu "libkdegames"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • kblackbox
  • kgoldrunner
  • kmahjongg
  • ksquares
  • libkdegames
  •   highscore
  •   kgame
  •   kggzgames
  •   kggzmod
  •   kggznet
  • libkmahjongg
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal