Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / static / source / qt5-mandelbrot / mandelbrotwidget.cxx
blob5886dd2664c0eda8d12ca823f90782303cdcf168
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 ** * Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** * Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in
28 ** the documentation and/or other materials provided with the
29 ** distribution.
30 ** * Neither the name of The Qt Company Ltd nor the names of its
31 ** contributors may be used to endorse or promote products derived
32 ** from this software without specific prior written permission.
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
47 ** $QT_END_LICENSE$
49 ****************************************************************************/
51 #include "mandelbrotwidget.h"
52 #include "mandelbrotwidget.moc"
54 #include <QtGui/QPainter>
55 #include <QtGui/QKeyEvent>
57 #include <math.h>
59 const double DefaultCenterX = -0.637011;
60 const double DefaultCenterY = -0.0395159;
61 const double DefaultScale = 0.00403897;
63 const double ZoomInFactor = 0.8;
64 const double ZoomOutFactor = 1 / ZoomInFactor;
65 const int ScrollStep = 20;
67 MandelbrotWidget::MandelbrotWidget(QWidget* parent)
68 : QWidget(parent)
69 , centerX(DefaultCenterX)
70 , centerY(DefaultCenterY)
71 , pixmapScale(DefaultScale)
72 , curScale(DefaultScale)
74 connect(&thread, &RenderThread::renderedImage, this, &MandelbrotWidget::updatePixmap);
76 setWindowTitle(tr("Mandelbrot"));
77 #if QT_CONFIG(cursor)
78 setCursor(Qt::CrossCursor);
79 #endif
80 resize(550, 400);
83 void MandelbrotWidget::paintEvent(QPaintEvent* /* event */)
85 QPainter painter(this);
86 painter.fillRect(rect(), Qt::black);
88 if (pixmap.isNull())
90 painter.setPen(Qt::white);
91 painter.drawText(rect(), Qt::AlignCenter, tr("Rendering initial image, please wait..."));
92 return;
95 if (qFuzzyCompare(curScale, pixmapScale))
97 painter.drawPixmap(pixmapOffset, pixmap);
99 else
101 auto previewPixmap = qFuzzyCompare(pixmap.devicePixelRatioF(), qreal(1))
102 ? pixmap
103 : pixmap.scaled(pixmap.size() / pixmap.devicePixelRatioF(),
104 Qt::KeepAspectRatio, Qt::SmoothTransformation);
105 double scaleFactor = pixmapScale / curScale;
106 int newWidth = int(previewPixmap.width() * scaleFactor);
107 int newHeight = int(previewPixmap.height() * scaleFactor);
108 int newX = pixmapOffset.x() + (previewPixmap.width() - newWidth) / 2;
109 int newY = pixmapOffset.y() + (previewPixmap.height() - newHeight) / 2;
111 painter.save();
112 painter.translate(newX, newY);
113 painter.scale(scaleFactor, scaleFactor);
115 QRectF exposed = painter.transform().inverted().mapRect(rect()).adjusted(-1, -1, 1, 1);
116 painter.drawPixmap(exposed, previewPixmap, exposed);
117 painter.restore();
120 QString text = tr("Use mouse wheel or the '+' and '-' keys to zoom. "
121 "Press and hold left mouse button to scroll.");
122 QFontMetrics metrics = painter.fontMetrics();
123 int textWidth = metrics.horizontalAdvance(text);
125 painter.setPen(Qt::NoPen);
126 painter.setBrush(QColor(0, 0, 0, 127));
127 painter.drawRect((width() - textWidth) / 2 - 5, 0, textWidth + 10, metrics.lineSpacing() + 5);
128 painter.setPen(Qt::white);
129 painter.drawText((width() - textWidth) / 2, metrics.leading() + metrics.ascent(), text);
132 void MandelbrotWidget::resizeEvent(QResizeEvent* /* event */)
134 thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());
137 void MandelbrotWidget::keyPressEvent(QKeyEvent* event)
139 switch (event->key())
141 case Qt::Key_Plus:
142 zoom(ZoomInFactor);
143 break;
144 case Qt::Key_Minus:
145 zoom(ZoomOutFactor);
146 break;
147 case Qt::Key_Left:
148 scroll(-ScrollStep, 0);
149 break;
150 case Qt::Key_Right:
151 scroll(+ScrollStep, 0);
152 break;
153 case Qt::Key_Down:
154 scroll(0, -ScrollStep);
155 break;
156 case Qt::Key_Up:
157 scroll(0, +ScrollStep);
158 break;
159 default:
160 QWidget::keyPressEvent(event);
164 #if QT_CONFIG(wheelevent)
165 void MandelbrotWidget::wheelEvent(QWheelEvent* event)
167 const int numDegrees = event->angleDelta().y() / 8;
168 const double numSteps = numDegrees / double(15);
169 zoom(pow(ZoomInFactor, numSteps));
171 #endif
173 void MandelbrotWidget::mousePressEvent(QMouseEvent* event)
175 if (event->button() == Qt::LeftButton)
176 lastDragPos = event->pos();
179 void MandelbrotWidget::mouseMoveEvent(QMouseEvent* event)
181 if (event->buttons() & Qt::LeftButton)
183 pixmapOffset += event->pos() - lastDragPos;
184 lastDragPos = event->pos();
185 update();
189 void MandelbrotWidget::mouseReleaseEvent(QMouseEvent* event)
191 if (event->button() == Qt::LeftButton)
193 pixmapOffset += event->pos() - lastDragPos;
194 lastDragPos = QPoint();
196 const auto pixmapSize = pixmap.size() / pixmap.devicePixelRatioF();
197 int deltaX = (width() - pixmapSize.width()) / 2 - pixmapOffset.x();
198 int deltaY = (height() - pixmapSize.height()) / 2 - pixmapOffset.y();
199 scroll(deltaX, deltaY);
203 void MandelbrotWidget::updatePixmap(const QImage& image, double scaleFactor)
205 if (!lastDragPos.isNull())
206 return;
208 pixmap = QPixmap::fromImage(image);
209 pixmapOffset = QPoint();
210 lastDragPos = QPoint();
211 pixmapScale = scaleFactor;
212 update();
215 void MandelbrotWidget::zoom(double zoomFactor)
217 curScale *= zoomFactor;
218 update();
219 thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());
222 void MandelbrotWidget::scroll(int deltaX, int deltaY)
224 centerX += deltaX * curScale;
225 centerY += deltaY * curScale;
226 update();
227 thread.render(centerX, centerY, curScale, size(), devicePixelRatioF());