kgamecanvas.cpp

Go to the documentation of this file.
00001 /*  Originally created for KBoard
00002     Copyright 2006 Maurizio Monge <maurizio.monge@gmail.com>
00003 
00004 BSD License
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions
00007 are met:
00008 
00009 1. Redistributions of source code must retain the above copyright
00010    notice, this list of conditions and the following disclaimer.
00011 2. Redistributions in binary form must reproduce the above copyright
00012    notice, this list of conditions and the following disclaimer in the
00013    documentation and/or other materials provided with the distribution.
00014 
00015 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00017 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00018 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00019 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00020 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00021 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00022 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00023 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00024 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025  */
00026 
00027 // KGame namespace changes: mauricio@tabuleiro.com
00028 
00029 #include "kgamecanvas.h"
00030 
00031 #include <QPaintEvent>
00032 #include <QPainter>
00033 #include <QRegion>
00034 #include <QApplication>
00035 #include <QTimer>
00036 #include <QTime>
00037 
00038 /*
00039   TODO:
00040     - (maybe) allow an item to be destroyed while calling KGameCanvasItem::advance.
00041     - When a group is hidden/destroyed should only update items (optimize for sparse groups)
00042 */
00043 
00044 #define DEBUG_DONT_MERGE_UPDATES 0
00045 #define DEBUG_CANVAS_PAINTS      0
00046 
00047 /*
00048     KGameCanvasAbstract
00049 */
00050 KGameCanvasAbstract::KGameCanvasAbstract() {
00051 
00052 }
00053 
00054 KGameCanvasAbstract::~KGameCanvasAbstract() {
00055    //Note: this does not delete the items, be sure not to leak memory!
00056    for(int i=0;i<m_items.size();i++)
00057      m_items[i]->m_canvas = NULL;
00058 }
00059 
00060 KGameCanvasItem* KGameCanvasAbstract::itemAt(const QPoint &pt) const {
00061   for(int i=m_items.size()-1;i>=0;i--) {
00062     KGameCanvasItem *el = m_items[i];
00063     if(el->m_visible && el->rect().contains(pt))
00064       return el;
00065   }
00066   return NULL;
00067 }
00068 
00069 QList<KGameCanvasItem*> KGameCanvasAbstract::itemsAt(const QPoint &pt) const {
00070   QList<KGameCanvasItem*> retv;
00071 
00072   for(int i=m_items.size()-1;i>=0;i--) {
00073     KGameCanvasItem *el = m_items[i];
00074     if(el->m_visible && el->rect().contains(pt))
00075       retv.append(el);
00076   }
00077 
00078   return retv;
00079 }
00080 
00081 
00082 /*
00083     KGameCanvasWidget
00084 */
00085 class KGameCanvasWidgetPrivate {
00086 public:
00087   QTimer m_anim_timer;
00088   QTime m_anim_time;
00089   bool m_pending_update;
00090   QRegion m_pending_update_reg;
00091 
00092 #if DEBUG_CANVAS_PAINTS
00093   bool debug_paints;
00094 #endif //DEBUG_CANVAS_PAINTS
00095 
00096   KGameCanvasWidgetPrivate()
00097   : m_pending_update(false)
00098 #if DEBUG_CANVAS_PAINTS
00099   , debug_paints(false)
00100 #endif //DEBUG_CANVAS_PAINTS
00101   {}
00102 };
00103 
00104 KGameCanvasWidget::KGameCanvasWidget(QWidget* parent)
00105 : QWidget(parent)
00106 , priv(new KGameCanvasWidgetPrivate()) {
00107   priv->m_anim_time.start();
00108   connect(&priv->m_anim_timer, SIGNAL(timeout()), this, SLOT(processAnimations()));
00109 }
00110 
00111 KGameCanvasWidget::~KGameCanvasWidget() {
00112   delete priv;
00113 }
00114 
00115 void KGameCanvasWidget::ensureAnimating() {
00116   if(!priv->m_anim_timer.isActive() )
00117       priv->m_anim_timer.start();
00118 }
00119 
00120 void KGameCanvasWidget::ensurePendingUpdate() {
00121   if(priv->m_pending_update)
00122     return;
00123   priv->m_pending_update = true;
00124 
00125 #if DEBUG_DONT_MERGE_UPDATES
00126   updateChanges();
00127 #else //DEBUG_DONT_MERGE_UPDATES
00128   QTimer::singleShot( 0, this, SLOT(updateChanges()) );
00129 #endif //DEBUG_DONT_MERGE_UPDATES
00130 }
00131 
00132 void KGameCanvasWidget::updateChanges() {
00133   for(int i=0;i<m_items.size();i++) {
00134     KGameCanvasItem *el = m_items.at(i);
00135 
00136     if(el->m_changed)
00137       el->updateChanges();
00138   }
00139   priv->m_pending_update = false;
00140 
00141 #if DEBUG_CANVAS_PAINTS
00142   repaint();
00143   priv->debug_paints = true;
00144   repaint( priv->m_pending_update_reg );
00145   QApplication::syncX();
00146   priv->debug_paints = false;
00147   usleep(100000);
00148   repaint( priv->m_pending_update_reg );
00149   QApplication::syncX();
00150   usleep(100000);
00151 #else //DEBUG_CANVAS_PAINTS
00152   repaint( priv->m_pending_update_reg );
00153 #endif //DEBUG_CANVAS_PAINTS
00154 
00155   priv->m_pending_update_reg = QRegion();
00156 }
00157 
00158 void KGameCanvasWidget::invalidate(const QRect& r, bool /*translate*/) {
00159   priv->m_pending_update_reg |= r;
00160   ensurePendingUpdate();
00161 }
00162 
00163 void KGameCanvasWidget::invalidate(const QRegion& r, bool /*translate*/) {
00164   priv->m_pending_update_reg |= r;
00165   ensurePendingUpdate();
00166 }
00167 
00168 void KGameCanvasWidget::paintEvent(QPaintEvent *event) {
00169 #if DEBUG_CANVAS_PAINTS
00170   if(priv->debug_paints)
00171   {
00172     QPainter p(this);
00173     p.fillRect(event->rect(), Qt::magenta);
00174     return;
00175   }
00176 #endif //DEBUG_CANVAS_PAINTS
00177 
00178   {QPainter p(this);
00179   QRect evr = event->rect();
00180   QRegion evreg = event->region();
00181 
00182   for(int i=0;i<m_items.size();i++) {
00183     KGameCanvasItem *el = m_items.at(i);
00184     if( el->m_visible && evr.intersects( el->rect() )
00185         && evreg.contains( el->rect() ) ) {
00186       el->m_last_rect = el->rect();
00187       el->paintInternal(&p, evr, evreg, QPoint(), 1.0 );
00188     }
00189   }}
00190 
00191   QApplication::syncX();
00192 }
00193 
00194 void KGameCanvasWidget::processAnimations() {
00195   if(m_animated_items.empty() ) {
00196     priv->m_anim_timer.stop();
00197     return;
00198   }
00199 
00200   int tm = priv->m_anim_time.elapsed();
00201 
00202   // The list MUST be copied, because it could be modified calling advance.
00203   // After all since it is implicitly shared the copy will not happen unless
00204   // is it actually modified
00205   QList<KGameCanvasItem*> ait = m_animated_items;
00206   for(int i=0;i<ait.size();i++) {
00207     KGameCanvasItem *el = ait[i];
00208     el->advance(tm);
00209   }
00210 
00211   if(m_animated_items.empty() )
00212     priv->m_anim_timer.stop();
00213 }
00214 
00215 void KGameCanvasWidget::setAnimationDelay(int d) {
00216   priv->m_anim_timer.setInterval(d);
00217 }
00218 
00219 int KGameCanvasWidget::mSecs() {
00220   return priv->m_anim_time.elapsed();
00221 }
00222 
00223 KGameCanvasWidget* KGameCanvasWidget::topLevelCanvas() {
00224   return this;
00225 }
00226 
00227 QPoint KGameCanvasWidget::canvasPosition() const {
00228         return QPoint(0, 0);
00229 }
00230 
00231 /*
00232     KGameCanvasItem
00233 */
00234 KGameCanvasItem::KGameCanvasItem(KGameCanvasAbstract* KGameCanvas)
00235 : m_visible(false)
00236 , m_animated(false)
00237 , m_opacity(255)
00238 , m_pos(0,0)
00239 , m_canvas(KGameCanvas)
00240 , m_changed(false) {
00241   if(m_canvas) m_canvas->m_items.append(this);
00242 }
00243 
00244 KGameCanvasItem::~KGameCanvasItem() {
00245   if(m_canvas) {
00246     m_canvas->m_items.removeAll(this);
00247     if(m_animated)
00248       m_canvas->m_animated_items.removeAll(this);
00249     if(m_visible)
00250       m_canvas->invalidate(m_last_rect, false);
00251   }
00252 }
00253 
00254 void KGameCanvasItem::changed() {
00255   m_changed = true;
00256 
00257   //even if m_changed was already true we cannot optimiza away this call, because maybe the
00258   //item has been reparented, etc. It is a very quick call anyway.
00259   if(m_canvas)
00260     m_canvas->ensurePendingUpdate();
00261 }
00262 
00263 void KGameCanvasItem::updateChanges() {
00264   if(!m_changed)
00265     return;
00266   if(m_canvas) {
00267     m_canvas->invalidate(m_last_rect, false);
00268     if(m_visible)
00269       m_canvas->invalidate(rect());
00270   }
00271   m_changed = false;
00272 }
00273 
00274 QPixmap *KGameCanvasItem::transparence_pixmap_cache = NULL;
00275 
00276 QPixmap* KGameCanvasItem::getTransparenceCache(const QSize &s) {
00277   if(!transparence_pixmap_cache)
00278     transparence_pixmap_cache = new QPixmap();
00279   if(s.width()>transparence_pixmap_cache->width() ||
00280     s.height()>transparence_pixmap_cache->height()) {
00281 
00282     /* Strange that a pixmap with alpha should be created this way, i think a qt bug */
00283     *transparence_pixmap_cache = QPixmap::fromImage( QImage(
00284       s.expandedTo(transparence_pixmap_cache->size()), QImage::Format_ARGB32 ) );
00285   }
00286 
00287   return transparence_pixmap_cache;
00288 }
00289 
00290 void KGameCanvasItem::paintInternal(QPainter* pp, const QRect& /*prect*/,
00291                     const QRegion& /*preg*/, const QPoint& /*delta*/, double cumulative_opacity) {
00292   int opacity = int(cumulative_opacity*m_opacity + 0.5);
00293 
00294   if(opacity <= 0)
00295     return;
00296 
00297   if(opacity >= 255) {
00298     paint(pp);
00299     return;
00300   }
00301 
00302   if(!layered()) {
00303     pp->setOpacity(opacity/255.0);
00304     paint(pp);
00305     pp->setOpacity(1.0);
00306     return;
00307   }
00308 
00309   QRect mr = rect();
00310   QPixmap* cache = getTransparenceCache(mr.size());
00311 
00312   {
00313     QPainter p(cache);
00314 
00315     /* clear */
00316     p.setBrush(QColor(255,255,255,0));
00317     p.setPen(Qt::NoPen);
00318     p.setCompositionMode(QPainter::CompositionMode_Source);
00319     p.drawRect(QRect(QPoint(),mr.size()));
00320 
00321     /* paint on the item */
00322     p.translate(-mr.topLeft());
00323     paint(&p);
00324     p.translate(mr.topLeft());
00325 
00326     /* make the opacity */
00327     p.setBrush( QColor(255,255,255,255-opacity) );
00328     p.setPen( Qt::NoPen );
00329     p.setCompositionMode( QPainter::CompositionMode_DestinationOut );
00330     p.drawRect( QRect(QPoint(),mr.size()) );
00331   }
00332 
00333   pp->drawPixmap(mr.topLeft(), *cache, QRect(QPoint(),mr.size()) );
00334 }
00335 
00336 void KGameCanvasItem::putInCanvas(KGameCanvasAbstract *c) {
00337   if(m_canvas == c)
00338       return;
00339 
00340   if(m_canvas) {
00341     if(m_visible)
00342       m_canvas->invalidate(m_last_rect, false); //invalidate the previously drawn rectangle
00343     m_canvas->m_items.removeAll(this);
00344     if(m_animated)
00345       m_canvas->m_animated_items.removeAll(this);
00346   }
00347 
00348   m_canvas = c;
00349 
00350   if(m_canvas) {
00351     m_canvas->m_items.append(this);
00352     if(m_animated) {
00353       m_canvas->m_animated_items.append(this);
00354       m_canvas->ensureAnimating();
00355     }
00356     if(m_visible)
00357       changed();
00358   }
00359 }
00360 
00361 void KGameCanvasItem::setVisible(bool v) {
00362   if(m_visible == v)
00363       return;
00364 
00365   m_visible = v;
00366   if(m_canvas) {
00367     if(!v)
00368       m_canvas->invalidate(m_last_rect, false);
00369     else
00370       changed();
00371   }
00372   if(!v)
00373     m_last_rect = QRect();
00374 }
00375 
00376 void KGameCanvasItem::setAnimated(bool a) {
00377   if(m_animated == a)
00378     return;
00379 
00380   m_animated = a;
00381   if(m_canvas) {
00382     if(a) {
00383       m_canvas->m_animated_items.append(this);
00384       m_canvas->ensureAnimating();
00385     }
00386     else
00387       m_canvas->m_animated_items.removeAll(this);
00388   }
00389 }
00390 
00391 void KGameCanvasItem::setOpacity(int o) {
00392   if (o<0) o=0;
00393   if (o>255) o = 255;
00394   m_opacity = o;
00395 
00396   if(m_canvas && m_visible)
00397     changed();
00398 }
00399 
00400 bool KGameCanvasItem::layered() const { return true; }
00401 
00402 void KGameCanvasItem::advance(int /*msecs*/) { }
00403 
00404 void KGameCanvasItem::updateAfterRestack(int from, int to)
00405 {
00406     int inc = from>to ? -1 : 1;
00407 
00408     QRegion upd;
00409     for(int i=from; i!=to;i+=inc)
00410     {
00411         KGameCanvasItem *el = m_canvas->m_items.at(i);
00412         if(!el->m_visible)
00413             continue;
00414 
00415         QRect r = el->rect() & rect();
00416         if(!r.isEmpty())
00417             upd |= r;
00418     }
00419 
00420     if(!upd.isEmpty())
00421         m_canvas->invalidate(upd);
00422 }
00423 
00424 void KGameCanvasItem::raise()
00425 {
00426     if(!m_canvas || m_canvas->m_items.last() == this)
00427         return;
00428 
00429     int old_pos = m_canvas->m_items.indexOf(this);
00430     m_canvas->m_items.removeAt(old_pos);
00431     m_canvas->m_items.append(this);
00432     if(m_visible)
00433         updateAfterRestack(old_pos, m_canvas->m_items.size()-1);
00434 }
00435 
00436 void KGameCanvasItem::lower()
00437 {
00438     if(!m_canvas || m_canvas->m_items.first() == this)
00439         return;
00440 
00441     int old_pos = m_canvas->m_items.indexOf(this);
00442     m_canvas->m_items.removeAt(old_pos);
00443     m_canvas->m_items.prepend(this);
00444 
00445     if(m_visible)
00446         updateAfterRestack(old_pos, 0);
00447 }
00448 
00449 void KGameCanvasItem::stackOver(KGameCanvasItem* ref)
00450 {
00451     if(!m_canvas)
00452         return;
00453 
00454     if(ref->m_canvas != m_canvas)
00455     {
00456         qCritical("KGameCanvasItem::stackOver: Argument must be a sibling item!\n");
00457         return;
00458     }
00459 
00460     int i = m_canvas->m_items.indexOf( ref );
00461     if(i < m_canvas->m_items.size()-2  &&  m_canvas->m_items[i+1] == this)
00462         return;
00463 
00464     int old_pos = m_canvas->m_items.indexOf(this);
00465     m_canvas->m_items.removeAt(old_pos);
00466     i = m_canvas->m_items.indexOf(ref);
00467     m_canvas->m_items.insert(i+1,this);
00468 
00469     if(m_visible)
00470         updateAfterRestack(old_pos, i+1);
00471 }
00472 
00473 void KGameCanvasItem::stackUnder(KGameCanvasItem* ref)
00474 {
00475     if(!m_canvas)
00476         return;
00477 
00478 
00479     if(ref->m_canvas != m_canvas)
00480     {
00481         qCritical("KGameCanvasItem::stackUnder: Argument must be a sibling item!\n");
00482         return;
00483     }
00484 
00485     int i = m_canvas->m_items.indexOf( ref );
00486     if(i >= 1  &&  m_canvas->m_items[i-1] == this)
00487         return;
00488 
00489     int old_pos = m_canvas->m_items.indexOf(this);
00490     m_canvas->m_items.removeAt(old_pos);
00491     i = m_canvas->m_items.indexOf(ref);
00492     m_canvas->m_items.insert(i,this);
00493 
00494     if(m_visible)
00495         updateAfterRestack(old_pos, i);
00496 }
00497 
00498 void KGameCanvasItem::moveTo(const QPoint &newpos)
00499 {
00500   if(m_pos == newpos)
00501     return;
00502   m_pos = newpos;
00503   if(m_visible && m_canvas)
00504     changed();
00505 }
00506 
00507 QPoint KGameCanvasItem::absolutePosition() const
00508 {
00509         if (m_canvas) {
00510                 return m_canvas->canvasPosition() + m_pos;
00511         }
00512         else {
00513                 return m_pos;
00514         }
00515 }
00516 
00517 /*
00518     KGameCanvasGroup
00519 */
00520 KGameCanvasGroup::KGameCanvasGroup(KGameCanvasAbstract* KGameCanvas)
00521 : KGameCanvasItem(KGameCanvas)
00522 , KGameCanvasAbstract()
00523 , m_child_rect_changed(true) {
00524 
00525 }
00526 
00527 KGameCanvasGroup::~KGameCanvasGroup() {
00528 
00529 }
00530 
00531 void KGameCanvasGroup::ensureAnimating() {
00532   setAnimated(true);
00533 }
00534 
00535 void KGameCanvasGroup::ensurePendingUpdate() {
00536    if(!m_changed || !m_child_rect_changed) {
00537      m_child_rect_changed = true;
00538      KGameCanvasItem::changed();
00539    }
00540 }
00541 
00542 void KGameCanvasGroup::updateChanges() {
00543   if(!m_changed)
00544     return;
00545   for(int i=0;i<m_items.size();i++) {
00546     KGameCanvasItem *el = m_items.at(i);
00547 
00548     if(el->m_changed)
00549       el->updateChanges();
00550   }
00551   m_changed = false;
00552 }
00553 
00554 void KGameCanvasGroup::changed() {
00555   if(!m_changed) {
00556     KGameCanvasItem::changed();
00557 
00558     for(int i=0;i<m_items.size();i++)
00559       m_items[i]->changed();
00560   }
00561 }
00562 
00563 void KGameCanvasGroup::invalidate(const QRect& r, bool translate) {
00564   if(m_canvas)
00565     m_canvas->invalidate(translate ? r.translated(m_pos) : r, translate);
00566   if(!m_changed)
00567     ensurePendingUpdate();
00568 }
00569 
00570 void KGameCanvasGroup::invalidate(const QRegion& r, bool translate) {
00571   if(m_canvas)
00572     m_canvas->invalidate(translate ? r.translated(m_pos) : r, translate);
00573   if(!m_changed)
00574     ensurePendingUpdate();
00575 }
00576 
00577 void KGameCanvasGroup::advance(int msecs) {
00578 
00579   // The list MUST be copied, because it could be modified calling advance.
00580   // After all since it is implicitly shared the copy will not happen unless
00581   // is it actually modified
00582   QList<KGameCanvasItem*> ait = m_animated_items;
00583   for(int i=0;i<ait.size();i++)
00584   {
00585       KGameCanvasItem *el = ait[i];
00586       el->advance(msecs);
00587   }
00588 
00589   if(m_animated_items.empty())
00590       setAnimated(false);
00591 }
00592 
00593 void KGameCanvasGroup::paintInternal(QPainter* p, const QRect& prect,
00594           const QRegion& preg, const QPoint& delta, double cumulative_opacity) {
00595   cumulative_opacity *= (m_opacity/255.0);
00596 
00597   QPoint adelta = delta;
00598   adelta += m_pos;
00599   p->translate(m_pos);
00600 
00601   for(int i=0;i<m_items.size();i++) {
00602     KGameCanvasItem *el = m_items.at(i);
00603     QRect r = el->rect().translated(adelta);
00604 
00605     if( el->m_visible && prect.intersects( r ) && preg.contains( r ) ) {
00606       el->m_last_rect = r;
00607       el->paintInternal(p,prect,preg,adelta,cumulative_opacity);
00608     }
00609   }
00610 
00611   p->translate(-m_pos);
00612 }
00613 
00614 void KGameCanvasGroup::paint(QPainter* /*p*/) {
00615   Q_ASSERT(!"This function should never be called");
00616 }
00617 
00618 QRect KGameCanvasGroup::rect() const
00619 {
00620   if(!m_child_rect_changed)
00621     return m_last_child_rect.translated(m_pos);
00622 
00623   m_child_rect_changed = false;
00624   m_last_child_rect = QRect();
00625   for(int i=0;i<m_items.size();i++)
00626   {
00627     KGameCanvasItem *el = m_items[i];
00628     if(el->m_visible)
00629       m_last_child_rect |= el->rect();
00630   }
00631 
00632   return m_last_child_rect.translated(m_pos);
00633 }
00634 
00635 KGameCanvasWidget* KGameCanvasGroup::topLevelCanvas()
00636 {
00637     return m_canvas ? m_canvas->topLevelCanvas() : NULL;
00638 }
00639 
00640 QPoint KGameCanvasGroup::canvasPosition() const {
00641         return KGameCanvasItem::absolutePosition();
00642 }
00643 
00644 /*
00645     KGameCanvasDummy
00646 */
00647 KGameCanvasDummy::KGameCanvasDummy(KGameCanvasAbstract* KGameCanvas)
00648     : KGameCanvasItem(KGameCanvas)
00649 {
00650 
00651 }
00652 
00653 KGameCanvasDummy::~KGameCanvasDummy()
00654 {
00655 
00656 }
00657 
00658 void KGameCanvasDummy::paint(QPainter* /*p*/) {
00659 }
00660 
00661 QRect KGameCanvasDummy::rect() const
00662 {
00663     return QRect();
00664 }
00665 
00666 
00667 /*
00668     KGameCanvasPixmap
00669 */
00670 KGameCanvasPixmap::KGameCanvasPixmap(const QPixmap& p, KGameCanvasAbstract* KGameCanvas)
00671     : KGameCanvasItem(KGameCanvas), m_pixmap(p) {
00672 
00673 }
00674 
00675 KGameCanvasPixmap::KGameCanvasPixmap(KGameCanvasAbstract* KGameCanvas)
00676     : KGameCanvasItem(KGameCanvas) {
00677 
00678 }
00679 
00680 KGameCanvasPixmap::~KGameCanvasPixmap() {
00681 
00682 }
00683 
00684 void KGameCanvasPixmap::setPixmap(const QPixmap& p) {
00685   m_pixmap = p;
00686   if(visible() && canvas() )
00687     changed();
00688 }
00689 
00690 void KGameCanvasPixmap::paint(QPainter* p) {
00691   p->drawPixmap(pos(), m_pixmap);
00692 }
00693 
00694 QRect KGameCanvasPixmap::rect() const {
00695     return QRect(pos(), m_pixmap.size());
00696 }
00697 
00698 
00699 /*
00700     KGameCanvasTiledPixmap
00701 */
00702 KGameCanvasTiledPixmap::KGameCanvasTiledPixmap(const QPixmap& pixmap, const QSize &size, const QPoint &origin,
00703                         bool move_orig, KGameCanvasAbstract* KGameCanvas)
00704     : KGameCanvasItem(KGameCanvas)
00705     , m_pixmap(pixmap)
00706     , m_size(size)
00707     , m_origin(origin)
00708     , m_move_orig(move_orig) {
00709 
00710 }
00711 
00712 KGameCanvasTiledPixmap::KGameCanvasTiledPixmap(KGameCanvasAbstract* KGameCanvas)
00713     : KGameCanvasItem(KGameCanvas)
00714     , m_size(0,0)
00715     , m_origin(0,0)
00716     , m_move_orig(false) {
00717 
00718 }
00719 
00720 KGameCanvasTiledPixmap::~KGameCanvasTiledPixmap() {
00721 
00722 }
00723 
00724 void KGameCanvasTiledPixmap::setPixmap(const QPixmap& pixmap) {
00725     m_pixmap = pixmap;
00726     if(visible() && canvas() )
00727       changed();
00728 }
00729 
00730 void KGameCanvasTiledPixmap::setSize(const QSize &size) {
00731   m_size = size;
00732   if(visible() && canvas() )
00733     changed();
00734 }
00735 
00736 void KGameCanvasTiledPixmap::setOrigin(const QPoint &origin)
00737 {
00738   m_origin = m_move_orig ? origin - pos() : origin;
00739 
00740   if(visible() && canvas() )
00741     changed();
00742 }
00743 
00744 
00745 void KGameCanvasTiledPixmap::setMoveOrigin(bool move_orig)
00746 {
00747   if(move_orig && !m_move_orig)
00748       m_origin -= pos();
00749   if(move_orig && !m_move_orig)
00750       m_origin += pos();
00751   m_move_orig = move_orig;
00752 }
00753 
00754 void KGameCanvasTiledPixmap::paint(QPainter* p)
00755 {
00756     if(m_move_orig)
00757         p->drawTiledPixmap( rect(), m_pixmap, m_origin);
00758     else
00759         p->drawTiledPixmap( rect(), m_pixmap, m_origin+pos() );
00760 }
00761 
00762 QRect KGameCanvasTiledPixmap::rect() const
00763 {
00764     return QRect(pos(), m_size);
00765 }
00766 
00767 
00768 /*
00769     KGameCanvasRectangle
00770 */
00771 KGameCanvasRectangle::KGameCanvasRectangle(const QColor& color, const QSize &size, KGameCanvasAbstract* KGameCanvas)
00772     : KGameCanvasItem(KGameCanvas)
00773     , m_color(color)
00774     , m_size(size)
00775 {
00776 
00777 }
00778 
00779 KGameCanvasRectangle::KGameCanvasRectangle(KGameCanvasAbstract* KGameCanvas)
00780     : KGameCanvasItem(KGameCanvas)
00781     , m_size(0,0)
00782 {
00783 
00784 }
00785 
00786 KGameCanvasRectangle::~KGameCanvasRectangle()
00787 {
00788 
00789 }
00790 
00791 void KGameCanvasRectangle::setColor(const QColor& color)
00792 {
00793   m_color = color;
00794   if(visible() && canvas() )
00795     changed();
00796 }
00797 
00798 void KGameCanvasRectangle::setSize(const QSize &size)
00799 {
00800   m_size = size;
00801   if(visible() && canvas() )
00802     changed();
00803 }
00804 
00805 void KGameCanvasRectangle::paint(QPainter* p) {
00806   p->fillRect( rect(), m_color );
00807 }
00808 
00809 QRect KGameCanvasRectangle::rect() const {
00810     return QRect(pos(), m_size);
00811 }
00812 
00813 
00814 /*
00815     KGameCanvasText
00816 */
00817 KGameCanvasText::KGameCanvasText(const QString& text, const QColor& color,
00818                         const QFont& font, HPos hp, VPos vp,
00819                         KGameCanvasAbstract* KGameCanvas)
00820     : KGameCanvasItem(KGameCanvas)
00821     , m_text(text)
00822     , m_color(color)
00823     , m_font(font)
00824     , m_hpos(hp)
00825     , m_vpos(vp) {
00826     calcBoundingRect();
00827 }
00828 
00829 KGameCanvasText::KGameCanvasText(KGameCanvasAbstract* KGameCanvas)
00830     : KGameCanvasItem(KGameCanvas)
00831     //, m_text("")
00832     , m_color(Qt::black)
00833     , m_font(QApplication::font())
00834     , m_hpos(HStart)
00835     , m_vpos(VBaseline) {
00836 
00837 }
00838 
00839 KGameCanvasText::~KGameCanvasText() {
00840 
00841 }
00842 
00843 void KGameCanvasText::calcBoundingRect() {
00844     m_bounding_rect = QFontMetrics(m_font).boundingRect(m_text);
00845     /*printf("b rect is %d %d %d %d\n",
00846         m_bounding_rect.x(),
00847         m_bounding_rect.y(),
00848         m_bounding_rect.width(),
00849         m_bounding_rect.height() );*/
00850 }
00851 
00852 void KGameCanvasText::setText(const QString& text) {
00853   if(m_text == text)
00854     return;
00855   m_text = text;
00856   calcBoundingRect();
00857 
00858   if(visible() && canvas() )
00859     changed();
00860 }
00861 
00862 void KGameCanvasText::setColor(const QColor& color) {
00863   m_color = color;
00864 }
00865 
00866 void KGameCanvasText::setFont(const QFont& font) {
00867   m_font = font;
00868   calcBoundingRect();
00869 
00870   if(visible() && canvas() )
00871     changed();
00872 }
00873 
00874 void KGameCanvasText::setPositioning(HPos hp, VPos vp) {
00875   pos() += offsetToDrawPos();
00876   m_hpos = hp;
00877   m_vpos = vp;
00878   pos() -= offsetToDrawPos();
00879 }
00880 
00881 QPoint KGameCanvasText::offsetToDrawPos() const {
00882     QPoint retv;
00883 
00884     switch(m_hpos) {
00885         case HStart:
00886             retv.setX(0);
00887             break;
00888         case HLeft:
00889             retv.setX(-m_bounding_rect.left());
00890             break;
00891         case HRight:
00892             retv.setX(-m_bounding_rect.right());
00893             break;
00894         case HCenter:
00895             retv.setX(-(m_bounding_rect.left()+m_bounding_rect.right())/2);
00896             break;
00897     }
00898 
00899     switch(m_vpos) {
00900         case VBaseline:
00901             retv.setY(0);
00902             break;
00903         case VTop:
00904             retv.setY(-m_bounding_rect.top());
00905             break;
00906         case VBottom:
00907             retv.setY(-m_bounding_rect.bottom());
00908             break;
00909         case VCenter:
00910             retv.setY(-(m_bounding_rect.top()+m_bounding_rect.bottom())/2);
00911             break;
00912     }
00913 
00914     return retv;
00915 }
00916 
00917 void KGameCanvasText::paint(QPainter* p) {
00918   p->setPen(m_color);
00919   p->setFont(m_font);
00920   p->drawText( pos() + offsetToDrawPos(), m_text);
00921 }
00922 
00923 QRect KGameCanvasText::rect() const {
00924     return m_bounding_rect.translated( pos() + offsetToDrawPos() );
00925 }
00926 
00927 
00928 /*
00929     KGameCanvasPicture
00930 */
00931 KGameCanvasPicture::KGameCanvasPicture(const QPicture& p, KGameCanvasAbstract* KGameCanvas)
00932     : KGameCanvasItem(KGameCanvas), m_picture(p)
00933 {
00934 
00935 }
00936 
00937 KGameCanvasPicture::KGameCanvasPicture(KGameCanvasAbstract* KGameCanvas)
00938     : KGameCanvasItem(KGameCanvas)
00939 {
00940 
00941 }
00942 
00943 KGameCanvasPicture::~KGameCanvasPicture()
00944 {
00945 
00946 }
00947 
00948 void KGameCanvasPicture::setPicture(const QPicture& p)
00949 {
00950   m_picture = p;
00951 
00952   if(visible() && canvas() )
00953     changed();
00954 }
00955 
00956 void KGameCanvasPicture::paint(QPainter* p)
00957 {
00958     p->drawPicture(pos(), m_picture);
00959 }
00960 
00961 QRect KGameCanvasPicture::rect() const
00962 {
00963     return m_picture.boundingRect().translated( pos());
00964 }
00965 
00966 KGameCanvasAdapter::KGameCanvasAdapter()
00967 : m_child_rect_valid(false)
00968 {
00969 }
00970 
00971 QRect KGameCanvasAdapter::childRect()
00972 {
00973     if (!m_child_rect_valid) {
00974         m_child_rect = QRect();
00975         foreach (KGameCanvasItem* el, m_items) {
00976             m_child_rect |= el->rect();
00977         }
00978         m_child_rect_valid = true;
00979     }
00980 
00981     return m_child_rect;
00982 }
00983 
00984 void KGameCanvasAdapter::render(QPainter *painter)
00985 {
00986     foreach (KGameCanvasItem* el, m_items) {
00987         if (el->m_visible) {
00988             el->m_last_rect = el->rect();
00989             el->paintInternal(painter, childRect(), childRect(), QPoint(), 1.0);
00990         }
00991     }
00992 }
00993 
00994 void KGameCanvasAdapter::ensurePendingUpdate()
00995 {
00996     m_child_rect_valid = false;
00997 
00998     foreach (KGameCanvasItem* el, m_items) {
00999         if (el->m_changed) {
01000             el->updateChanges();
01001         }
01002     }
01003 
01004     updateParent(m_invalidated_rect);
01005     m_invalidated_rect = QRect();
01006 }
01007 
01008 void KGameCanvasAdapter::invalidate(const QRegion& r, bool)
01009 {
01010     invalidate(r.boundingRect());
01011 }
01012 
01013 void KGameCanvasAdapter::invalidate(const QRect& r, bool)
01014 {
01015     m_invalidated_rect |= r;
01016 }
01017 
01018 #include "kgamecanvas.moc"

Generated on Sun Mar 16 08:02:52 2008 for Libkdegames by  doxygen 1.5.3