/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of the Qt Build Suite. ** ** 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 http://www.qt.io/terms-conditions. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "mouse.h" #include #include #include #include static const double Pi = 3.14159265358979323846264338327950288419717; static double TwoPi = 2.0 * Pi; static qreal normalizeAngle(qreal angle) { while (angle < 0) angle += TwoPi; while (angle > TwoPi) angle -= TwoPi; return angle; } //! [0] Mouse::Mouse() : angle(0), speed(0), mouseEyeDirection(0), color(qrand() % 256, qrand() % 256, qrand() % 256) { setRotation(qrand() % (360 * 16)); } //! [0] //! [1] QRectF Mouse::boundingRect() const { qreal adjust = 0.5; return QRectF(-18 - adjust, -22 - adjust, 36 + adjust, 60 + adjust); } //! [1] //! [2] QPainterPath Mouse::shape() const { QPainterPath path; path.addRect(-10, -20, 20, 40); return path; } //! [2] //! [3] void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { // Body painter->setBrush(color); painter->drawEllipse(-10, -20, 20, 40); // Eyes painter->setBrush(Qt::white); painter->drawEllipse(-10, -17, 8, 8); painter->drawEllipse(2, -17, 8, 8); // Nose painter->setBrush(Qt::black); painter->drawEllipse(QRectF(-2, -22, 4, 4)); // Pupils painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4)); painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4)); // Ears painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red); painter->drawEllipse(-17, -12, 16, 16); painter->drawEllipse(1, -12, 16, 16); // Tail QPainterPath path(QPointF(0, 20)); path.cubicTo(-5, 22, -5, 22, 0, 25); path.cubicTo(5, 27, 5, 32, 0, 30); path.cubicTo(-5, 32, -5, 42, 0, 35); painter->setBrush(Qt::NoBrush); painter->drawPath(path); } //! [3] //! [4] void Mouse::advance(int step) { if (!step) return; //! [4] // Don't move too far away //! [5] QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0)); if (lineToCenter.length() > 150) { qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length()); if (lineToCenter.dy() < 0) angleToCenter = TwoPi - angleToCenter; angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2); if (angleToCenter < Pi && angleToCenter > Pi / 4) { // Rotate left angle += (angle < -Pi / 2) ? 0.25 : -0.25; } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) { // Rotate right angle += (angle < Pi / 2) ? 0.25 : -0.25; } } else if (::sin(angle) < 0) { angle += 0.25; } else if (::sin(angle) > 0) { angle -= 0.25; //! [5] //! [6] } //! [6] // Try not to crash with any other mice //! [7] QList dangerMice = scene()->items(QPolygonF() << mapToScene(0, 0) << mapToScene(-30, -50) << mapToScene(30, -50)); foreach (QGraphicsItem *item, dangerMice) { if (item == this) continue; QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0)); qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length()); if (lineToMouse.dy() < 0) angleToMouse = TwoPi - angleToMouse; angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2); if (angleToMouse >= 0 && angleToMouse < Pi / 2) { // Rotate right angle += 0.5; } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) { // Rotate left angle -= 0.5; //! [7] //! [8] } //! [8] //! [9] } //! [9] // Add some random movement //! [10] if (dangerMice.size() > 1 && (qrand() % 10) == 0) { if (qrand() % 1) angle += (qrand() % 100) / 500.0; else angle -= (qrand() % 100) / 500.0; } //! [10] //! [11] speed += (-50 + qrand() % 100) / 100.0; qreal dx = ::sin(angle) * 10; mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5; setRotation(rotation() + dx); setPos(mapToParent(0, -(3 + sin(speed) * 3))); } //! [11]