File indexing completed on 2023-09-24 08:17:46
0001 /* 0002 This file is part of the KDE games lskat program 0003 SPDX-FileCopyrightText: 2006 Martin Heni <kde@heni-online.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "gameview.h" 0009 0010 // General includes 0011 #include <cmath> 0012 0013 // Qt includes 0014 #include <QTimer> 0015 0016 // KF includes 0017 0018 // Local includes 0019 #include "lskat_debug.h" 0020 #include "lskatglobal.h" 0021 #include "thememanager.h" 0022 0023 // Constructor for the view 0024 GameView::GameView(const QSize &size, int advancePeriod, QGraphicsScene *scene, ThemeManager *theme, QWidget *parent) 0025 : QGraphicsView(scene, parent) 0026 { 0027 // Store attributes 0028 mTheme = theme; 0029 0030 // We do not need scrolling so switch it off 0031 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0032 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0033 0034 // Frame off 0035 setFrameStyle(QFrame::NoFrame); 0036 0037 // Cache on 0038 setCacheMode(QGraphicsView::CacheBackground); 0039 setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); 0040 setOptimizationFlags( 0041 QGraphicsView::DontSavePainterState | 0042 QGraphicsView::DontAdjustForAntialiasing); 0043 0044 // Debug 0045 mDisplayUpdateTime = 0; 0046 mFrameSprite = new QGraphicsTextItem(nullptr); 0047 scene->addItem(mFrameSprite); 0048 mFrameSprite->setPos(QPointF(0.0, 0.0)); 0049 mFrameSprite->setZValue(1000.0); 0050 if (global_debug > 0) mFrameSprite->show(); 0051 else mFrameSprite->hide(); 0052 0053 // Update/advance in [ms] 0054 QTimer *timer = new QTimer(this); 0055 connect(timer, &QTimer::timeout, this, &GameView::updateAndAdvance); 0056 timer->start(advancePeriod); 0057 0058 // Set size and position of the view and the canvas: 0059 // they are resized once a level is loaded 0060 resize(size); 0061 scene->setSceneRect(0, 0, this->width(), this->height()); 0062 adjustSize(); 0063 0064 // Enable mouse 0065 setInteractive(true); 0066 0067 // Scale theme 0068 //mTheme->rescale(this->width()); 0069 mThemeQueue.clear(); 0070 mThemeOffset.clear(); 0071 mTimeStart.start(); 0072 } 0073 0074 GameView::~GameView() 0075 { 0076 delete mFrameSprite; 0077 } 0078 0079 // Advance and update canvas 0080 void GameView::updateAndAdvance() 0081 { 0082 static int elapsed = -1; 0083 static QElapsedTimer timer; 0084 if (elapsed < 0) 0085 { 0086 timer.start(); 0087 elapsed = 0; 0088 } 0089 else 0090 { 0091 elapsed = timer.elapsed(); 0092 timer.start(); 0093 mDisplayUpdateTime = elapsed; 0094 } 0095 0096 scene()->advance(); 0097 //NOTE regarding QGV porting 0098 //QGV will handle dirty rects for us 0099 //Calling update will just dirty the view and cause a full redraw, killing performance 0100 //scene()->update(); 0101 } 0102 0103 // Slot called by the framework when the window is resized. 0104 void GameView::resizeEvent(QResizeEvent *e) 0105 { 0106 QElapsedTimer t; 0107 t.start(); 0108 if (global_debug > 2) qCDebug(LSKAT_LOG) << "RESIZE EVENT " << e->size() << " oldSize="<< e->oldSize() << " at " << t.msecsTo(mTimeStart); 0109 double diffW = double(e->oldSize().width() - e->size().width()); 0110 double diffH = double(e->oldSize().height() - e->size().height()); 0111 double delta = fabs(diffW) + fabs(diffH); 0112 0113 // Adapt the canvas size to the window size 0114 if (scene()) 0115 { 0116 scene()->setSceneRect(0, 0, e->size().width(), e->size().height()); 0117 } 0118 0119 QSizeF size = QSizeF(e->size()); 0120 // Rescale on minimum fitting aspect ratio either width or height limiting 0121 double aspect = size.width() / size.height(); 0122 QPoint offset; 0123 double width = 0.0; 0124 0125 // Scale width: 0126 // Ideal size would be: 'width'*'height' 0127 // Offset in width is (e->size().width() - width) / 2, offset in height is zero 0128 if (aspect > mTheme->aspectRatio()) 0129 { 0130 width = e->size().height() * mTheme->aspectRatio(); 0131 offset = QPoint(int((e->size().width() - width) / 2.0), 0); 0132 } 0133 // Scale height: 0134 // 'height' = width / mTheme->aspectRatio() 0135 // Ideal size would be: 'width'*'height': 0136 // Offset in height is (e->size().height() - width / mTheme->aspectRatio()) / 2, offset in width is zero 0137 else 0138 { 0139 width = e->size().width(); 0140 offset = QPoint(0, int((e->size().height() - width / mTheme->aspectRatio()) / 2.0)); 0141 } 0142 0143 // Pixel rescale 0144 double oldScale = mTheme->getScale(); 0145 resetTransform(); 0146 if (width > oldScale) 0147 { 0148 scale(double(width / oldScale), double(width / oldScale)); 0149 } 0150 mThemeQueue.prepend(int(width)); 0151 mThemeOffset.prepend(offset); 0152 if (global_debug > 2) qCDebug(LSKAT_LOG) << "Queued resize, aspect=" << aspect << " theme aspect=" << mTheme->aspectRatio(); 0153 0154 long queueDelay = 0; 0155 if (delta < 15) queueDelay = 750; 0156 else if (delta < 35) queueDelay = 500; 0157 0158 QTimer::singleShot(queueDelay, this, &GameView::rescaleTheme); 0159 } 0160 0161 // Rescale the theme (update theme SVG graphics) from the theme list 0162 void GameView::rescaleTheme() 0163 { 0164 if (mThemeQueue.size() == 0) 0165 { 0166 if (global_debug > 2) qCDebug(LSKAT_LOG) << "***************** Swallowing rescale event ***********************"; 0167 return; 0168 } 0169 0170 QElapsedTimer t; 0171 t.start(); 0172 0173 if (global_debug > 2) qCDebug(LSKAT_LOG) << "Theme queue rescale start at " << t.msecsTo(mTimeStart); 0174 resetTransform(); 0175 int width = mThemeQueue.first(); 0176 mInputOffset = mThemeOffset.first(); 0177 if (global_debug > 2) qCDebug(LSKAT_LOG) << "Theme queue size=" << mThemeQueue.size() << " Rescale width to " << width; 0178 0179 mThemeQueue.clear(); 0180 mThemeOffset.clear(); 0181 mTheme->rescale(width, mInputOffset); 0182 0183 if (global_debug > 2) qCDebug(LSKAT_LOG) << "Time elapsed: " << t.elapsed() << "ms"; 0184 } 0185 0186 // Our subclassed (temporary) QGraphicsView paintEvent, see header file 0187 void GameView::paintEvent(QPaintEvent *event) 0188 { 0189 QPaintEvent *newEvent = new QPaintEvent(event->region().boundingRect()); 0190 QGraphicsView::paintEvent(newEvent); 0191 delete newEvent; 0192 } 0193 0194 // Mouse click event 0195 void GameView::mouseReleaseEvent(QMouseEvent *ev) 0196 { 0197 if (ev->button() != Qt::LeftButton) return; 0198 0199 QPointF point = ev->pos()-mInputOffset; 0200 Q_EMIT signalLeftMousePress(point.toPoint()); 0201 } 0202 0203 void GameView::drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[]) 0204 { 0205 QElapsedTimer time; 0206 time.start(); 0207 QGraphicsView::drawItems(painter, numItems, items, options); 0208 0209 // Time display 0210 int elapsed = time.elapsed(); 0211 mDrawTimes.append(elapsed); 0212 if (mDrawTimes.size() > 50) mDrawTimes.removeFirst(); 0213 double avg = 0.0; 0214 for (int i = 0; i < mDrawTimes.size(); i++) avg += mDrawTimes[i]; 0215 avg /= mDrawTimes.size(); 0216 0217 if (global_debug > 0) 0218 mFrameSprite->setPlainText(QStringLiteral("Draw: %1 ms Average %2 ms Update: %3 ms").arg(elapsed).arg(int(avg)).arg(mDisplayUpdateTime)); 0219 } 0220 0221 #include "moc_gameview.cpp"