File indexing completed on 2024-04-28 07:33:17

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