Sophie

Sophie

distrib > Mageia > 6 > armv5tl > media > core-updates > by-pkgid > 768f7d9f703884aa2562bf0a651086df > files > 3922

qtbase5-doc-5.9.4-1.1.mga6.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- padnavigator.qdoc -->
  <title>Pad Navigator Example | Qt Widgets 5.9</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td >Qt 5.9</td><td ><a href="qtwidgets-index.html">Qt Widgets</a></td><td >Pad Navigator Example</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right">Qt 5.9.4 Reference Documentation</td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#roundrectitem-class-definition">RoundRectItem Class Definition</a></li>
<li class="level1"><a href="#flippablepad-class-definition">FlippablePad Class Definition</a></li>
<li class="level1"><a href="#splashitem-class-definition">SplashItem Class Definition</a></li>
<li class="level1"><a href="#padnavigator-class-definition">PadNavigator Class Definition</a></li>
<li class="level1"><a href="#the-main-function">The main() Function</a></li>
<li class="level1"><a href="#performance-notes">Performance Notes</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Pad Navigator Example</h1>
<span class="subtitle"></span>
<!-- $$$graphicsview/padnavigator-description -->
<div class="descr"> <a name="details"></a>
<p>The Pad Navigator Example shows how you can use Graphics View together with embedded widgets and Qt's <a href="../qtcore/statemachine-api.html">state machine framework</a> to create a simple but useful, dynamic, animated user interface.</p>
<p class="centerAlign"><img src="images/padnavigator-example.png" alt="" /></p><p>The interface consists of a flippable, rotating pad with icons that can be selected using the arrow keys on your keyboard or keypad. Pressing enter will flip the pad around and reveal its back side, which has a form embedded into a <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a>. You can interact with the form, and press the enter key to flip back to the front side of the pad at any time.</p>
<p>Graphics View provides the <a href="qgraphicsscene.html">QGraphicsScene</a> class for managing and interacting with a large number of custom-made 2D graphical items derived from the <a href="qgraphicsitem.html">QGraphicsItem</a> class, and a <a href="qgraphicsview.html">QGraphicsView</a> widget for visualizing the items, with support for zooming and rotation.</p>
<p>This example consists of a <code>RoundRectItem</code> class, a <code>FlippablePad</code> class, a <code>PadNavigator</code> class, a <code>SplashItem</code> class, and a <code>main()</code> function.</p>
<a name="roundrectitem-class-definition"></a>
<h2 id="roundrectitem-class-definition">RoundRectItem Class Definition</h2>
<p>The <code>RoundRectItem</code> class is used by itself to display the icons on the pad, and as a base class for <code>FlippablePad</code>, the class for the pad itself. The role of the class is to paint a round rectangle of a specified size and gradient color, and optionally to paint a pixmap icon on top. To support <code>FlippablePad</code> it also allows filling its contents with a plain window background color.</p>
<p>Let's start by reviewing the <code>RoundRectItem</code> class declaration.</p>
<pre class="cpp">

  <span class="keyword">class</span> RoundRectItem : <span class="keyword">public</span> <span class="type"><a href="qgraphicsobject.html">QGraphicsObject</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(bool fill READ fill WRITE setFill)
  <span class="keyword">public</span>:
      RoundRectItem(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> <span class="operator">&amp;</span>bounds<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> <span class="operator">&amp;</span>color<span class="operator">,</span>
                    <span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

      <span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span> pixmap() <span class="keyword">const</span>;
      <span class="type">void</span> setPixmap(<span class="keyword">const</span> <span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span> <span class="operator">&amp;</span>pixmap);

      <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> boundingRect() <span class="keyword">const</span> override;
      <span class="type">void</span> paint(<span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span> <span class="operator">*</span>painter<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="qstyleoptiongraphicsitem.html">QStyleOptionGraphicsItem</a></span> <span class="operator">*</span>option<span class="operator">,</span> <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>widget <span class="operator">=</span> <span class="number">0</span>) override;

      bool fill() <span class="keyword">const</span>;
      <span class="type">void</span> setFill(bool fill);

</pre>
<p><code>RoundRectItem</code> inherits <a href="qgraphicsobject.html">QGraphicsObject</a>, which makes it easy to control its properties using <a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a>. Its constructor takes a rectangle to determine its bounds, and a color.</p>
<p>Besides implementing the mandatory <a href="qgraphicsitem.html#paint">paint()</a> and <a href="qgraphicsitem.html#boundingRect">boundingRect()</a> pure virtual functions, it also provides the <code>pixmap</code> and <code>fill</code> properties.</p>
<p>The <code>pixmap</code> property sets an optional pixmap that is drawn on top of the round rectangle. The <code>fill</code> property will, when true, fill the round rectangle contents with a fixed <a href="../qtgui/qpalette.html#ColorRole-enum">QPalette::Window</a> background color. Otherwise the contents are filled using a gradient based on the color passed to <code>RoundRectItem</code>'s constructor.</p>
<pre class="cpp">

  <span class="keyword">private</span>:
      <span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span> pix;
      bool fillRect;
      <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> bounds;
      <span class="type"><a href="../qtgui/qlineargradient.html">QLinearGradient</a></span> gradient;
  };

