Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example painting/transformations
++ \title Transformations Example
++ \examplecategory {Graphics}
++ \ingroup examples-painting
++ \brief The Transformations example shows how transformations
++ influence the way that QPainter renders graphics primitives.
++
++ \brief The Transformations example shows how transformations influence
++ the way that QPainter renders graphics primitives. In particular
++ it shows how the order of transformations affect the result.
++
++ \image transformations-example.png
++ {Application displaying different customizable text transformations}
++
++ The application allows the user to manipulate the rendering of a
++ shape by changing the translation, rotation and scale of
++ QPainter's coordinate system.
++
++ The example consists of two classes and a global enum:
++
++ \list
++ \li The \c RenderArea class controls the rendering of a given shape.
++ \li The \c Window class is the application's main window.
++ \li The \c Operation enum describes the various transformation
++ operations available in the application.
++ \endlist
++
++ First we will take a quick look at the \c Operation enum, then we
++ will review the \c RenderArea class to see how a shape is
++ rendered. Finally, we will take a look at the Transformations
++ application's features implemented in the \c Window class.
++
++ \section1 Transformation Operations
++
++ Normally, the QPainter operates on the associated device's own
++ coordinate system, but it also has good support for coordinate
++ transformations.
++
++ The default coordinate system of a paint device has its origin at
++ the top-left corner. The x values increase to the right and the y
++ values increase downwards. You can scale the coordinate system by
++ a given offset using the QPainter::scale() function, you can
++ rotate it clockwise using the QPainter::rotate() function and you
++ can translate it (i.e. adding a given offset to the points) using
++ the QPainter::translate() function. You can also twist the
++ coordinate system around the origin (called shearing) using the
++ QPainter::shear() function.
++
++ All the transformation operations operate on QPainter's
++ transformation matrix that you can retrieve using the
++ QPainter::worldTransform() function. A matrix transforms a point in the
++ plane to another point. For more information about the
++ transformation matrix, see the \l {Coordinate System} and
++ QTransform documentation.
++
++ \snippet painting/transformations/renderarea.h 0
++
++ The global \c Operation enum is declared in the \c renderarea.h
++ file and describes the various transformation operations available
++ in the Transformations application.
++
++ \section1 RenderArea Class Definition
++
++ The \c RenderArea class inherits QWidget, and controls the
++ rendering of a given shape.
++
++ \snippet painting/transformations/renderarea.h 1
++
++ We declare two public functions, \c setOperations() and
++ \c setShape(), to be able to specify the \c RenderArea widget's shape
++ and to transform the coordinate system the shape is rendered
++ within.
++
++ We reimplement the QWidget's \l
++ {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
++ {QWidget::sizeHint()}{sizeHint()} functions to give the \c
++ RenderArea widget a reasonable size within our application, and we
++ reimplement the QWidget::paintEvent() event handler to draw the
++ render area's shape applying the user's transformation choices.
++
++ \snippet painting/transformations/renderarea.h 2
++
++ We also declare several convenience functions to draw the shape,
++ the coordinate system's outline and the coordinates, and to
++ transform the painter according to the chosen transformations.
++
++ In addition, the \c RenderArea widget keeps a list of the
++ currently applied transformation operations, a reference to its
++ shape, and a couple of convenience variables that we will use when
++ rendering the coordinates.
++
++ \section1 RenderArea Class Implementation
++
++ The \c RenderArea widget controls the rendering of a given shape,
++ including the transformations of the coordinate system, by
++ reimplementing the QWidget::paintEvent() event handler. But first
++ we will take a quick look at the constructor and at the functions
++ that provides access to the \c RenderArea widget:
++
++ \snippet painting/transformations/renderarea.cpp 0
++
++ In the constructor we pass the parent parameter on to the base
++ class, and customize the font that we will use to render the
++ coordinates. The QWidget::font() function returns the font
++ currently set for the widget. As long as no special font has been
++ set, or after QWidget::setFont() is called, this is either a
++ special font for the widget class, the parent's font or (if this
++ widget is a top level widget) the default application font.
++
++ After ensuring that the font's size is 12 points, we extract the
++ rectangles enclosing the coordinate letters, 'x' and 'y', using the
++ QFontMetrics class.
++
++ QFontMetrics provides functions to access the individual metrics
++ of the font, its characters, and for strings rendered in the
++ font. The QFontMetrics::boundingRect() function returns the
++ bounding rectangle of the given character relative to the
++ left-most point on the base line.
++
++ \snippet painting/transformations/renderarea.cpp 1
++ \codeline
++ \snippet painting/transformations/renderarea.cpp 2
++
++ In the \c setShape() and \c setOperations() functions we update
++ the \c RenderArea widget by storing the new value or values
++ followed by a call to the QWidget::update() slot which schedules a
++ paint event for processing when Qt returns to the main event loop.
++
++ \snippet painting/transformations/renderarea.cpp 3
++ \codeline
++ \snippet painting/transformations/renderarea.cpp 4
++
++ We reimplement the QWidget's \l
++ {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
++ {QWidget::sizeHint()}{sizeHint()} functions to give the \c
++ RenderArea widget a reasonable size within our application. The
++ default implementations of these functions returns an invalid size
++ if there is no layout for this widget, and returns the layout's
++ minimum size or preferred size, respectively, otherwise.
++
++ \snippet painting/transformations/renderarea.cpp 5
++
++ The \c paintEvent() event handler receives the \c RenderArea
++ widget's paint events. A paint event is a request to repaint all
++ or part of the widget. It can happen as a result of
++ QWidget::repaint() or QWidget::update(), or because the widget was
++ obscured and has now been uncovered, or for many other reasons.
++
++ First we create a QPainter for the \c RenderArea widget. The \l
++ {QPainter::RenderHint}{QPainter::Antialiasing} render hint
++ indicates that the engine should antialias edges of primitives if
++ possible. Then we erase the area that needs to be repainted using
++ the QPainter::fillRect() function.
++
++ We also translate the coordinate system with an constant offset to
++ ensure that the original shape is renderend with a suitable
++ margin.
++
++ \snippet painting/transformations/renderarea.cpp 6
++
++ Before we start to render the shape, we instantiate
++ a QPainterStateGuard to save the current painter state (i.e. push the
++ state onto a stack) including the current coordinate system while
++ in scope. The rationale for saving the painter state is that the
++ following call to the \c transformPainter() function will transform the
++ coordinate system depending on the currently chosen transformation
++ operations, and we need a way to get back to the original state to
++ draw the outline.
++
++ After transforming the coordinate system, we draw the \c
++ RenderArea's shape, and then we restore the painter state using
++ the QPainter::restore() function (i.e. popping the saved state off
++ the stack).
++
++ \snippet painting/transformations/renderarea.cpp 7
++
++ Then we draw the square outline.
++
++ \snippet painting/transformations/renderarea.cpp 8
++
++ Since we want the coordinates to correspond with the coordinate
++ system the shape is rendered within, we must make another call to
++ the \c transformPainter() function.
++
++ The order of the painting operations is essential with respect to
++ the shared pixels. The reason why we don't render the coordinates
++ when the coordinate system already is transformed to render the
++ shape, but instead defer their rendering to the end, is that we
++ want the coordinates to appear on top of the shape and its
++ outline.
++
++ There is no need to save the QPainter state this time since
++ drawing the coordinates is the last painting operation.
++
++ \snippet painting/transformations/renderarea.cpp 9
++ \codeline
++ \snippet painting/transformations/renderarea.cpp 10
++ \codeline
++ \snippet painting/transformations/renderarea.cpp 11
++
++ The \c drawCoordinates(), \c drawOutline() and \c drawShape() are
++ convenience functions called from the \c paintEvent() event
++ handler. For more information about QPainter's basic drawing
++ operations and how to display basic graphics primitives, see the
++ \l {painting/basicdrawing}{Basic Drawing} example.
++
++ \snippet painting/transformations/renderarea.cpp 12
++
++ The \c transformPainter() convenience function is also called from
++ the \c paintEvent() event handler, and transforms the given
++ QPainter's coordinate system according to the user's
++ transformation choices.
++
++ \section1 Window Class Definition
++
++ The \c Window class is the Transformations application's main
++ window.
++
++ The application displays four \c RenderArea widgets. The left-most
++ widget renders the shape in QPainter's default coordinate system,
++ the others render the shape with the chosen transformation in
++ addition to all the transformations applied to the \c RenderArea
++ widgets to their left.
++
++ \snippet painting/transformations/window.h 0
++
++ We declare two public slots to make the application able to
++ respond to user interaction, updating the displayed \c RenderArea
++ widgets according to the user's transformation choices.
++
++ The \c operationChanged() slot updates each of the \c RenderArea
++ widgets applying the currently chosen transformation operations, and
++ is called whenever the user changes the selected operations. The
++ \c shapeSelected() slot updates the \c RenderArea widgets' shapes
++ whenever the user changes the preferred shape.
++
++ \snippet painting/transformations/window.h 1
++
++ We also declare a private convenience function, \c setupShapes(),
++ that is used when constructing the \c Window widget, and we
++ declare pointers to the various components of the widget. We
++ choose to keep the available shapes in a QList of \l
++ {QPainterPath}s. In addition we declare a private enum counting
++ the number of displayed \c RenderArea widgets except the widget
++ that renders the shape in QPainter's default coordinate system.
++
++ \section1 Window Class Implementation
++
++ In the constructor we create and initialize the application's
++ components:
++
++ \snippet painting/transformations/window.cpp 0
++
++ First we create the \c RenderArea widget that will render the
++ shape in the default coordinate system. We also create the
++ associated QComboBox that allows the user to choose among four
++ different shapes: A clock, a house, a text and a truck. The shapes
++ themselves are created at the end of the constructor, using the
++ \c setupShapes() convenience function.
++
++ \snippet painting/transformations/window.cpp 1
++
++ Then we create the \c RenderArea widgets that will render their
++ shapes with coordinate transformations. By default the applied
++ operation is \uicontrol {No Transformation}, i.e. the shapes are
++ rendered within the default coordinate system. We create and
++ initialize the associated \l {QComboBox}es with items
++ corresponding to the various transformation operations described by
++ the global \c Operation enum.
++
++ We also connect the \l {QComboBox}es' \l
++ {QComboBox::activated()}{activated()} signal to the \c
++ operationChanged() slot to update the application whenever the
++ user changes the selected transformation operations.
++
++ \snippet painting/transformations/window.cpp 2
++
++ Finally, we set the layout for the application window using the
++ QWidget::setLayout() function, construct the available shapes
++ using the private \c setupShapes() convenience function, and make
++ the application show the clock shape on startup using the public
++ \c shapeSelected() slot before we set the window title.
++
++
++ \snippet painting/transformations/window.cpp 3
++ \snippet painting/transformations/window.cpp 4
++ \snippet painting/transformations/window.cpp 5
++ \snippet painting/transformations/window.cpp 6
++ \dots
++
++ \snippet painting/transformations/window.cpp 7
++
++ The \c setupShapes() function is called from the constructor and
++ create the QPainterPath objects representing the shapes that are
++ used in the application. For construction details, see the \c
++ {painting/transformations/window.cpp} example
++ file. The shapes are stored in a QList. The QList::append()
++ function inserts the given shape at the end of the list.
++
++ We also connect the associated QComboBox's \l
++ {QComboBox::activated()}{activated()} signal to the \c
++ shapeSelected() slot to update the application when the user
++ changes the preferred shape.
++
++ \snippet painting/transformations/window.cpp 8
++
++ The public \c operationChanged() slot is called whenever the user
++ changes the selected operations.
++
++ We retrieve the chosen transformation operation for each of the
++ transformed \c RenderArea widgets by querying the associated \l
++ {QComboBox}{QComboBoxes}. The transformed \c RenderArea widgets
++ are supposed to render the shape with the transformation specified
++ by its associated combobox \e {in addition to} all the
++ transformations applied to the \c RenderArea widgets to its
++ left. For that reason, for each widget we query, we append the
++ associated operation to a QList of transformations which we apply
++ to the widget before proceeding to the next.
++
++ \snippet painting/transformations/window.cpp 9
++
++ The \c shapeSelected() slot is called whenever the user changes
++ the preferred shape, updating the \c RenderArea widgets using
++ their public \c setShape() function.
++
++ \section1 Summary
++
++ The Transformations example shows how transformations influence
++ the way that QPainter renders graphics primitives. Normally, the
++ QPainter operates on the device's own coordinate system, but it
++ also has good support for coordinate transformations. With the
++ Transformations application you can scale, rotate and translate
++ QPainter's coordinate system. The order in which these
++ transformations are applied is essential for the result.
++
++ All the transformation operations operate on QPainter's
++ transformation matrix. For more information about the
++ transformation matrix, see the \l {Coordinate System} and
++ QTransform documentation.
++
++ The Qt reference documentation provides several painting
++ examples. Among these is the \l {painting/affine}{Affine
++ Transformations} example that shows Qt's ability to perform
++ transformations on painting operations. The example also allows the
++ user to experiment with the various transformation operations.
++ */