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"