sortingbox.cpp Example File

widgets/tooltips/sortingbox.cpp

  /****************************************************************************
  **
  ** Copyright (C) 2016 The Qt Company Ltd.
  ** Contact: https://www.qt.io/licensing/
  **
  ** This file is part of the examples of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:BSD$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and The Qt Company. For licensing terms
  ** and conditions see https://www.qt.io/terms-conditions. For further
  ** information use the contact form at https://www.qt.io/contact-us.
  **
  ** BSD License Usage
  ** Alternatively, you may use this file under the terms of the BSD license
  ** as follows:
  **
  ** "Redistribution and use in source and binary forms, with or without
  ** modification, are permitted provided that the following conditions are
  ** met:
  **   * Redistributions of source code must retain the above copyright
  **     notice, this list of conditions and the following disclaimer.
  **   * Redistributions in binary form must reproduce the above copyright
  **     notice, this list of conditions and the following disclaimer in
  **     the documentation and/or other materials provided with the
  **     distribution.
  **   * Neither the name of The Qt Company Ltd nor the names of its
  **     contributors may be used to endorse or promote products derived
  **     from this software without specific prior written permission.
  **
  **
  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/

  #include <QtWidgets>

  #include <stdlib.h>

  #include "sortingbox.h"

  SortingBox::SortingBox()
  {
      setMouseTracking(true);
      setBackgroundRole(QPalette::Base);

      itemInMotion = 0;

      newCircleButton = createToolButton(tr("New Circle"),
                                         QIcon(":/images/circle.png"),
                                         SLOT(createNewCircle()));

      newSquareButton = createToolButton(tr("New Square"),
                                         QIcon(":/images/square.png"),
                                         SLOT(createNewSquare()));

      newTriangleButton = createToolButton(tr("New Triangle"),
                                           QIcon(":/images/triangle.png"),
                                           SLOT(createNewTriangle()));

      circlePath.addEllipse(QRect(0, 0, 100, 100));
      squarePath.addRect(QRect(0, 0, 100, 100));

      qreal x = trianglePath.currentPosition().x();
      qreal y = trianglePath.currentPosition().y();
      trianglePath.moveTo(x + 120 / 2, y);
      trianglePath.lineTo(0, 100);
      trianglePath.lineTo(120, 100);
      trianglePath.lineTo(x + 120 / 2, y);

      setWindowTitle(tr("Tool Tips"));
      resize(500, 300);

      createShapeItem(circlePath, tr("Circle"), initialItemPosition(circlePath),
                      initialItemColor());
      createShapeItem(squarePath, tr("Square"), initialItemPosition(squarePath),
                      initialItemColor());
      createShapeItem(trianglePath, tr("Triangle"),
                      initialItemPosition(trianglePath), initialItemColor());
  }

  bool SortingBox::event(QEvent *event)
  {
      if (event->type() == QEvent::ToolTip) {
          QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
          int index = itemAt(helpEvent->pos());
          if (index != -1) {
              QToolTip::showText(helpEvent->globalPos(), shapeItems[index].toolTip());
          } else {
              QToolTip::hideText();
              event->ignore();
          }

          return true;
      }
      return QWidget::event(event);
  }

  void SortingBox::resizeEvent(QResizeEvent * /* event */)
  {
      int margin = style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin);
      int x = width() - margin;
      int y = height() - margin;

      y = updateButtonGeometry(newCircleButton, x, y);
      y = updateButtonGeometry(newSquareButton, x, y);
      updateButtonGeometry(newTriangleButton, x, y);
  }

  void SortingBox::paintEvent(QPaintEvent * /* event */)
  {
      QPainter painter(this);
      painter.setRenderHint(QPainter::Antialiasing);
      foreach (ShapeItem shapeItem, shapeItems) {
          painter.translate(shapeItem.position());
          painter.setBrush(shapeItem.color());
          painter.drawPath(shapeItem.path());
          painter.translate(-shapeItem.position());
      }
  }

  void SortingBox::mousePressEvent(QMouseEvent *event)
  {
      if (event->button() == Qt::LeftButton) {
          int index = itemAt(event->pos());
          if (index != -1) {
              itemInMotion = &shapeItems[index];
              previousPosition = event->pos();
              shapeItems.move(index, shapeItems.size() - 1);
              update();
          }
      }
  }

  void SortingBox::mouseMoveEvent(QMouseEvent *event)
  {
      if ((event->buttons() & Qt::LeftButton) && itemInMotion)
          moveItemTo(event->pos());
  }

  void SortingBox::mouseReleaseEvent(QMouseEvent *event)
  {
      if (event->button() == Qt::LeftButton && itemInMotion) {
          moveItemTo(event->pos());
          itemInMotion = 0;
      }
  }

  void SortingBox::createNewCircle()
  {
      static int count = 1;
      createShapeItem(circlePath, tr("Circle <%1>").arg(++count),
                      randomItemPosition(), randomItemColor());
  }

  void SortingBox::createNewSquare()
  {
      static int count = 1;
      createShapeItem(squarePath, tr("Square <%1>").arg(++count),
                      randomItemPosition(), randomItemColor());
  }

  void SortingBox::createNewTriangle()
  {
      static int count = 1;
      createShapeItem(trianglePath, tr("Triangle <%1>").arg(++count),
                      randomItemPosition(), randomItemColor());
  }

  int SortingBox::itemAt(const QPoint &pos)
  {
      for (int i = shapeItems.size() - 1; i >= 0; --i) {
          const ShapeItem &item = shapeItems[i];
          if (item.path().contains(pos - item.position()))
              return i;
      }
      return -1;
  }

  void SortingBox::moveItemTo(const QPoint &pos)
  {
      QPoint offset = pos - previousPosition;
      itemInMotion->setPosition(itemInMotion->position() + offset);
      previousPosition = pos;
      update();
  }

  int SortingBox::updateButtonGeometry(QToolButton *button, int x, int y)
  {
      QSize size = button->sizeHint();
      button->setGeometry(x - size.rwidth(), y - size.rheight(),
                          size.rwidth(), size.rheight());

      return y - size.rheight()
             - style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
  }

  void SortingBox::createShapeItem(const QPainterPath &path,
                                   const QString &toolTip, const QPoint &pos,
                                   const QColor &color)
  {
      ShapeItem shapeItem;
      shapeItem.setPath(path);
      shapeItem.setToolTip(toolTip);
      shapeItem.setPosition(pos);
      shapeItem.setColor(color);
      shapeItems.append(shapeItem);
      update();
  }

  QToolButton *SortingBox::createToolButton(const QString &toolTip,
                                            const QIcon &icon, const char *member)
  {
      QToolButton *button = new QToolButton(this);
      button->setToolTip(toolTip);
      button->setIcon(icon);
      button->setIconSize(QSize(32, 32));
      connect(button, SIGNAL(clicked()), this, member);

      return button;
  }

  QPoint SortingBox::initialItemPosition(const QPainterPath &path)
  {
      int x;
      int y = (height() - (int)path.controlPointRect().height()) / 2;
      if (shapeItems.size() == 0)
          x = ((3 * width()) / 2 - (int)path.controlPointRect().width()) / 2;
      else
          x = (width() / shapeItems.size()
               - (int)path.controlPointRect().width()) / 2;

      return QPoint(x, y);
  }

  QPoint SortingBox::randomItemPosition()
  {
      return QPoint(qrand() % (width() - 120), qrand() % (height() - 120));
  }

  QColor SortingBox::initialItemColor()
  {
      return QColor::fromHsv(((shapeItems.size() + 1) * 85) % 256, 255, 190);
  }

  QColor SortingBox::randomItemColor()
  {
      return QColor::fromHsv(qrand() % 256, 255, 190);
  }