examples/widgets/tetrix/tetrixboard.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/widgets/tetrix/tetrixboard.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "tetrixboard.h"
+
+//! [0]
+TetrixBoard::TetrixBoard(QWidget *parent)
+    : QFrame(parent)
+{
+    setFrameStyle(QFrame::Panel | QFrame::Sunken);
+    setFocusPolicy(Qt::StrongFocus);
+    isStarted = false;
+    isPaused = false;
+    clearBoard();
+
+    nextPiece.setRandomShape();
+}
+//! [0]
+
+//! [1]
+void TetrixBoard::setNextPieceLabel(QLabel *label)
+{
+    nextPieceLabel = label;
+}
+//! [1]
+
+//! [2]
+QSize TetrixBoard::sizeHint() const
+{
+    return QSize(BoardWidth * 15 + frameWidth() * 2,
+                 BoardHeight * 15 + frameWidth() * 2);
+}
+
+QSize TetrixBoard::minimumSizeHint() const
+//! [2] //! [3]
+{
+    return QSize(BoardWidth * 5 + frameWidth() * 2,
+                 BoardHeight * 5 + frameWidth() * 2);
+}
+//! [3]
+
+//! [4]
+void TetrixBoard::start()
+{
+    if (isPaused)
+        return;
+
+    isStarted = true;
+    isWaitingAfterLine = false;
+    numLinesRemoved = 0;
+    numPiecesDropped = 0;
+    score = 0;
+    level = 1;
+    clearBoard();
+
+    emit linesRemovedChanged(numLinesRemoved);
+    emit scoreChanged(score);
+    emit levelChanged(level);
+
+    newPiece();
+    timer.start(timeoutTime(), this);
+}
+//! [4]
+
+//! [5]
+void TetrixBoard::pause()
+{
+    if (!isStarted)
+        return;
+
+    isPaused = !isPaused;
+    if (isPaused) {
+	timer.stop();
+    } else {
+	timer.start(timeoutTime(), this);
+    }
+    update();
+//! [5] //! [6]
+}
+//! [6]
+
+//! [7]
+void TetrixBoard::paintEvent(QPaintEvent *event)
+{
+    QFrame::paintEvent(event);
+
+    QPainter painter(this);
+    QRect rect = contentsRect();
+//! [7]
+
+    if (isPaused) {
+	painter.drawText(rect, Qt::AlignCenter, tr("Pause"));
+        return;
+    }
+
+//! [8]
+    int boardTop = rect.bottom() - BoardHeight*squareHeight();
+
+    for (int i = 0; i < BoardHeight; ++i) {
+        for (int j = 0; j < BoardWidth; ++j) {
+            TetrixShape shape = shapeAt(j, BoardHeight - i - 1);
+	    if (shape != NoShape)
+                drawSquare(painter, rect.left() + j * squareWidth(),
+                           boardTop + i * squareHeight(), shape);
+        }
+//! [8] //! [9]
+    }
+//! [9]
+
+//! [10]
+    if (curPiece.shape() != NoShape) {
+        for (int i = 0; i < 4; ++i) {
+            int x = curX + curPiece.x(i);
+            int y = curY - curPiece.y(i);
+            drawSquare(painter, rect.left() + x * squareWidth(),
+                       boardTop + (BoardHeight - y - 1) * squareHeight(),
+                       curPiece.shape());
+        }
+//! [10] //! [11]
+    }
+//! [11] //! [12]
+}
+//! [12]
+
+//! [13]
+void TetrixBoard::keyPressEvent(QKeyEvent *event)
+{
+    if (!isStarted || isPaused || curPiece.shape() == NoShape) {
+	QFrame::keyPressEvent(event);
+        return;
+    }
+//! [13]
+
+//! [14]
+    switch (event->key()) {
+    case Qt::Key_Left:
+        tryMove(curPiece, curX - 1, curY);
+	break;
+    case Qt::Key_Right:
+        tryMove(curPiece, curX + 1, curY);
+	break;
+    case Qt::Key_Down:
+        tryMove(curPiece.rotatedRight(), curX, curY);
+	break;
+    case Qt::Key_Up:
+        tryMove(curPiece.rotatedLeft(), curX, curY);
+	break;
+    case Qt::Key_Space:
+	dropDown();
+	break;
+    case Qt::Key_D:
+	oneLineDown();
+	break;
+    default:
+	QFrame::keyPressEvent(event);
+    }
+//! [14]
+}
+
+//! [15]
+void TetrixBoard::timerEvent(QTimerEvent *event)
+{
+    if (event->timerId() == timer.timerId()) {
+        if (isWaitingAfterLine) {
+	    isWaitingAfterLine = false;
+	    newPiece();
+	    timer.start(timeoutTime(), this);
+        } else {
+            oneLineDown();
+        }
+    } else {
+        QFrame::timerEvent(event);
+//! [15] //! [16]
+    }
+//! [16] //! [17]
+}
+//! [17]
+
+//! [18]
+void TetrixBoard::clearBoard()
+{
+    for (int i = 0; i < BoardHeight * BoardWidth; ++i)
+        board[i] = NoShape;
+}
+//! [18]
+
+//! [19]
+void TetrixBoard::dropDown()
+{
+    int dropHeight = 0;
+    int newY = curY;
+    while (newY > 0) {
+        if (!tryMove(curPiece, curX, newY - 1))
+            break;
+        --newY;
+        ++dropHeight;
+    }
+    pieceDropped(dropHeight);
+//! [19] //! [20]
+}
+//! [20]
+
+//! [21]
+void TetrixBoard::oneLineDown()
+{
+    if (!tryMove(curPiece, curX, curY - 1))
+	pieceDropped(0);
+}
+//! [21]
+
+//! [22]
+void TetrixBoard::pieceDropped(int dropHeight)
+{
+    for (int i = 0; i < 4; ++i) {
+        int x = curX + curPiece.x(i);
+        int y = curY - curPiece.y(i);
+        shapeAt(x, y) = curPiece.shape();
+    }
+
+    ++numPiecesDropped;
+    if (numPiecesDropped % 25 == 0) {
+        ++level;
+        timer.start(timeoutTime(), this);
+        emit levelChanged(level);
+    }
+
+    score += dropHeight + 7;
+    emit scoreChanged(score);
+    removeFullLines();
+
+    if (!isWaitingAfterLine)
+        newPiece();
+//! [22] //! [23]
+}
+//! [23]
+
+//! [24]
+void TetrixBoard::removeFullLines()
+{
+    int numFullLines = 0;
+
+    for (int i = BoardHeight - 1; i >= 0; --i) {
+        bool lineIsFull = true;
+
+        for (int j = 0; j < BoardWidth; ++j) {
+            if (shapeAt(j, i) == NoShape) {
+                lineIsFull = false;
+                break;
+            }
+        }
+
+        if (lineIsFull) {
+//! [24] //! [25]
+	    ++numFullLines;
+	    for (int k = i; k < BoardHeight - 1; ++k) {
+                for (int j = 0; j < BoardWidth; ++j)
+                    shapeAt(j, k) = shapeAt(j, k + 1);
+	    }
+//! [25] //! [26]
+	    for (int j = 0; j < BoardWidth; ++j)
+                shapeAt(j, BoardHeight - 1) = NoShape;
+	}
+//! [26] //! [27]
+    }
+//! [27]
+
+//! [28]
+    if (numFullLines > 0) {
+	numLinesRemoved += numFullLines;
+	score += 10 * numFullLines;
+	emit linesRemovedChanged(numLinesRemoved);
+        emit scoreChanged(score);
+
+        timer.start(500, this);
+        isWaitingAfterLine = true;
+        curPiece.setShape(NoShape);
+        update();
+    }
+//! [28] //! [29]
+}
+//! [29]
+
+//! [30]
+void TetrixBoard::newPiece()
+{
+    curPiece = nextPiece;
+    nextPiece.setRandomShape();
+    showNextPiece();
+    curX = BoardWidth / 2 + 1;
+    curY = BoardHeight - 1 + curPiece.minY();
+
+    if (!tryMove(curPiece, curX, curY)) {
+	curPiece.setShape(NoShape);
+        timer.stop();
+        isStarted = false;
+    }
+//! [30] //! [31]
+}
+//! [31]
+
+//! [32]
+void TetrixBoard::showNextPiece()
+{
+    if (!nextPieceLabel)
+        return;
+
+    int dx = nextPiece.maxX() - nextPiece.minX() + 1;
+    int dy = nextPiece.maxY() - nextPiece.minY() + 1;
+
+    QPixmap pixmap(dx * squareWidth(), dy * squareHeight());
+    QPainter painter(&pixmap);
+    painter.fillRect(pixmap.rect(), nextPieceLabel->palette().background());
+
+    for (int i = 0; i < 4; ++i) {
+        int x = nextPiece.x(i) - nextPiece.minX();
+        int y = nextPiece.y(i) - nextPiece.minY();
+        drawSquare(painter, x * squareWidth(), y * squareHeight(),
+                   nextPiece.shape());
+    }
+    nextPieceLabel->setPixmap(pixmap);
+//! [32] //! [33]
+}
+//! [33]
+
+//! [34]
+bool TetrixBoard::tryMove(const TetrixPiece &newPiece, int newX, int newY)
+{
+    for (int i = 0; i < 4; ++i) {
+        int x = newX + newPiece.x(i);
+        int y = newY - newPiece.y(i);
+        if (x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight)
+            return false;
+        if (shapeAt(x, y) != NoShape)
+            return false;
+    }
+//! [34]
+
+//! [35]
+    curPiece = newPiece;
+    curX = newX;
+    curY = newY;
+    update();
+    return true;
+}
+//! [35]
+
+//! [36]
+void TetrixBoard::drawSquare(QPainter &painter, int x, int y, TetrixShape shape)
+{
+    static const QRgb colorTable[8] = {
+        0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
+        0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00
+    };
+
+    QColor color = colorTable[int(shape)];
+    painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2,
+                     color);
+
+    painter.setPen(color.light());
+    painter.drawLine(x, y + squareHeight() - 1, x, y);
+    painter.drawLine(x, y, x + squareWidth() - 1, y);
+
+    painter.setPen(color.dark());
+    painter.drawLine(x + 1, y + squareHeight() - 1,
+                     x + squareWidth() - 1, y + squareHeight() - 1);
+    painter.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,
+                     x + squareWidth() - 1, y + 1);
+}
+//! [36]