00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00031 static const int MARGIN = 15;
00032
00033 static const int SHOW_OFFSET = 5;
00034
00035 static const int SOME_SPACE = 10;
00036
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
00049
00050
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
00144
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);
00153 d->m_textChildItem->setZValue(100);
00154
00155 KIcon infoIcon("dialog-information");
00156
00157 setMessageIcon( infoIcon.pixmap(32, 32) );
00158
00159 d->m_timer.setSingleShot(true);
00160
00161 setAcceptsHoverEvents(true);
00162
00163 setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
00164
00165
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)
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;
00204 }
00205
00206
00207
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
00226 prepareGeometryChange();
00227
00228
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
00236
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
00257 d->m_textChildItem->setPos( d->m_textChildItem->x(),
00258 d->m_boundRect.height()/2 - d->m_textChildItem->boundingRect().height()/2);
00259
00260
00261 setupTimeline();
00262
00263
00264 animationFrame(d->m_timeLine.startFrame());
00265 show();
00266 d->m_timeLine.start();
00267
00268 if(d->m_timeout != 0)
00269 {
00270
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
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
00361 d->m_textChildItem->setOpacity(d->m_opacity);
00362
00363
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();
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
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
00411
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
00456
00457 }
00458
00459 void KGamePopupItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* )
00460 {
00461 if (d->m_hideOnClick)
00462 forceHide();
00463 }
00464
00465
00466 #include "kgamepopupitem.moc"