doc/src/examples/tetrix.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/src/examples/tetrix.qdoc	Thu Apr 08 14:19:33 2010 +0300
@@ -0,0 +1,445 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation 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$
+**
+****************************************************************************/
+
+/*! 
+    \example widgets/tetrix
+    \title Tetrix Example
+
+    The Tetrix example is a Qt version of the classic Tetrix game.
+
+    \image tetrix-example.png
+
+    The object of the game is to stack pieces dropped from the top of the
+    playing area so that they fill entire rows at the bottom of the playing area.
+
+    When a row is filled, all the blocks on that row are removed, the player earns
+    a number of points, and the pieces above are moved down to occupy that row.
+    If more than one row is filled, the blocks on each row are removed, and the
+    player earns extra points.
+
+    The \gui{Left} cursor key moves the current piece one space to the left, the
+    \gui{Right} cursor key moves it one space to the right, the \gui{Up} cursor
+    key rotates the piece counter-clockwise by 90 degrees, and the \gui{Down}
+    cursor key rotates the piece clockwise by 90 degrees.
+
+    To avoid waiting for a piece to fall to the bottom of the board, press \gui{D}
+    to immediately move the piece down by one row, or press the \gui{Space} key to
+    drop it as close to the bottom of the board as possible.
+
+    This example shows how a simple game can be created using only three classes:
+
+    \list
+    \o The \c TetrixWindow class is used to display the player's score, number of
+       lives, and information about the next piece to appear.
+    \o The \c TetrixBoard class contains the game logic, handles keyboard input, and
+       displays the pieces on the playing area.
+    \o The \c TetrixPiece class contains information about each piece.
+    \endlist
+
+    In this approach, the \c TetrixBoard class is the most complex class, since it
+    handles the game logic and rendering. One benefit of this is that the
+    \c TetrixWindow and \c TetrixPiece classes are very simple and contain only a
+    minimum of code.
+
+    \section1 TetrixWindow Class Definition
+
+    The \c TetrixWindow class is used to display the game information and contains
+    the playing area:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.h 0
+
+    We use private member variables for the board, various display widgets, and
+    buttons to allow the user to start a new game, pause the current game, and quit.
+
+    Although the window inherits QWidget, the constructor does not provide an
+    argument to allow a parent widget to be specified. This is because the window
+    will always be used as a top-level widget.
+
+    \section1 TetrixWindow Class Implementation
+
+    The constructor sets up the user interface elements for the game:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 0
+
+    We begin by constructing a \c TetrixBoard instance for the playing area and a
+    label that shows the next piece to be dropped into the playing area; the label
+    is initially empty.
+
+    Three QLCDNumber objects are used to display the score, number of lives, and
+    lines removed. These initially show default values, and will be filled in
+    when a game begins:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 1
+
+    Three buttons with shortcuts are constructed so that the user can start a
+    new game, pause the current game, and quit the application:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 2
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 3
+
+    These buttons are configured so that they never receive the keyboard focus;
+    we want the keyboard focus to remain with the \c TetrixBoard instance so that
+    it receives all the keyboard events. Nonetheless, the buttons will still respond
+    to \key{Alt} key shortcuts.
+
+    We connect \l{QAbstractButton::}{clicked()} signals from the \gui{Start}
+    and \gui{Pause} buttons to the board, and from the \gui{Quit} button to the
+    application's \l{QApplication::}{quit()} slot.
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 4
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 5
+
+    Signals from the board are also connected to the LCD widgets for the purpose of
+    updating the score, number of lives, and lines removed from the playing area.
+
+    We place the label, LCD widgets, and the board into a QGridLayout
+    along with some labels that we create with the \c createLabel() convenience
+    function:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 6
+
+    Finally, we set the grid layout on the widget, give the window a title, and
+    resize it to an appropriate size.
+
+    The \c createLabel() convenience function simply creates a new label on the
+    heap, gives it an appropriate alignment, and returns it to the caller:
+
+    \snippet examples/widgets/tetrix/tetrixwindow.cpp 7
+
+    Since each label will be used in the widget's layout, it will become a child
+    of the \c TetrixWindow widget and, as a result, it will be deleted when the
+    window is deleted.
+
+    \section1 TetrixPiece Class Definition
+
+    The \c TetrixPiece class holds information about a piece in the game's
+    playing area, including its shape, position, and the range of positions it can
+    occupy on the board:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.h 0
+
+    Each shape contains four blocks, and these are defined by the \c coords private
+    member variable. Additionally, each piece has a high-level description that is
+    stored internally in the \c pieceShape variable.
+
+    The constructor is written inline in the definition, and simply ensures that
+    each piece is initially created with no shape. The \c shape() function simply
+    returns the contents of the \c pieceShape variable, and the \c x() and \c y()
+    functions return the x and y-coordinates of any given block in the shape.
+
+    \section1 TetrixPiece Class Implementation
+
+    The \c setRandomShape() function is used to select a random shape for a piece:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 0
+
+    For convenience, it simply chooses a random shape from the \c TetrixShape enum
+    and calls the \c setShape() function to perform the task of positioning the
+    blocks.
+
+    The \c setShape() function uses a look-up table of pieces to associate each
+    shape with an array of block positions:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 1
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 2
+
+    These positions are read from the table into the piece's own array of positions,
+    and the piece's internal shape information is updated to use the new shape.
+
+    The \c x() and \c y() functions are implemented inline in the class definition,
+    returning positions defined on a grid that extends horizontally and vertically
+    with coordinates from -2 to 2. Although the predefined coordinates for each
+    piece only vary horizontally from -1 to 1 and vertically from -1 to 2, each
+    piece can be rotated by 90, 180, and 270 degrees.
+
+    The \c minX() and \c maxX() functions return the minimum and maximum horizontal
+    coordinates occupied by the blocks that make up the piece:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 3
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 4
+
+    Similarly, the \c minY() and \c maxY() functions return the minimum and maximum
+    vertical coordinates occupied by the blocks:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 5
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 6
+
+    The \c rotatedLeft() function returns a new piece with the same shape as an
+    existing piece, but rotated counter-clockwise by 90 degrees:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 7
+
+    Similarly, the \c rotatedRight() function returns a new piece with the same
+    shape as an existing piece, but rotated clockwise by 90 degrees:
+
+    \snippet examples/widgets/tetrix/tetrixpiece.cpp 9
+
+    These last two functions enable each piece to create rotated copies of itself.
+
+    \section1 TetrixBoard Class Definition
+
+    The \c TetrixBoard class inherits from QFrame and contains the game logic and display features:
+
+    \snippet examples/widgets/tetrix/tetrixboard.h 0
+
+    Apart from the \c setNextPieceLabel() function and the \c start() and \c pause()
+    public slots, we only provide public functions to reimplement QWidget::sizeHint()
+    and QWidget::minimumSizeHint(). The signals are used to communicate changes to
+    the player's information to the \c TetrixWindow instance.
+
+    The rest of the functionality is provided by reimplementations of protected event
+    handlers and private functions:
+
+    \snippet examples/widgets/tetrix/tetrixboard.h 1
+
+    The board is composed of a fixed-size array whose elements correspond to
+    spaces for individual blocks. Each element in the array contains a \c TetrixShape
+    value corresponding to the type of shape that occupies that element.
+
+    Each shape on the board will occupy four elements in the array, and these will
+    all contain the enum value that corresponds to the type of the shape.
+
+    We use a QBasicTimer to control the rate at which pieces fall toward the bottom
+    of the playing area. This allows us to provide an implementation of
+    \l{QObject::}{timerEvent()} that we can use to update the widget.
+
+    \section1 TetrixBoard Class Implementation
+
+    In the constructor, we customize the frame style of the widget, ensure that
+    keyboard input will be received by the widget by using Qt::StrongFocus for the
+    focus policy, and initialize the game state:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 0
+
+    The first (next) piece is also set up with a random shape.
+
+    The \c setNextPieceLabel() function is used to pass in an externally-constructed
+    label to the board, so that it can be shown alongside the playing area:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 1
+
+    We provide a reasonable size hint and minimum size hint for the board, based on
+    the size of the space for each block in the playing area:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 2
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 3
+
+    By using a minimum size hint, we indicate to the layout in the parent widget
+    that the board should not shrink below a minimum size.
+
+    A new game is started when the \c start() slot is called. This resets the
+    game's state, the player's score and level, and the contents of the board:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 4
+
+    We also emit signals to inform other components of these changes before creating
+    a new piece that is ready to be dropped into the playing area. We start the
+    timer that determines how often the piece drops down one row on the board.
+
+    The \c pause() slot is used to temporarily stop the current game by stopping the
+    internal timer:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 5
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 6
+
+    We perform checks to ensure that the game can only be paused if it is already
+    running and not already paused.
+
+    The \c paintEvent() function is straightforward to implement. We begin by
+    calling the base class's implementation of \l{QWidget::}{paintEvent()} before
+    constructing a QPainter for use on the board:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 7
+
+    Since the board is a subclass of QFrame, we obtain a QRect that covers the area
+    \e inside the frame decoration before drawing our own content.
+
+    If the game is paused, we want to hide the existing state of the board and
+    show some text. We achieve this by painting text onto the widget and returning
+    early from the function. The rest of the painting is performed after this point.
+
+    The position of the top of the board is found by subtracting the total height
+    of each space on the board from the bottom of the frame's internal rectangle.
+    For each space on the board that is occupied by a piece, we call the
+    \c drawSquare() function to draw a block at that position.
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 8
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 9
+
+    Spaces that are not occupied by blocks are left blank.
+
+    Unlike the existing pieces on the board, the current piece is drawn
+    block-by-block at its current position:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 10
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 11
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 12
+
+    The \c keyPressEvent() handler is called whenever the player presses a key while
+    the \c TetrixBoard widget has the keyboard focus.
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 13
+
+    If there is no current game, the game is running but paused, or if there is no
+    current shape to control, we simply pass on the event to the base class.
+
+    We check whether the event is about any of the keys that the player uses to
+    control the current piece and, if so, we call the relevant function to handle
+    the input:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 14
+
+    In the case where the player presses a key that we are not interested in, we
+    again pass on the event to the base class's implementation of
+    \l{QWidget::}{keyPressEvent()}.
+
+    The \c timerEvent() handler is called every time the class's QBasicTimer
+    instance times out. We need to check that the event we receive corresponds to
+    our timer. If it does, we can update the board:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 15
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 16
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 17
+
+    If a row (or line) has just been filled, we create a new piece and reset the
+    timer; otherwise we move the current piece down by one row. We let the base
+    class handle other timer events that we receive.
+
+    The \c clearBoard() function simply fills the board with the
+    \c TetrixShape::NoShape value:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 18
+
+    The \c dropDown() function moves the current piece down as far as possible on
+    the board, either until it is touching the bottom of the playing area or it is
+    stacked on top of another piece:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 19
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 20
+
+    The number of rows the piece has dropped is recorded and passed to the
+    \c pieceDropped() function so that the player's score can be updated.
+
+    The \c oneLineDown() function is used to move the current piece down by one row
+    (line), either when the user presses the \gui{D} key or when the piece is
+    scheduled to move:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 21
+
+    If the piece cannot drop down by one line, we call the \c pieceDropped() function
+    with zero as the argument to indicate that it cannot fall any further, and that
+    the player should receive no extra points for the fall.
+
+    The \c pieceDropped() function itself is responsible for awarding points to the
+    player for positioning the current piece, checking for full rows on the board
+    and, if no lines have been removed, creating a new piece to replace the current
+    one:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 22
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 23
+
+    We call \c removeFullLines() each time a piece has been dropped. This scans
+    the board from bottom to top, looking for blank spaces on each row.
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 24
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 25
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 26
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 27
+
+    If a row contains no blank spaces, the rows above it are copied down by one row
+    to compress the stack of pieces, the top row on the board is cleared, and the
+    number of full lines found is incremented.
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 28
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 29
+
+    If some lines have been removed, the player's score and the total number of lines
+    removed are updated. The \c linesRemoved() and \c scoreChanged() signals are
+    emitted to send these new values to other widgets in the window.
+
+    Additionally, we set the timer to elapse after half a second, set the
+    \c isWaitingAfterLine flag to indicate that lines have been removed, unset
+    the piece's shape to ensure that it is not drawn, and update the widget.
+    The next time that the \c timerEvent() handler is called, a new piece will be
+    created and the game will continue.
+
+    The \c newPiece() function places the next available piece at the top of the
+    board, and creates a new piece with a random shape:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 30
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 31
+
+    We place a new piece in the middle of the board at the top. The game is over if
+    the piece can't move, so we unset its shape to prevent it from being drawn, stop
+    the timer, and unset the \c isStarted flag.
+
+    The \c showNextPiece() function updates the label that shows the next piece to
+    be dropped:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 32
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 33
+
+    We draw the piece's component blocks onto a pixmap that is then set on the label.
+
+    The \c tryMove() function is used to determine whether a piece can be positioned
+    at the specified coordinates:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 34
+
+    We examine the spaces on the board that the piece needs to occupy and, if they
+    are already occupied by other pieces, we return \c false to indicate that the
+    move has failed.
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 35
+
+    If the piece could be placed on the board at the desired location, we update the
+    current piece and its position, update the widget, and return \c true to indicate
+    success.
+
+    The \c drawSquare() function draws the blocks (normally squares) that make up
+    each piece using different colors for pieces with different shapes:
+
+    \snippet examples/widgets/tetrix/tetrixboard.cpp 36
+
+    We obtain the color to use from a look-up table that relates each shape to an
+    RGB value, and use the painter provided to draw the block at the specified
+    coordinates.
+*/