File indexing completed on 2022-09-27 12:31:08

0001 /*
0002     SPDX-FileCopyrightText: 2003-2006 Cies Breijs <cies AT kde DOT nl>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "canvas.h"
0008 
0009 #include <cmath>
0010 
0011 #include <QResizeEvent>
0012 #include <QWheelEvent>
0013 #include <QtMath>
0014 
0015 #include <KLocalizedString>
0016 
0017 
0018 
0019 int kTurtleZValue = 1;
0020 int kCanvasFrameZValue = -10000;
0021 int kCanvasMargin = 20;
0022 
0023 
0024 Canvas::Canvas(QWidget *parent) : QGraphicsView(parent)
0025 {
0026     // create a new scene for this view
0027     _scene = new QGraphicsScene(parent);
0028     //_scene->setItemIndexMethod(QGraphicsScene::NoIndex);
0029     //_scene->setSceneRect(-200, -200, 400, 400);  // (-50, -50, 50, 50);
0030 
0031     setCacheMode(CacheBackground);
0032     setRenderHint(QPainter::Antialiasing);
0033     setTransformationAnchor(AnchorUnderMouse);
0034     setResizeAnchor(AnchorViewCenter);
0035     setMinimumSize(100, 100);
0036 
0037     // foreground pen for drawing
0038     pen = new QPen();
0039     
0040     // font
0041     textFont = new QFont();
0042     
0043     // Canvas area marker
0044     canvasFrame = new QGraphicsRectItem();
0045     canvasFrame->setZValue(kCanvasFrameZValue);
0046     _scene->addItem(canvasFrame);
0047     
0048     // the turtle shape
0049     turtle = new Sprite();
0050     turtle->setZValue(kTurtleZValue);  // above the others
0051     _scene->addItem(turtle);
0052 
0053     // set initial values
0054     initValues();
0055     setInteractive(false);
0056 
0057     // at last we assign the scene to the view
0058     setScene(_scene);
0059 }
0060 
0061 Canvas::~Canvas()
0062 {
0063     delete pen;
0064     delete turtle;
0065     delete canvasFrame;
0066     delete textFont;
0067     delete _scene;
0068 }
0069 
0070 
0071 void Canvas::initValues()
0072 {
0073     _scene->setSceneRect(QRectF(0, 0, 400, 400));
0074     canvasFrame->setBrush(QBrush());
0075     canvasFrame->setRect(_scene->sceneRect());
0076     fitInView(_scene->sceneRect().adjusted(kCanvasMargin * -1, kCanvasMargin * -1, kCanvasMargin, kCanvasMargin), Qt::KeepAspectRatio);
0077     turtle->setPos(200, 200);
0078     turtle->setAngle(0);
0079     _scene->setBackgroundBrush(QBrush(Qt::white));
0080     pen->setColor(Qt::black);
0081     pen->setWidth(1);
0082     penWidthIsZero = false;
0083     textColor.setRgb(0, 0, 0) ;
0084     delete textFont;
0085     textFont = new QFont();
0086     // Reset our pen to the default position
0087     slotPenDown();
0088     // Show turtle, might have been hidden in the last run
0089     slotSpriteShow();
0090 }
0091 
0092 void Canvas::resizeEvent(QResizeEvent* event)
0093 {
0094     fitInView(_scene->sceneRect().adjusted(kCanvasMargin*-1,kCanvasMargin*-1,kCanvasMargin,kCanvasMargin), Qt::KeepAspectRatio);
0095     event->accept();
0096 }
0097 
0098 QColor Canvas::rgbDoublesToColor(double r, double g, double b)
0099 {
0100     return QColor(qMin(qMax(static_cast<int>(r), 0), 255),
0101             qMin(qMax(static_cast<int>(g), 0), 255),
0102             qMin(qMax(static_cast<int>(b), 0), 255));
0103 }
0104 
0105 void Canvas::drawLine(double x1, double y1, double x2, double y2)
0106 {
0107     if (penWidthIsZero) return;
0108     QGraphicsLineItem* line = new QGraphicsLineItem(QLineF(x1, y1, x2, y2), nullptr);
0109     _scene->addItem(line);
0110     line->setPen(*pen);
0111     lines.append(line);
0112 }
0113 
0114 
0115 void Canvas::slotClear()
0116 {
0117     const QList<QGraphicsItem*> list = _scene->items();
0118     for (QGraphicsItem* item : list) {
0119         // delete all but the turtle (who lives on a separate layer with z-value 1)
0120         if ((item->zValue() != kTurtleZValue) && (item->zValue() != kCanvasFrameZValue))
0121             delete item;
0122     }
0123 }
0124 
0125 void Canvas::slotForward(double x)
0126 {
0127     double x2 = turtle->pos().x() + (x * std::sin(qDegreesToRadians(turtle->angle())));
0128     double y2 = turtle->pos().y() - (x * std::cos(qDegreesToRadians(turtle->angle())));
0129     drawLine(turtle->pos().x(), turtle->pos().y(), x2, y2);
0130     slotGo(x2, y2);
0131 }
0132 
0133 void Canvas::slotBackward(double x)
0134 {
0135     double x2 = turtle->pos().x() - ( x * std::sin(qDegreesToRadians(turtle->angle())));
0136     double y2 = turtle->pos().y() + ( x * std::cos(qDegreesToRadians(turtle->angle())));
0137     drawLine(turtle->pos().x(), turtle->pos().y(), x2, y2);
0138     slotGo(x2, y2);
0139 }
0140 
0141 void Canvas::slotCenter()
0142 {
0143     slotGo(_scene->width()/2, _scene->height()/2);
0144 }
0145 
0146 void Canvas::slotPenWidth(double width)
0147 {
0148     int w = qMax(static_cast<int>(round(width)), 0);
0149     if (w == 0) {
0150         penWidthIsZero = true;
0151         return;
0152     } else {
0153         penWidthIsZero = false;
0154         if (w == 1)
0155             pen->setWidth(0);
0156         else
0157             pen->setWidthF(width);
0158     }
0159 }
0160 
0161 void Canvas::slotPenColor(double r, double g, double b)
0162 {
0163     pen->setColor(rgbDoublesToColor(r, g, b));
0164     textColor.setRgb(static_cast<int>(r), static_cast<int>(g), static_cast<int>(b));
0165 }
0166 
0167 void Canvas::slotCanvasColor(double r, double g, double b)
0168 {
0169     //_scene->setBackgroundBrush(QBrush(rgbDoublesToColor(r, g, b)));
0170     canvasFrame->setBrush(QBrush(rgbDoublesToColor(r, g, b)));
0171 }
0172 
0173 void Canvas::slotCanvasSize(double r, double g)
0174 {
0175     _scene->setSceneRect(QRectF(0,0,r,g));
0176     canvasFrame->setRect(_scene->sceneRect());
0177     fitInView(_scene->sceneRect(), Qt::KeepAspectRatio);
0178 }
0179 
0180 void Canvas::slotPrint(const QString& text)
0181 {
0182     QGraphicsTextItem *ti = new QGraphicsTextItem(text, nullptr);
0183     _scene->addItem(ti);
0184 //  ti->setDefaultTextColor(textColor);
0185     ti->setFont(*textFont);
0186     ti->setTransform(QTransform().rotate(turtle->angle()), true);
0187     ti->setPos(turtle->pos().x(), turtle->pos().y());
0188     ti->setDefaultTextColor(textColor);
0189 }
0190 
0191 void Canvas::slotFontType(const QString& family, const QString& extra)
0192 {
0193     textFont->setFamily(family);
0194     textFont->setBold(extra.contains(i18n("bold")));
0195     textFont->setItalic(extra.contains(i18n("italic")));
0196     textFont->setUnderline(extra.contains(i18n("underline")));
0197     textFont->setOverline(extra.contains(i18n("overline")));
0198     textFont->setStrikeOut(extra.contains(i18n("strikeout")));
0199 }
0200 
0201 void Canvas::slotReset()
0202 {
0203     slotClear();
0204     initValues();
0205 }
0206 
0207 void Canvas::wheelEvent(QWheelEvent *event)
0208 {
0209     scaleView(std::pow(static_cast<double>(2.0), -event->angleDelta().y() / 240.0));
0210 }
0211 
0212 void Canvas::scaleView(double scaleFactor)
0213 {
0214     qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
0215     if (factor < 0.07 || factor > 100) return;
0216     scale(scaleFactor, scaleFactor);
0217 }
0218 
0219 void Canvas::getX(double& value)
0220 {
0221     value = turtle->pos().x();
0222 }
0223 
0224 void Canvas::getY(double& value)
0225 {
0226     value = turtle->pos().y();
0227 }
0228 
0229 void Canvas::getDirection(double &value)
0230 {
0231     value = fmod(turtle->angle(), 360);
0232 }
0233 
0234 QImage Canvas::getPicture()
0235 {
0236     QImage png(sceneRect().size().toSize(), QImage::Format_RGB32);
0237     // create a painter to draw on the image
0238     QPainter p(&png);
0239     p.setRenderHint(QPainter::Antialiasing);  // antialiasing like our Canvas
0240     _scene->render(&p);
0241     p.end();
0242     return png;
0243 }
0244 
0245 void Canvas::saveAsSvg(const QString& title, const QString& fileName)
0246 {
0247     Q_UNUSED(title);
0248     // it would have been nicer if this method didn't needed to be passed a filename..
0249     // but otherwise some QBuffer, QByteArray, etc. thing had to be set up.
0250     QSvgGenerator generator;
0251     generator.setFileName(fileName);
0252     generator.setSize(_scene->sceneRect().size().toSize());
0253     generator.setViewBox(_scene->sceneRect());
0254     generator.setTitle(title);
0255 //  generator.setDescription(i18n("Created with KTurtle %1 -- %2").arg(version).arg(website));
0256     // create a painter to draw on the image
0257     QPainter p(&generator);
0258 //  p.setRenderHint(QPainter::Antialiasing);  // antialiasing like our Canvas
0259 
0260     bool spriteWasVisible = turtle->isVisible();
0261 
0262     slotSpriteHide();  // hide the sprite as it draws really ugly (especially when Qt < 4.5)
0263     _scene->render(&p);
0264 
0265     if(spriteWasVisible)
0266         slotSpriteShow();
0267     p.end();
0268 }