</pre>
<p>The private data members are:</p>
<ul>
<li><code>pix</code>: The optional pixmap that is drawn on top of the rectangle.</li>
<li><code>fillRect</code>: Corresponds to the <code>fill</code> property.</li>
<li><code>color</code>: The configurable gradient color fill of the rectangle.</li>
<li><code>bounds</code>: The bounds of the rectangle.</li>
<li><code>gradient</code>: A precalculated gradient used to fill the rectangle.</li>
</ul>
<p>We will now review the <code>RoundRectItem</code> implementation. Let's start by looking at its constructor:</p>
<pre class="cpp">

  RoundRectItem<span class="operator">::</span>RoundRectItem(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> <span class="operator">&amp;</span>bounds<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> <span class="operator">&amp;</span>color<span class="operator">,</span>
                               <span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="qgraphicsobject.html">QGraphicsObject</a></span>(parent)<span class="operator">,</span> fillRect(<span class="keyword">false</span>)<span class="operator">,</span> bounds(bounds)
  {
      gradient<span class="operator">.</span>setStart(bounds<span class="operator">.</span>topLeft());
      gradient<span class="operator">.</span>setFinalStop(bounds<span class="operator">.</span>bottomRight());
      gradient<span class="operator">.</span>setColorAt(<span class="number">0</span><span class="operator">,</span> color);
      gradient<span class="operator">.</span>setColorAt(<span class="number">1</span><span class="operator">,</span> color<span class="operator">.</span>dark(<span class="number">200</span>));
      setCacheMode(ItemCoordinateCache);
  }

</pre>
<p>The constructor initializes its member variables and forwards the <code>parent</code> argument to <a href="qgraphicsobject.html">QGraphicsObject</a>'s constructor. It then constructs the linear gradient that is used in <a href="qgraphicsitem.html#paint">paint()</a> to draw the round rectangle's gradient background. The linear gradient's starting point is at the top-left corner of the bounds, and the end is at the bottom-left corner. The start color is identical to the color passed as an argument, and a slightly darker color is chosen for the final stop.</p>
<p>We store this gradient as a member variable to avoid having to recreate the gradient every time the item is repainted.</p>
<p>Finally we set the cache mode <a href="qgraphicsitem.html#CacheMode-enum">ItemCoordinateCache</a>. This mode causes the item's rendering to be cached into an off-screen pixmap that remains persistent as we move and transform the item. This mode is ideal for this example, and works particularly well with OpenGL and OpenGL ES.</p>
<pre class="cpp">

  <span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span> RoundRectItem<span class="operator">::</span>pixmap() <span class="keyword">const</span>
  {
      <span class="keyword">return</span> pix;
  }
  <span class="type">void</span> RoundRectItem<span class="operator">::</span>setPixmap(<span class="keyword">const</span> <span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span> <span class="operator">&amp;</span>pixmap)
  {
      pix <span class="operator">=</span> pixmap;
      update();
  }

</pre>
<p>The <code>pixmap</code> property implementation simple returns the member pixmap, or sets it and then calls <a href="qgraphicsitem.html#update">update()</a>.</p>
<pre class="cpp">

  <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> RoundRectItem<span class="operator">::</span>boundingRect() <span class="keyword">const</span>
  {
      <span class="keyword">return</span> bounds<span class="operator">.</span>adjusted(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">2</span><span class="operator">,</span> <span class="number">2</span>);
  }

</pre>
<p>As the <a href="qgraphicsitem.html#paint">paint()</a> implementation below draws a simple drop shadow down and to the right of the item, we return a slightly adjusted rectangle from <a href="qgraphicsitem.html#boundingRect">boundingRect()</a>.</p>
<pre class="cpp">

  <span class="type">void</span> RoundRectItem<span class="operator">::</span>paint(<span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span> <span class="operator">*</span>painter<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="qstyleoptiongraphicsitem.html">QStyleOptionGraphicsItem</a></span> <span class="operator">*</span>option<span class="operator">,</span>
                            <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>widget)
  {
      Q_UNUSED(option);
      Q_UNUSED(widget);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setPen(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>NoPen);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setBrush(<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span>(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">64</span>));
      painter<span class="operator">-</span><span class="operator">&gt;</span>drawRoundRect(bounds<span class="operator">.</span>translated(<span class="number">2</span><span class="operator">,</span> <span class="number">2</span>));

</pre>
<p>The <a href="qgraphicsitem.html#paint">paint()</a> implementation starts by rendering a semi transparent black round rectangle drop shadow, two units down and to the right of the main item.</p>
<pre class="cpp">

      <span class="keyword">if</span> (fillRect)
          painter<span class="operator">-</span><span class="operator">&gt;</span>setBrush(<span class="type"><a href="qapplication.html">QApplication</a></span><span class="operator">::</span>palette()<span class="operator">.</span>brush(<span class="type"><a href="../qtgui/qpalette.html">QPalette</a></span><span class="operator">::</span>Window));
      <span class="keyword">else</span>
          painter<span class="operator">-</span><span class="operator">&gt;</span>setBrush(gradient);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setPen(<span class="type"><a href="../qtgui/qpen.html">QPen</a></span>(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>black<span class="operator">,</span> <span class="number">1</span>));
      painter<span class="operator">-</span><span class="operator">&gt;</span>drawRoundRect(bounds);

</pre>
<p>We then draw the &quot;foreground&quot; round rectangle itself. The fill depends on the <code>fill</code> property; if true, we will with a plain <a href="../qtgui/qpalette.html#ColorRole-enum">QPalette::Window</a> color. We get the current brush from <a href="qapplication.html#palette">QApplication::palette</a>(). We assign a single unit wide pen for the stroke, assign the brush, and then draw the rectangle.</p>
<pre class="cpp">

      <span class="keyword">if</span> (<span class="operator">!</span>pix<span class="operator">.</span>isNull()) {
          painter<span class="operator">-</span><span class="operator">&gt;</span>scale(<span class="number">1.95</span><span class="operator">,</span> <span class="number">1.95</span>);
          painter<span class="operator">-</span><span class="operator">&gt;</span>drawPixmap(<span class="operator">-</span>pix<span class="operator">.</span>width() <span class="operator">/</span> <span class="number">2</span><span class="operator">,</span> <span class="operator">-</span>pix<span class="operator">.</span>height() <span class="operator">/</span> <span class="number">2</span><span class="operator">,</span> pix);
      }
  }

</pre>
<p>If a pixmap has been assigned to the <i>pixmap</i> property, we draw this pixmap in the center of the rectangle item. The pixmaps are scaled to match the size of the icons; in arguably a better approach would have been to store the icons with the right size in the first places.</p>
<pre class="cpp">

  bool RoundRectItem<span class="operator">::</span>fill() <span class="keyword">const</span>
  {
      <span class="keyword">return</span> fillRect;
  }
  <span class="type">void</span> RoundRectItem<span class="operator">::</span>setFill(bool fill)
  {
      fillRect <span class="operator">=</span> fill;
      update();
  }

</pre>
<p>Finally, for completeness we include the <code>fill</code> property implementation. It returns the <code>fill</code> member variable's value, and when assigned to, it calls <a href="qgraphicsitem.html#update">update()</a>.</p>
<p>As mentioned already, <code>RoundRectItem</code> is the base class for <code>FlippablePad</code>, which is the class representing the tilting pad itself. We will proceed to reviewing <code>FlippablePad</code>.</p>
<a name="flippablepad-class-definition"></a>
<h2 id="flippablepad-class-definition">FlippablePad Class Definition</h2>
<p><code>FlippablePad</code> is, in addition to its inherited <code>RoundRectItem</code> responsibilities, responsible for creating and managing a grid of icons.</p>
<pre class="cpp">

  <span class="keyword">class</span> FlippablePad : <span class="keyword">public</span> RoundRectItem
  {
  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> FlippablePad(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size<span class="operator">,</span> <span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

      RoundRectItem <span class="operator">*</span>iconAt(<span class="type">int</span> column<span class="operator">,</span> <span class="type">int</span> row) <span class="keyword">const</span>;

  <span class="keyword">private</span>:
      <span class="type"><a href="../qtcore/qvector.html">QVector</a></span><span class="operator">&lt;</span><span class="type"><a href="../qtcore/qvector.html">QVector</a></span><span class="operator">&lt;</span>RoundRectItem <span class="operator">*</span><span class="operator">&gt;</span> <span class="operator">&gt;</span> iconGrid;
  };

</pre>
<p>Its declaration is very simple: It inherits <code>RoundRectItem</code> and does not need any special polymorphic behavior. It's suitable to declare its own constructor, and a getter-function that allows <code>PadNavigator</code> to access the icons in the grid by (row, column).</p>
<p>The example has no &quot;real&quot; behavior or logic of any kind, and because of that, the icons do not need to provide any <i>behavior</i> or special interactions management. In a real application, however, it would be natural for the <code>FlippablePad</code> and its icons to handle more of the navigation logic. In this example, we have chosen to leave this to the <code>PadNavigator</code> class, which we will get back to below.</p>
<p>We will now review the <code>FlippablePad</code> implementation. This implementation starts with two helper functions: <code>boundsFromSize()</code> and <code>posForLocation()</code>:</p>
<pre class="cpp">

  <span class="keyword">static</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> boundsFromSize(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size)
  {
      <span class="keyword">return</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span>((<span class="operator">-</span>size<span class="operator">.</span>width() <span class="operator">/</span> <span class="number">2.0</span>) <span class="operator">*</span> <span class="number">150</span><span class="operator">,</span> (<span class="operator">-</span>size<span class="operator">.</span>height() <span class="operator">/</span> <span class="number">2.0</span>) <span class="operator">*</span> <span class="number">150</span><span class="operator">,</span>
                    size<span class="operator">.</span>width() <span class="operator">*</span> <span class="number">150</span><span class="operator">,</span> size<span class="operator">.</span>height() <span class="operator">*</span> <span class="number">150</span>);
  }

</pre>
<p><code>boundsForSize()</code> takes a <a href="../qtcore/qsize.html">QSize</a> argument, and returns the bounding rectangle of the flippable pad item. The <a href="../qtcore/qsize.html">QSize</a> determines how many rows and columns the icon grid should have. Each icon is given 150x150 units of space, and this determines the bounds.</p>
<pre class="cpp">

  <span class="keyword">static</span> <span class="type"><a href="../qtcore/qpointf.html">QPointF</a></span> posForLocation(<span class="type">int</span> column<span class="operator">,</span> <span class="type">int</span> row<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size)
  {
      <span class="keyword">return</span> <span class="type"><a href="../qtcore/qpointf.html">QPointF</a></span>(column <span class="operator">*</span> <span class="number">150</span><span class="operator">,</span> row <span class="operator">*</span> <span class="number">150</span>)
          <span class="operator">-</span> <span class="type"><a href="../qtcore/qpointf.html">QPointF</a></span>((size<span class="operator">.</span>width() <span class="operator">-</span> <span class="number">1</span>) <span class="operator">*</span> <span class="number">75</span><span class="operator">,</span> (size<span class="operator">.</span>height() <span class="operator">-</span> <span class="number">1</span>) <span class="operator">*</span> <span class="number">75</span>);
  }

</pre>
<p><code>posForLocation()</code> returns the position of an icon given its row and column position. Like <code>boundsForSize()</code>, the function assumes each icon is given 150x150 units of space, and that all icons are centered around the flippable pad item's origin (0, 0).</p>
<pre class="cpp">

  FlippablePad<span class="operator">::</span>FlippablePad(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size<span class="operator">,</span> <span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent)
      : RoundRectItem(boundsFromSize(size)<span class="operator">,</span> <span class="type"><a href="../qtgui/qcolor.html">QColor</a></span>(<span class="number">226</span><span class="operator">,</span> <span class="number">255</span><span class="operator">,</span> <span class="number">92</span><span class="operator">,</span> <span class="number">64</span>)<span class="operator">,</span> parent)
  {

</pre>
<p>The <code>FlippablePad</code> constructor passes suitable bounds (using <code>boundsForSize()</code>) and specific color to <code>RoundRectItem</code>'s constructor.</p>
<pre class="cpp">

      <span class="type">int</span> numIcons <span class="operator">=</span> size<span class="operator">.</span>width() <span class="operator">*</span> size<span class="operator">.</span>height();
      <span class="type"><a href="../qtcore/qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span><span class="operator">&gt;</span> pixmaps;
      <span class="type"><a href="../qtcore/qdiriterator.html">QDirIterator</a></span> it(<span class="string">&quot;:/images&quot;</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qstringlist.html">QStringList</a></span>() <span class="operator">&lt;</span><span class="operator">&lt;</span> <span class="string">&quot;*.png&quot;</span>);
      <span class="keyword">while</span> (it<span class="operator">.</span>hasNext() <span class="operator">&amp;</span><span class="operator">&amp;</span> pixmaps<span class="operator">.</span>size() <span class="operator">&lt;</span> numIcons)
          pixmaps <span class="operator">&lt;</span><span class="operator">&lt;</span> it<span class="operator">.</span>next();

</pre>
<p>It then loads pixmaps from compiled-in resources to use for its icons. <a href="../qtcore/qdiriterator.html">QDirIterator</a> is very useful in this context, as it allows us to fetch all resource &quot;*.png&quot; files inside the <code>:/images</code> directory without explicitly naming the files.</p>
<p>We also make sure not to load more pixmaps than we need.</p>
<pre class="cpp">

      <span class="keyword">const</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> iconRect(<span class="operator">-</span><span class="number">54</span><span class="operator">,</span> <span class="operator">-</span><span class="number">54</span><span class="operator">,</span> <span class="number">108</span><span class="operator">,</span> <span class="number">108</span>);
      <span class="keyword">const</span> <span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> iconColor(<span class="number">214</span><span class="operator">,</span> <span class="number">240</span><span class="operator">,</span> <span class="number">110</span><span class="operator">,</span> <span class="number">128</span>);
      iconGrid<span class="operator">.</span>resize(size<span class="operator">.</span>height());
      <span class="type">int</span> n <span class="operator">=</span> <span class="number">0</span>;

      <span class="keyword">for</span> (<span class="type">int</span> y <span class="operator">=</span> <span class="number">0</span>; y <span class="operator">&lt;</span> size<span class="operator">.</span>height(); <span class="operator">+</span><span class="operator">+</span>y) {
          iconGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">.</span>resize(size<span class="operator">.</span>width());
          <span class="keyword">for</span> (<span class="type">int</span> x <span class="operator">=</span> <span class="number">0</span>; x <span class="operator">&lt;</span> size<span class="operator">.</span>width(); <span class="operator">+</span><span class="operator">+</span>x) {
              RoundRectItem <span class="operator">*</span>rect <span class="operator">=</span> <span class="keyword">new</span> RoundRectItem(iconRect<span class="operator">,</span> iconColor<span class="operator">,</span> <span class="keyword">this</span>);
              rect<span class="operator">-</span><span class="operator">&gt;</span>setZValue(<span class="number">1</span>);
              rect<span class="operator">-</span><span class="operator">&gt;</span>setPos(posForLocation(x<span class="operator">,</span> y<span class="operator">,</span> size));
              rect<span class="operator">-</span><span class="operator">&gt;</span>setPixmap(pixmaps<span class="operator">.</span>at(n<span class="operator">+</span><span class="operator">+</span> <span class="operator">%</span> pixmaps<span class="operator">.</span>size()));
              iconGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">[</span>x<span class="operator">]</span> <span class="operator">=</span> rect;
          }
      }
  }

</pre>
<p>Now that we have the pixmaps, we can create icons, position then and assign pixmaps. We start by finding a suitable size and color for the icons, and initializing a convenient grid structure for storing the icons. This <code>iconGrid</code> is also used later to find the icon for a specific (column, row) location.</p>
<p>For each row and column in our grid, we proceed to constructing each icon as an instance of <code>RoundRectItem</code>. The item is placed by using the <code>posForLocation()</code> helper function. To make room for the slip-behind selection item, we give each icon a <a href="qgraphicsitem.html#zValue">Z-value</a> of 1. The pixmaps are distributed to the icons in round-robin fasion.</p>
<p>Again, this approach is only suitable for example purposes. In a real-life application where each icon represents a specific action, it would be more natural to assign the pixmaps directly, or that the icons themselves provide suitable pixmaps.</p>
<pre class="cpp">

  RoundRectItem <span class="operator">*</span>FlippablePad<span class="operator">::</span>iconAt(<span class="type">int</span> column<span class="operator">,</span> <span class="type">int</span> row) <span class="keyword">const</span>
  {
      <span class="keyword">return</span> iconGrid<span class="operator">[</span>row<span class="operator">]</span><span class="operator">[</span>column<span class="operator">]</span>;
  }

</pre>
<p>Finally, the <code>iconAt()</code> function returns a pointer to the icon at a specific row and column. It makes a somewhat bold assumption that the input is valid, which is fair because the <code>PadNavigator</code> class only calls this function with correct input.</p>
<p>We will now review the <code>SplashItem</code> class.</p>
<a name="splashitem-class-definition"></a>
<h2 id="splashitem-class-definition">SplashItem Class Definition</h2>
<p>The <code>SplashItem</code> class represents the &quot;splash window&quot;, a semitransparent white overlay with text that appears immediately after the application has started, and disappears after pressing any key. The animation is controlled by <code>PadNavigator</code>; this class is very simple by itself.</p>
<pre class="cpp">

  <span class="keyword">class</span> SplashItem : <span class="keyword">public</span> <span class="type"><a href="qgraphicsobject.html">QGraphicsObject</a></span>
  {
      Q_OBJECT
  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> SplashItem(<span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

      <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> boundingRect() <span class="keyword">const</span> override;
      <span class="type">void</span> paint(<span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span> <span class="operator">*</span>painter<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="qstyleoptiongraphicsitem.html">QStyleOptionGraphicsItem</a></span> <span class="operator">*</span>option<span class="operator">,</span> <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>widget <span class="operator">=</span> <span class="number">0</span>) override;

  <span class="keyword">private</span>:
      <span class="type"><a href="../qtcore/qstring.html">QString</a></span> text;
  };

</pre>
<p>The class declaration shows that <code>SplashItem</code> inherits <a href="qgraphicsobject.html">QGraphicsObject</a> to allow it to be controlled by <a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a>. It reimplements the mandatory <a href="qgraphicsitem.html#paint">paint()</a> and <a href="qgraphicsitem.html#boundingRect">boundingRect()</a> pure virtual functions, and keeps a <code>text</code> member variable which will contain the information text displayed on this splash item.</p>
<p>Let's look at its implementation.</p>
<pre class="cpp">

  SplashItem<span class="operator">::</span>SplashItem(<span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="qgraphicsobject.html">QGraphicsObject</a></span>(parent)
  {
      text <span class="operator">=</span> tr(<span class="string">&quot;Welcome to the Pad Navigator Example. You can use the&quot;</span>
                <span class="string">&quot; keyboard arrows to navigate the icons, and press enter&quot;</span>
                <span class="string">&quot; to activate an item. Press any key to begin.&quot;</span>);
      setCacheMode(DeviceCoordinateCache);
  }

</pre>
<p>The constructor forwards to <a href="qgraphicsobject.html">QGraphicsObject</a> as expected, assigns a text message to the <code>text</code> member variable, and enables <a href="qgraphicsitem.html#CacheMode-enum">DeviceCoordinateCache</a>. This cache mode is suitable because the splash item only moves and is never transformed, and because it contains text, it's important that it has a pixel perfect visual appearance (in constrast to <a href="qgraphicsitem.html#CacheMode-enum">ItemCoordinateCache</a>, where the visual appearance is not as good).</p>
<p>We use caching to avoid having to relayout and rerender the text for each frame. An alterative approach would be to use the new <a href="../qtgui/qstatictext.html">QStaticText</a> class.</p>
<pre class="cpp">

  <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> SplashItem<span class="operator">::</span>boundingRect() <span class="keyword">const</span>
  {
      <span class="keyword">return</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span>(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">400</span><span class="operator">,</span> <span class="number">175</span>);
  }

</pre>
<p><code>SplashItem</code>'s bounding rectangle is fixed at (400x175).</p>
<pre class="cpp">

  <span class="type">void</span> SplashItem<span class="operator">::</span>paint(<span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span> <span class="operator">*</span>painter<span class="operator">,</span> <span class="keyword">const</span> <span class="type"><a href="qstyleoptiongraphicsitem.html">QStyleOptionGraphicsItem</a></span> <span class="operator">*</span>option<span class="operator">,</span>
                         <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>widget)
  {
      Q_UNUSED(option);
      Q_UNUSED(widget);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setPen(<span class="type"><a href="../qtgui/qpen.html">QPen</a></span>(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>black<span class="operator">,</span> <span class="number">2</span>));
      painter<span class="operator">-</span><span class="operator">&gt;</span>setBrush(<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span>(<span class="number">245</span><span class="operator">,</span> <span class="number">245</span><span class="operator">,</span> <span class="number">255</span><span class="operator">,</span> <span class="number">220</span>));
      painter<span class="operator">-</span><span class="operator">&gt;</span>setClipRect(boundingRect());
      painter<span class="operator">-</span><span class="operator">&gt;</span>drawRoundRect(<span class="number">3</span><span class="operator">,</span> <span class="operator">-</span><span class="number">100</span> <span class="operator">+</span> <span class="number">3</span><span class="operator">,</span> <span class="number">400</span> <span class="operator">-</span> <span class="number">6</span><span class="operator">,</span> <span class="number">250</span> <span class="operator">-</span> <span class="number">6</span>);

      <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> textRect <span class="operator">=</span> boundingRect()<span class="operator">.</span>adjusted(<span class="number">10</span><span class="operator">,</span> <span class="number">10</span><span class="operator">,</span> <span class="operator">-</span><span class="number">10</span><span class="operator">,</span> <span class="operator">-</span><span class="number">10</span>);
      <span class="type">int</span> flags <span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>AlignTop <span class="operator">|</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>AlignLeft <span class="operator">|</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>TextWordWrap;

      <span class="type"><a href="../qtgui/qfont.html">QFont</a></span> font;
      font<span class="operator">.</span>setPixelSize(<span class="number">18</span>);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setPen(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>black);
      painter<span class="operator">-</span><span class="operator">&gt;</span>setFont(font);
      painter<span class="operator">-</span><span class="operator">&gt;</span>drawText(textRect<span class="operator">,</span> flags<span class="operator">,</span> text);
  }

</pre>
<p>The <a href="qgraphicsitem.html#paint">paint()</a> implementation draws a clipped round rectangle with a thick 2-unit border and a semi-transparent white background. It proceeds to finding a suitable text area by adjusting the splash item's bounding rectangle with 10 units in each side. The text is rendered inside this rectangle, with top-left alignment, and with word wrapping enabled.</p>
<p>The main class now remains. We will proceed to reviewing <code>PadNavigator</code>.</p>
<a name="padnavigator-class-definition"></a>
<h2 id="padnavigator-class-definition">PadNavigator Class Definition</h2>
<p><code>PadNavigator</code> represents the main window of our Pad Navigator Example application. It creates and controls a somewhat complex state machine, and several animations. Its class declaration is very simple:</p>
<pre class="cpp">

  <span class="keyword">class</span> PadNavigator : <span class="keyword">public</span> <span class="type"><a href="qgraphicsview.html">QGraphicsView</a></span>
  {
      Q_OBJECT
  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> PadNavigator(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size<span class="operator">,</span> <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

  <span class="keyword">protected</span>:
      <span class="type">void</span> resizeEvent(<span class="type"><a href="../qtgui/qresizeevent.html">QResizeEvent</a></span> <span class="operator">*</span>event) override;

  <span class="keyword">private</span>:
      Ui<span class="operator">::</span>Form form;
  };

</pre>
<p>It inherits <a href="qgraphicsview.html">QGraphicsView</a> and reimplements only one function: <a href="qgraphicsview.html#resizeEvent">resizeEvent()</a>, to ensure the scene is scaled to fit inside the view when resizing the main window.</p>
<p>The <code>PadNavigator</code> constructor takes a <a href="../qtcore/qsize.html">QSize</a> argument that determines the number or rows and columns in the grid.</p>
<p>It also keeps a private member instance, <code>form</code>, which is the generated code for the pad's back side item's <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a>-embedded form.</p>
<pre class="cpp">

  PadNavigator<span class="operator">::</span>PadNavigator(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> <span class="operator">&amp;</span>size<span class="operator">,</span> <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="qgraphicsview.html">QGraphicsView</a></span>(parent)
  {

</pre>
<p><code>PadNavigator</code>'s constructor is a bit long. In short, its job is to create all items, including the <code>FlippablePad</code>, the <code>SplashItem</code> and the <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a> <code>backItem</code>, and then to set up all animations, states and transitions that control the behavior of the application.</p>
<p>It starts out simple, by forwarding to <a href="qgraphicsview.html">QGraphicsView</a>'s constructor.</p>
<pre class="cpp">

      <span class="comment">// Splash item</span>
      SplashItem <span class="operator">*</span>splash <span class="operator">=</span> <span class="keyword">new</span> SplashItem;
      splash<span class="operator">-</span><span class="operator">&gt;</span>setZValue(<span class="number">1</span>);

</pre>
<p>The first item to be created is <code>SplashItem</code>. This is going to be a top-level item in the scene, next to <code>FlippablePad</code>, and stacked on top of it, so we assign it a <a href="qgraphicsitem.html#zValue">Z-value</a> of 1.</p>
<pre class="cpp">

      <span class="comment">// Pad item</span>
      FlippablePad <span class="operator">*</span>pad <span class="operator">=</span> <span class="keyword">new</span> FlippablePad(size);
      <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span> <span class="operator">*</span>flipRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span>(pad);
      <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span> <span class="operator">*</span>xRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span>(pad);
      <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span> <span class="operator">*</span>yRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgraphicsrotation.html">QGraphicsRotation</a></span>(pad);
      flipRotation<span class="operator">-</span><span class="operator">&gt;</span>setAxis(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>YAxis);
      xRotation<span class="operator">-</span><span class="operator">&gt;</span>setAxis(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>YAxis);
      yRotation<span class="operator">-</span><span class="operator">&gt;</span>setAxis(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>XAxis);
      pad<span class="operator">-</span><span class="operator">&gt;</span>setTransformations(<span class="type"><a href="../qtcore/qlist.html">QList</a></span><span class="operator">&lt;</span><span class="type"><a href="qgraphicstransform.html">QGraphicsTransform</a></span> <span class="operator">*</span><span class="operator">&gt;</span>()
                              <span class="operator">&lt;</span><span class="operator">&lt;</span> flipRotation
                              <span class="operator">&lt;</span><span class="operator">&lt;</span> xRotation <span class="operator">&lt;</span><span class="operator">&lt;</span> yRotation);

</pre>
<p>Now we construct the <code>FlippablePad</code> item, passing its column-row count to its constructor.</p>
<p>The pad is controlled by three transformations, and we create one <a href="qgraphicsrotation.html">QGraphicsRotation</a> object for each of these.</p>
<ul>
<li><code>flipRotation</code>: Rotates the grid around its <a href="../qtcore/qt.html#Axis-enum">Qt::YAxis</a>. This rotation is animated from 0 to 180, and eventually back, when enter is pressed on the keyboard, flipping the pad around.</li>
<li><code>xRotation</code>: Rotates the grid around its <a href="../qtcore/qt.html#Axis-enum">Qt::XAxis</a>. This is used to tilt the pad vertically corresponding to which item is currently selected. This way, the selected item is always kept in front.</li>
<li><code>yRotation</code>: Rotates the grid around its <a href="../qtcore/qt.html#Axis-enum">Qt::YAxis</a>. This is used to tilt the pad horizontally corresponding to which item is selected. This way, the selected item is always kept in front.</li>
</ul>
<p>The combination of all three rotations is assigned via <a href="qgraphicsitem.html#setTransformations">QGraphicsItem::setTransformations</a>().</p>
<pre class="cpp">

      <span class="comment">// Back (proxy widget) item</span>
      <span class="type"><a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a></span> <span class="operator">*</span>backItem <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a></span>(pad);
      <span class="type"><a href="qwidget.html">QWidget</a></span> <span class="operator">*</span>widget <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qwidget.html">QWidget</a></span>;
      form<span class="operator">.</span>setupUi(widget);
      form<span class="operator">.</span>hostName<span class="operator">-</span><span class="operator">&gt;</span>setFocus();
      backItem<span class="operator">-</span><span class="operator">&gt;</span>setWidget(widget);
      backItem<span class="operator">-</span><span class="operator">&gt;</span>setVisible(<span class="keyword">false</span>);
      backItem<span class="operator">-</span><span class="operator">&gt;</span>setFocus();
      backItem<span class="operator">-</span><span class="operator">&gt;</span>setCacheMode(<span class="type"><a href="qgraphicsitem.html">QGraphicsItem</a></span><span class="operator">::</span>ItemCoordinateCache);
      <span class="keyword">const</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> r <span class="operator">=</span> backItem<span class="operator">-</span><span class="operator">&gt;</span>rect();
      backItem<span class="operator">-</span><span class="operator">&gt;</span>setTransform(<span class="type"><a href="../qtgui/qtransform.html">QTransform</a></span>()
                             <span class="operator">.</span>rotate(<span class="number">180</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>YAxis)
                             <span class="operator">.</span>translate(<span class="operator">-</span>r<span class="operator">.</span>width()<span class="operator">/</span><span class="number">2</span><span class="operator">,</span> <span class="operator">-</span>r<span class="operator">.</span>height()<span class="operator">/</span><span class="number">2</span>));

</pre>
<p>Now we construct the <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a>-embedded <code>backItem</code>. The proxy widget is created as a child of the pad. We create a new <a href="qwidget.html">QWidget</a> and populate it with the <code>form</code> member. To ensure the <code>hostName</code> line edit is the first to receive input focus when this item is shown, we call <a href="qwidget.html#setFocus-1">setFocus()</a> immediately. This will not give the widget focus right away; it will only prepare the item to automatically receive focus once it is shown.</p>
<p>The <a href="qwidget.html">QWidget</a> based form is embedded into the proxy widget. The proxy is hidden initially; we only want to show it when the pad is rotated at least 90 degrees, and we also rotate the proxy itself by 180 degrees. This way we give the impression that the proxy widget is &quot;behind&quot; the flipped pad, when in fact, it's actually <i>on top of it</i>.</p>
<p>We enable <a href="qgraphicsitem.html#CacheMode-enum">ItemCoordinateCache</a> to ensure the flip animation can run smoothly.</p>
<pre class="cpp">

      <span class="comment">// Selection item</span>
      RoundRectItem <span class="operator">*</span>selectionItem <span class="operator">=</span> <span class="keyword">new</span> RoundRectItem(<span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span>(<span class="operator">-</span><span class="number">60</span><span class="operator">,</span> <span class="operator">-</span><span class="number">60</span><span class="operator">,</span> <span class="number">120</span><span class="operator">,</span> <span class="number">120</span>)<span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>gray<span class="operator">,</span> pad);
      selectionItem<span class="operator">-</span><span class="operator">&gt;</span>setZValue(<span class="number">0.5</span>);

</pre>
<p>We now create the selection item. This is simply another instance of <code>RoundRectItem</code> that is slightly larger than the icons on the pad. We create it as an immediate child of the <code>FlippablePad</code>, so the selection item is a sibling to all the icons. By giving it a <a href="qgraphicsitem.html#zValue">Z-value</a> of 0.5 we ensure it will slide between the pad and its icons.</p>
<p>What follows now is a series of animation initializations.</p>
<pre class="cpp">

      <span class="comment">// Splash animations</span>
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothSplashMove <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(splash<span class="operator">,</span> <span class="string">&quot;y&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothSplashOpacity <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(splash<span class="operator">,</span> <span class="string">&quot;opacity&quot;</span>);
      smoothSplashMove<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InQuad);
      smoothSplashMove<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">250</span>);
      smoothSplashOpacity<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">250</span>);

</pre>
<p>We begin with the animations that apply to the splash item. The first animation, <code>smoothSplashMove</code>, ensures that the &quot;y&quot; property of <code>splash</code> will be animated with a 250-millisecond duration <a href="../qtcore/qeasingcurve.html#Type-enum">InQuad</a> easing function. <code>smoothSplashOpacity</code> ensures the opacity of <code>splash</code> eases in and out in 250 milliseconds.</p>
<p>The values are assigned by <code>PadNavigator</code>'s state machine, which is created later.</p>
<pre class="cpp">

      <span class="comment">// Selection animation</span>
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothXSelection <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(selectionItem<span class="operator">,</span> <span class="string">&quot;x&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothYSelection <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(selectionItem<span class="operator">,</span> <span class="string">&quot;y&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothXRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(xRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothYRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(yRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span>);
      smoothXSelection<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">125</span>);
      smoothYSelection<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">125</span>);
      smoothXRotation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">125</span>);
      smoothYRotation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">125</span>);
      smoothXSelection<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothYSelection<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothXRotation<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothYRotation<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);

</pre>
<p>These are the animations that control the selection item's movement and the <code>xRotation</code> and <code>yRotation</code> <a href="qgraphicsrotation.html">QGraphicsRotation</a> objects that tilt the pad. All animations have a duration of 125 milliseconds, and they all use the <a href="../qtcore/qeasingcurve.html#Type-enum">InOutQuad</a> easing function.</p>
<pre class="cpp">

      <span class="comment">// Flip animation setup</span>
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothFlipRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(flipRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothFlipScale <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(pad<span class="operator">,</span> <span class="string">&quot;scale&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothFlipXRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(xRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>smoothFlipYRotation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(yRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span>);
      <span class="type"><a href="../qtcore/qparallelanimationgroup.html">QParallelAnimationGroup</a></span> <span class="operator">*</span>flipAnimation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qparallelanimationgroup.html">QParallelAnimationGroup</a></span>(<span class="keyword">this</span>);
      smoothFlipScale<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">500</span>);
      smoothFlipRotation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">500</span>);
      smoothFlipXRotation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">500</span>);
      smoothFlipYRotation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">500</span>);
      smoothFlipScale<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothFlipRotation<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothFlipXRotation<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothFlipYRotation<span class="operator">-</span><span class="operator">&gt;</span>setEasingCurve(<span class="type"><a href="../qtcore/qeasingcurve.html">QEasingCurve</a></span><span class="operator">::</span>InOutQuad);
      smoothFlipScale<span class="operator">-</span><span class="operator">&gt;</span>setKeyValueAt(<span class="number">0</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">1.0</span>));
      smoothFlipScale<span class="operator">-</span><span class="operator">&gt;</span>setKeyValueAt(<span class="number">0.5</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">0.7</span>));
      smoothFlipScale<span class="operator">-</span><span class="operator">&gt;</span>setKeyValueAt(<span class="number">1</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">1.0</span>));
      flipAnimation<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothFlipRotation);
      flipAnimation<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothFlipScale);
      flipAnimation<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothFlipXRotation);
      flipAnimation<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothFlipYRotation);

</pre>
<p>We now create the animations that control the flip-effect when you press the enter key. The main goal is to rotate the pad by 180 degrees or back, but we also need to make sure the selection item's tilt rotations are reset back to 0 when the pad is flipped, and restored back to their original values when flipped back:</p>
<ul>
<li><code>smoothFlipRotation</code>: Animates the main 180 degree rotation of the pad.</li>
<li><code>smoothFlipScale</code>: Scales the pad out and then in again while the pad is rotating.</li>
<li><code>smoothFlipXRotation</code>: Animates the selection item's X-tilt to 0 and back.</li>
<li><code>smoothFlipYRotation</code>: Animates the selection item's Y-tilt to 0 and back.</li>
<li><code>flipAnimation</code>: A parallel animation group that ensures all the above animations are run in parallel.</li>
</ul>
<p>All animations are given a 500 millisecond duration and an <a href="../qtcore/qeasingcurve.html#Type-enum">InOutQuad</a> easing function.</p>
<p>It's worth taking a close look at <code>smoothFlipScale</code>. This animation's start and end values are both 1.0, but at animation step 0.5 the animation's value is 0.7&#x2e; This means that after 50% of the animation's duration, or 250 milliseconds, the pad will be scaled down to 0.7x of its original size, which gives a great visual effect while flipping.</p>
<pre class="cpp">

      <span class="comment">// Flip animation delayed property assignment</span>
      <span class="type"><a href="../qtcore/qsequentialanimationgroup.html">QSequentialAnimationGroup</a></span> <span class="operator">*</span>setVariablesSequence <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qsequentialanimationgroup.html">QSequentialAnimationGroup</a></span>;
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>setFillAnimation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(pad<span class="operator">,</span> <span class="string">&quot;fill&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>setBackItemVisibleAnimation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(backItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span>);
      <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>setSelectionItemVisibleAnimation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(selectionItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span>);
      setFillAnimation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">0</span>);
      setBackItemVisibleAnimation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">0</span>);
      setSelectionItemVisibleAnimation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">0</span>);
      setVariablesSequence<span class="operator">-</span><span class="operator">&gt;</span>addPause(<span class="number">250</span>);
      setVariablesSequence<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(setBackItemVisibleAnimation);
      setVariablesSequence<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(setSelectionItemVisibleAnimation);
      setVariablesSequence<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(setFillAnimation);
      flipAnimation<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(setVariablesSequence);

</pre>
<p>This section uses a trick to ensure that certain properties are assigned precisely when the flip animation passes 50%, or 90 degrees, rotation. In short, the pad's icons and selection item are all hidden, the pad's <code>fill</code> property is enabled, and <code>backItem</code> is shown when flipping over. When flipping back, the reverse properties are applied.</p>
<p>The way this is achieved is by running a sequential animation in parallel to the other animations. This sequence, dubbed <code>setVariablesSequence</code>, starts with a 250 millisecond pause, and then executes several animations with a duration of 0. Each animation will ensure that properties are set immediate at this point.</p>
<p>This approach can also be used to call functions or set any other properties at a specific time while an animation is running.</p>
<pre class="cpp">

      <span class="comment">// Build the state machine</span>
      <span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span> <span class="operator">*</span>stateMachine <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span>(<span class="keyword">this</span>);
      <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>splashState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(stateMachine);
      <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>frontState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(stateMachine);
      <span class="type"><a href="../qtcore/qhistorystate.html">QHistoryState</a></span> <span class="operator">*</span>historyState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qhistorystate.html">QHistoryState</a></span>(frontState);
      <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>backState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(stateMachine);

</pre>
<p>We will now create the state machine. The whole <code>PadNavigator</code> state machinery is controlled by one single state machine that has a straight-forward state structure. The state engine itself is created as a child of the <code>PadNavigator</code> itself. We then create three top level states:</p>
<ul>
<li><code>splashState</code>: The initial state where the splash item is visible.</li>
<li><code>frontState</code>: The base state where the splash is gone and we can see the front side of the pad, and navigate the selection item.</li>
<li><code>backState</code>: The flipped state where the <code>backItem</code> is visible, and we can interact with the <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a>-embedded form.</li>
</ul>
<pre class="cpp">

      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(pad<span class="operator">,</span> <span class="string">&quot;fill&quot;</span><span class="operator">,</span> <span class="keyword">false</span>);
      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(splash<span class="operator">,</span> <span class="string">&quot;opacity&quot;</span><span class="operator">,</span> <span class="number">0.0</span>);
      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(backItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">false</span>);
      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(flipRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">0.0</span>));
      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(selectionItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">true</span>);
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(pad<span class="operator">,</span> <span class="string">&quot;fill&quot;</span><span class="operator">,</span> <span class="keyword">true</span>);
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(backItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">true</span>);
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(xRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">0.0</span>));
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(yRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">0.0</span>));
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(flipRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> qvariant_cast<span class="operator">&lt;</span><span class="type"><a href="../qtcore/qtglobal.html#qreal-typedef">qreal</a></span><span class="operator">&gt;</span>(<span class="number">180.0</span>));
      backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(selectionItem<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">false</span>);
      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>addDefaultAnimation(smoothXRotation);
      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>addDefaultAnimation(smoothYRotation);
      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>addDefaultAnimation(smoothXSelection);
      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>addDefaultAnimation(smoothYSelection);
      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>setInitialState(splashState);

</pre>
<p>Each state assigns specific properties to objects on entry. Most interesting perhaps is the assignment of the value 0.0 to the pad's <code>flipRotation</code> angle property when in <code>frontState</code>, and 180.0 when in <code>backState</code>. At the end of this section we register default animations with the state engine; these animations will apply to their respective objects and properties for any state transition. Otherwise it's common to assign animations to specific transitions.</p>
<p>The <code>splashState</code> state is set as the initial state. This is required before we start the state engine. We proceed with creating some transitions.</p>
<pre class="cpp">

      <span class="comment">// Transitions</span>
      <span class="type"><a href="../qtcore/qeventtransition.html">QEventTransition</a></span> <span class="operator">*</span>anyKeyTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qeventtransition.html">QEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span> splashState);
      anyKeyTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(frontState);
      anyKeyTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothSplashMove);
      anyKeyTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(smoothSplashOpacity);

</pre>
<p><a href="../qtcore/qeventtransition.html">QEventTransition</a> defines a very flexible transition type. You can use this class to trigger a transition based on an object receiving an event of a specific type. In this case, we would like to transition from <code>splashState</code> into <code>frontState</code> if <code>PadNavigator</code> receives any key press event (<a href="../qtcore/qevent.html#Type-enum">QEvent::KeyPress</a>).</p>
<p>We register the <code>splashItem</code>'s animations to this transition to ensure they are used to animate the item's movement and opacity.</p>
<pre class="cpp">

      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>enterTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                     <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Enter<span class="operator">,</span> backState);
      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>returnTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                      <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Return<span class="operator">,</span> backState);
      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>backEnterTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                         <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Enter<span class="operator">,</span> frontState);
      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>backReturnTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                          <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Return<span class="operator">,</span> frontState);
      enterTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(historyState);
      returnTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(historyState);
      backEnterTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(backState);
      backReturnTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(backState);
      enterTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(flipAnimation);
      returnTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(flipAnimation);
      backEnterTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(flipAnimation);
      backReturnTransition<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(flipAnimation);

</pre>
<p>We use <a href="qkeyeventtransition.html">QKeyEventTransition</a> to capture specific key events. In this case, we detect that the user presses <a href="../qtcore/qt.html#Key-enum">Qt::Key_Return</a> or <a href="../qtcore/qt.html#Key-enum">Qt::Key_Enter</a>, and use this to trigger transitions between <code>frontState</code> and backState. We register <code>flipAnimation</code>, our complex parallel animation group, with these transitions.</p>
<p>We continue by defining the states for each of the icons in the grid.</p>
<pre class="cpp">

      <span class="comment">// Create substates for each icon; store in temporary grid.</span>
      <span class="type">int</span> columns <span class="operator">=</span> size<span class="operator">.</span>width();
      <span class="type">int</span> rows <span class="operator">=</span> size<span class="operator">.</span>height();
      <span class="type"><a href="../qtcore/qvector.html">QVector</a></span><span class="operator">&lt;</span> <span class="type"><a href="../qtcore/qvector.html">QVector</a></span><span class="operator">&lt;</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span> <span class="operator">&gt;</span> <span class="operator">&gt;</span> stateGrid;
      stateGrid<span class="operator">.</span>resize(rows);
      <span class="keyword">for</span> (<span class="type">int</span> y <span class="operator">=</span> <span class="number">0</span>; y <span class="operator">&lt;</span> rows; <span class="operator">+</span><span class="operator">+</span>y) {
          stateGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">.</span>resize(columns);
          <span class="keyword">for</span> (<span class="type">int</span> x <span class="operator">=</span> <span class="number">0</span>; x <span class="operator">&lt;</span> columns; <span class="operator">+</span><span class="operator">+</span>x)
              stateGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">[</span>x<span class="operator">]</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(frontState);
      }
      frontState<span class="operator">-</span><span class="operator">&gt;</span>setInitialState(stateGrid<span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span>);
      selectionItem<span class="operator">-</span><span class="operator">&gt;</span>setPos(pad<span class="operator">-</span><span class="operator">&gt;</span>iconAt(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span>)<span class="operator">-</span><span class="operator">&gt;</span>pos());

</pre>
<p>We will use state groups to control transitions between icons. Each icon represents a <i>substate</i> of <code>frontState</code>. We will then define transitions between the states by detecting key presses, using <a href="qkeyeventtransition.html">QKeyEventTransition</a>.</p>
<p>We start by creating all the substates, and at the same time we create a temporary grid structure for the states to make it easier to find which states represents icons that are up, down, left and to the right each other.</p>
<p>Once the first substate is known, we set this up as the initial substate of <code>frontState</code>. We will use the (0, 0), or top-left, icon for the initial substate. We initialze the selection item's position to be exactly where the top-left icon is.</p>
<pre class="cpp">

      <span class="comment">// Enable key navigation using state transitions</span>
      <span class="keyword">for</span> (<span class="type">int</span> y <span class="operator">=</span> <span class="number">0</span>; y <span class="operator">&lt;</span> rows; <span class="operator">+</span><span class="operator">+</span>y) {
          <span class="keyword">for</span> (<span class="type">int</span> x <span class="operator">=</span> <span class="number">0</span>; x <span class="operator">&lt;</span> columns; <span class="operator">+</span><span class="operator">+</span>x) {
              <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>state <span class="operator">=</span> stateGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">[</span>x<span class="operator">]</span>;
              <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>rightTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                             <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Right<span class="operator">,</span> state);
              <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>leftTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                            <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Left<span class="operator">,</span> state);
              <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>downTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                            <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Down<span class="operator">,</span> state);
              <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>upTransition <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span>
                                                                          <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Up<span class="operator">,</span> state);
              rightTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(stateGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">[</span>(x <span class="operator">+</span> <span class="number">1</span>) <span class="operator">%</span> columns<span class="operator">]</span>);
              leftTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(stateGrid<span class="operator">[</span>y<span class="operator">]</span><span class="operator">[</span>((x <span class="operator">-</span> <span class="number">1</span>) <span class="operator">+</span> columns) <span class="operator">%</span> columns<span class="operator">]</span>);
              downTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(stateGrid<span class="operator">[</span>(y <span class="operator">+</span> <span class="number">1</span>) <span class="operator">%</span> rows<span class="operator">]</span><span class="operator">[</span>x<span class="operator">]</span>);
              upTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(stateGrid<span class="operator">[</span>((y <span class="operator">-</span> <span class="number">1</span>) <span class="operator">+</span> rows) <span class="operator">%</span> rows<span class="operator">]</span><span class="operator">[</span>x<span class="operator">]</span>);

</pre>
<p>We can now create four transitions for each icon. Each transition ensures that we move to the state corresponding to which arrow key has been pressed. It's clear from this techinique that we could design any other specific transitions to and from each of the sub states depending on these and other keys.</p>
<pre class="cpp">

              RoundRectItem <span class="operator">*</span>icon <span class="operator">=</span> pad<span class="operator">-</span><span class="operator">&gt;</span>iconAt(x<span class="operator">,</span> y);
              state<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(xRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> <span class="operator">-</span>icon<span class="operator">-</span><span class="operator">&gt;</span>x() <span class="operator">/</span> <span class="number">6.0</span>);
              state<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(yRotation<span class="operator">,</span> <span class="string">&quot;angle&quot;</span><span class="operator">,</span> icon<span class="operator">-</span><span class="operator">&gt;</span>y() <span class="operator">/</span> <span class="number">6.0</span>);
              state<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(selectionItem<span class="operator">,</span> <span class="string">&quot;x&quot;</span><span class="operator">,</span> icon<span class="operator">-</span><span class="operator">&gt;</span>x());
              state<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(selectionItem<span class="operator">,</span> <span class="string">&quot;y&quot;</span><span class="operator">,</span> icon<span class="operator">-</span><span class="operator">&gt;</span>y());
              frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(icon<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">true</span>);
              backState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(icon<span class="operator">,</span> <span class="string">&quot;visible&quot;</span><span class="operator">,</span> <span class="keyword">false</span>);

              <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span> <span class="operator">*</span>setIconVisibleAnimation <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qpropertyanimation.html">QPropertyAnimation</a></span>(icon<span class="operator">,</span> <span class="string">&quot;visible&quot;</span>);
              setIconVisibleAnimation<span class="operator">-</span><span class="operator">&gt;</span>setDuration(<span class="number">0</span>);
              setVariablesSequence<span class="operator">-</span><span class="operator">&gt;</span>addAnimation(setIconVisibleAnimation);
          }
      }

</pre>
<p>Also, for each of the icons, we assign suitable values to the <code>xRotation</code> and <code>yRotation</code> objects' &quot;angle&quot;-properties. If you recall, these properties &quot;tilt&quot; the pad corresponding to which item is currently selected. We ensure each icon is invisible when the pad is flipped, and visible when the pad is not flipped. To ensure the visible property is assigned at the right time, we add property-controlling animations to the <code>setVariableSequence</code> animation defined earlier.</p>
<pre class="cpp">

      <span class="comment">// Scene</span>
      <span class="type"><a href="qgraphicsscene.html">QGraphicsScene</a></span> <span class="operator">*</span>scene <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qgraphicsscene.html">QGraphicsScene</a></span>(<span class="keyword">this</span>);
      scene<span class="operator">-</span><span class="operator">&gt;</span>setBackgroundBrush(<span class="type"><a href="../qtgui/qpixmap.html">QPixmap</a></span>(<span class="string">&quot;:/images/blue_angle_swirl.jpg&quot;</span>));
      scene<span class="operator">-</span><span class="operator">&gt;</span>setItemIndexMethod(<span class="type"><a href="qgraphicsscene.html">QGraphicsScene</a></span><span class="operator">::</span>NoIndex);
      scene<span class="operator">-</span><span class="operator">&gt;</span>addItem(pad);
      scene<span class="operator">-</span><span class="operator">&gt;</span>setSceneRect(scene<span class="operator">-</span><span class="operator">&gt;</span>itemsBoundingRect());
      setScene(scene);

</pre>
<p>We are now finished with all states, transitions, and animations. We now create the scene that will contain all our items. The scene gets a defined background pixmap, and we disable item indexing (as most items in this scene are animated). We add our <code>pad</code> item to the scene, and use its bounding rectangle to fixate the scene rectangle. This rectangle is used by the view to find a suitable size for the application window.</p>
<p>Then the scene is assigned to the view, or in our case, <code>PadNavigator</code> itself.</p>
<pre class="cpp">

      <span class="comment">// Adjust splash item to scene contents</span>
      <span class="keyword">const</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span> sbr <span class="operator">=</span> splash<span class="operator">-</span><span class="operator">&gt;</span>boundingRect();
      splash<span class="operator">-</span><span class="operator">&gt;</span>setPos(<span class="operator">-</span>sbr<span class="operator">.</span>width() <span class="operator">/</span> <span class="number">2</span><span class="operator">,</span> scene<span class="operator">-</span><span class="operator">&gt;</span>sceneRect()<span class="operator">.</span>top() <span class="operator">-</span> <span class="number">2</span>);
      frontState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(splash<span class="operator">,</span> <span class="string">&quot;y&quot;</span><span class="operator">,</span> splash<span class="operator">-</span><span class="operator">&gt;</span>y() <span class="operator">-</span> <span class="number">100.0</span>);
      scene<span class="operator">-</span><span class="operator">&gt;</span>addItem(splash);

</pre>
<p>Now that the scene has received its final size, we can position the splash item at the very top, find its fade-out position, and add it to the scene.</p>
<pre class="cpp">

      <span class="comment">// View</span>
      setVerticalScrollBarPolicy(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>ScrollBarAlwaysOff);
      setHorizontalScrollBarPolicy(<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>ScrollBarAlwaysOff);
      setMinimumSize(<span class="number">50</span><span class="operator">,</span> <span class="number">50</span>);
      setViewportUpdateMode(FullViewportUpdate);
      setCacheMode(CacheBackground);
      setRenderHints(<span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span><span class="operator">::</span>Antialiasing
                     <span class="operator">|</span> <span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span><span class="operator">::</span>SmoothPixmapTransform
                     <span class="operator">|</span> <span class="type"><a href="../qtgui/qpainter.html">QPainter</a></span><span class="operator">::</span>TextAntialiasing);
  <span class="preprocessor">#ifndef QT_NO_OPENGL</span>
      setViewport(<span class="keyword">new</span> <span class="type"><a href="qopenglwidget.html">QOpenGLWidget</a></span>);
  <span class="preprocessor">#endif</span>

      stateMachine<span class="operator">-</span><span class="operator">&gt;</span>start();

</pre>
<p>The view toggles a few necessary properties:</p>
<ul>
<li>It disables its scroll bars - this application has no use for scroll bars.</li>
<li>It assigns a minimum size. This is necessary to avoid numerical errors in our fit-in-view <code>resizeEvent()</code> implementation.</li>
<li>It sets <a href="qgraphicsview.html#ViewportUpdateMode-enum">FullViewportUpdate</a>, to ensure <a href="qgraphicsview.html">QGraphicsView</a> doesn't spend time figuring out precisely what needs to be redrawn. This application is very simple - if anything changes, everything is updated.</li>
<li>It enables background caching - this makes no performance difference with OpenGL, but without OpenGL it avoids unnecessary re-scaling of the background pixmap.</li>
<li>It sets render hints that increase rendering quality.</li>
<li>If OpenGL is supported, a QGLWidget viewport is assigned to the view.</li>
</ul>
<p>Finally, we start the state engine.</p>
<pre class="cpp">

  <span class="type">void</span> PadNavigator<span class="operator">::</span>resizeEvent(<span class="type"><a href="../qtgui/qresizeevent.html">QResizeEvent</a></span> <span class="operator">*</span>event)
  {
      <span class="type"><a href="qgraphicsview.html">QGraphicsView</a></span><span class="operator">::</span>resizeEvent(event);
      fitInView(scene()<span class="operator">-</span><span class="operator">&gt;</span>sceneRect()<span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>KeepAspectRatio);
  }

</pre>
<p>The <a href="qgraphicsview.html#resizeEvent">resizeEvent()</a> implementation calls the base implementation, and then calls <a href="qgraphicsview.html#fitInView">QGraphicsView::fitInView</a>() to scale the scene so that it fits perfectly inside the view.</p>
<p>By resizing the main application window, you can see this effect yourself. The scene contents grow when you make the window larger, and shrink when you make it smaller, while keeping the aspect ratio intact.</p>
<a name="the-main-function"></a>
<h2 id="the-main-function">The main() Function</h2>
<pre class="cpp">

  <span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span>argv<span class="operator">[</span><span class="operator">]</span>)
  {
      <span class="type"><a href="qapplication.html">QApplication</a></span> app(argc<span class="operator">,</span> argv);
      Q_INIT_RESOURCE(padnavigator);

      PadNavigator navigator(<span class="type"><a href="../qtcore/qsize.html">QSize</a></span>(<span class="number">3</span><span class="operator">,</span> <span class="number">3</span>));
      navigator<span class="operator">.</span>show();
      <span class="keyword">return</span> app<span class="operator">.</span>exec();
  }

</pre>
<p>The <code>main</code> function creates the <a href="qapplication.html">QApplication</a> instance, uses <a href="../qtcore/qdir.html#Q_INIT_RESOURCE">Q_INIT_RESOURCE</a> to ensure our compiled-in resources aren't removed by the linker, and then creates a 3x3 <code>PadNavigator</code> instance and shows it.</p>
<p>Our flippable pad shows up with a suitable splash item once control returns to the event loop.</p>
<a name="performance-notes"></a>
<h2 id="performance-notes">Performance Notes</h2>
<p>The example uses OpenGL if this is available, to achieve optimal performance; otherwise perspective tranformations can be quite costly.</p>
<p>Although this example does use <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a> to demonstrate integration of Qt widget components integrated into Graphics View, using <a href="qgraphicsproxywidget.html">QGraphicsProxyWidget</a> comes with a performance penalty, and is therefore not recommended for embedded development.</p>
<p>This example uses extensive item caching to avoid rerendering of static elements, at the expense of graphics memory.</p>
<p>Files:</p>
<ul>
<li><a href="qtwidgets-graphicsview-padnavigator-flippablepad-cpp.html">graphicsview/padnavigator/flippablepad.cpp</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-flippablepad-h.html">graphicsview/padnavigator/flippablepad.h</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-form-ui.html">graphicsview/padnavigator/form.ui</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-padnavigator-cpp.html">graphicsview/padnavigator/padnavigator.cpp</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-padnavigator-h.html">graphicsview/padnavigator/padnavigator.h</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-roundrectitem-cpp.html">graphicsview/padnavigator/roundrectitem.cpp</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-roundrectitem-h.html">graphicsview/padnavigator/roundrectitem.h</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-splashitem-cpp.html">graphicsview/padnavigator/splashitem.cpp</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-splashitem-h.html">graphicsview/padnavigator/splashitem.h</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-main-cpp.html">graphicsview/padnavigator/main.cpp</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-padnavigator-pro.html">graphicsview/padnavigator/padnavigator.pro</a></li>
<li><a href="qtwidgets-graphicsview-padnavigator-padnavigator-qrc.html">graphicsview/padnavigator/padnavigator.qrc</a></li>
</ul>
<p>Images:</p>
<ul>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/artsfftscope.png">graphicsview/padnavigator/images/artsfftscope.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/blue_angle_swirl.jpg">graphicsview/padnavigator/images/blue_angle_swirl.jpg</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/kontact_contacts.png">graphicsview/padnavigator/images/kontact_contacts.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/kontact_journal.png">graphicsview/padnavigator/images/kontact_journal.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/kontact_mail.png">graphicsview/padnavigator/images/kontact_mail.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/kontact_notes.png">graphicsview/padnavigator/images/kontact_notes.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/kopeteavailable.png">graphicsview/padnavigator/images/kopeteavailable.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/metacontact_online.png">graphicsview/padnavigator/images/metacontact_online.png</a></li>
<li><a href="images/used-in-examples/graphicsview/padnavigator/images/minitools.png">graphicsview/padnavigator/images/minitools.png</a></li>
</ul>
</div>
<!-- @@@graphicsview/padnavigator -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2017 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>