File indexing completed on 2024-05-19 15:27:46

0001 /* This file is part of KGraphViewer.
0002    Copyright (C) 2005-2007 Gael de Chalendar <kleag@free.fr>
0003 
0004    KGraphViewer is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, version 2.
0007 
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011    General Public License for more details.
0012 
0013    You should have received a copy of the GNU General Public License
0014    along with this program; if not, write to the Free Software
0015    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0016    02110-1301, USA
0017 */
0018 
0019 #include "canvaselement.h"
0020 #include "FontsCache.h"
0021 #include "dot2qtconsts.h"
0022 #include "dotdefaults.h"
0023 #include "dotgraphview.h"
0024 #include "graphelement.h"
0025 #include "kgraphviewerlib_debug.h"
0026 
0027 #include <iostream>
0028 #include <math.h>
0029 #include <stdlib.h>
0030 
0031 #include <QGraphicsScene>
0032 #include <QGraphicsSceneMouseEvent>
0033 #include <QMenu>
0034 #include <QPainter>
0035 
0036 #include <QAction>
0037 #include <QDebug>
0038 #include <klocalizedstring.h>
0039 
0040 // comment out to get extended debug output during rendering
0041 // #define RENDER_DEBUG 1
0042 
0043 #ifndef RENDER_DEBUG
0044 #define RENDER_DEBUG 0
0045 #endif
0046 
0047 namespace KGraphViewer
0048 {
0049 CanvasElement::CanvasElement(DotGraphView *v, GraphElement *gelement, QGraphicsScene *c, QGraphicsItem *parent)
0050     : QObject()
0051     , QAbstractGraphicsShapeItem(parent)
0052     , m_scaleX(0)
0053     , m_scaleY(0)
0054     , m_xMargin(0)
0055     , m_yMargin(0)
0056     , m_gh(0)
0057     , m_element(gelement)
0058     , m_view(v)
0059     , m_font(nullptr)
0060     , m_pen(Dot2QtConsts::componentData().qtColor(gelement->fontColor()))
0061     , m_popup(new QMenu())
0062     , m_hovered(false)
0063     , m_lastRenderOpRev(0)
0064 {
0065     //   qCDebug(KGRAPHVIEWERLIB_LOG);
0066     m_font = FontsCache::changeable().fromName(gelement->fontName());
0067 
0068     /*  qCDebug(KGRAPHVIEWERLIB_LOG) << "Creating CanvasElement for "<<gelement->id();
0069       qCDebug(KGRAPHVIEWERLIB_LOG) << "    data: " << wdhcf << "," << hdvcf << "," << gh << ","
0070         << scaleX << "," << scaleY << "," << xMargin << "," << yMargin << endl;*/
0071 
0072     if (element()->style() == "bold") {
0073         m_pen.setStyle(Qt::SolidLine);
0074         m_pen.setWidth(int(2 * ((m_scaleX + m_scaleY) / 2)));
0075     } else if (element()->style() != "filled") {
0076         m_pen.setStyle(Dot2QtConsts::componentData().qtPenStyle(m_element->style()));
0077         m_pen.setWidth(int((m_scaleX + m_scaleY) / 2));
0078         if (element()->style().left(12) == "setlinewidth") {
0079             bool ok;
0080             uint lineWidth = element()->style().mid(13, m_element->style().length() - 1 - 13).toInt(&ok);
0081             m_pen.setWidth(lineWidth * int((m_scaleX + m_scaleY) / 2));
0082         }
0083     }
0084     if (m_element->style() == "filled") {
0085         m_brush = Dot2QtConsts::componentData().qtColor(element()->backColor());
0086         //     QCanvasPolygon::drawShape(p);
0087     } else {
0088         m_brush = c->backgroundBrush();
0089     }
0090 
0091     // the message should be given (or possible to be given) by the part user
0092     QAction *removeElementAction = new QAction(i18n("Remove selected element(s)"), this);
0093     m_popup->addAction(removeElementAction);
0094     connect(removeElementAction, &QAction::triggered, this, &CanvasElement::slotRemoveElement);
0095 
0096     connect(this, &CanvasElement::selected, v, &DotGraphView::slotElementSelected);
0097 
0098     connect(this, &CanvasElement::elementContextMenuEvent, v, &DotGraphView::slotContextMenuEvent);
0099 
0100     setAcceptHoverEvents(true);
0101 
0102     connect(this, &CanvasElement::hoverEnter, v, static_cast<void (DotGraphView::*)(CanvasElement *)>(&DotGraphView::slotElementHoverEnter));
0103     connect(this, &CanvasElement::hoverLeave, v, static_cast<void (DotGraphView::*)(CanvasElement *)>(&DotGraphView::slotElementHoverLeave));
0104 }
0105 
0106 CanvasElement::~CanvasElement()
0107 {
0108     delete m_popup;
0109 }
0110 
0111 void CanvasElement::modelChanged()
0112 {
0113     qCDebug(KGRAPHVIEWERLIB_LOG); //<< id();
0114     m_pen = QPen(Dot2QtConsts::componentData().qtColor(m_element->fontColor()));
0115     m_font = FontsCache::changeable().fromName(m_element->fontName());
0116     prepareGeometryChange();
0117     computeBoundingRect();
0118 }
0119 
0120 void CanvasElement::initialize(qreal scaleX, qreal scaleY, qreal xMargin, qreal yMargin, qreal gh)
0121 {
0122     Q_UNUSED(gh);
0123     //   qCDebug(KGRAPHVIEWERLIB_LOG);
0124     setFlag(QGraphicsItem::ItemIsMovable, true);
0125     setFlag(QGraphicsItem::ItemIsSelectable, true);
0126 
0127     m_scaleX = scaleX;
0128     m_scaleY = scaleY;
0129     m_xMargin = xMargin;
0130     m_yMargin = yMargin;
0131     //   m_gh = gh;
0132 
0133     setZValue(m_element->z());
0134 
0135     computeBoundingRect();
0136 }
0137 
0138 QRectF CanvasElement::boundingRect() const
0139 {
0140     return m_boundingRect;
0141 }
0142 
0143 void CanvasElement::computeBoundingRect()
0144 {
0145     //   qCDebug(KGRAPHVIEWERLIB_LOG) << element();
0146     qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << zValue();
0147 
0148     qreal adjust = 0.5;
0149     QRectF rect;
0150     if (element()->renderOperations().isEmpty()) {
0151         qCDebug(KGRAPHVIEWERLIB_LOG) << "no render operation";
0152         rect = QRectF(0, 0, (m_view->defaultNewElementPixmap().size().width()) * m_scaleX, (m_view->defaultNewElementPixmap().size().height()) * m_scaleY);
0153         m_boundingRect = rect;
0154     } else {
0155         DotRenderOpVec::const_iterator it, it_end;
0156         it = element()->renderOperations().constBegin();
0157         it_end = element()->renderOperations().constEnd();
0158         for (; it != it_end; it++) {
0159 #if RENDER_DEBUG
0160             QString msg;
0161             QTextStream dd(&msg);
0162             dd << element()->id() << " an op: " << (*it).renderop << " ";
0163             for (int i : (*it).integers) {
0164                 dd << i << " ";
0165             }
0166             dd << (*it).str;
0167             qCDebug(KGRAPHVIEWERLIB_LOG) << msg;
0168 #endif
0169 
0170             if ((*it).renderop == "e" || (*it).renderop == "E") {
0171                 //         qCDebug(KGRAPHVIEWERLIB_LOG) << "integers[0]=" << (*it).integers[0] << ";
0172                 qreal w = m_scaleX * (*it).integers[2] * 2;
0173                 qreal h = m_scaleY * (*it).integers[3] * 2;
0174                 qreal x = m_xMargin + (((*it).integers[0]) * m_scaleX) - w / 2;
0175                 qreal y = ((m_gh - (*it).integers[1]) * m_scaleY) + m_yMargin - h / 2;
0176                 m_boundingRect = QRectF(x - adjust, y - adjust, w + adjust, h + adjust);
0177                 //         qCDebug(KGRAPHVIEWERLIB_LOG) << "'" << element()->id() << "' set rect for ellipse to " << rect;
0178             } else if ((*it).renderop == "p" || (*it).renderop == "P") {
0179                 QPolygonF polygon((*it).integers[0]);
0180                 for (int i = 0; i < (*it).integers[0]; i++) {
0181                     qreal x, y;
0182                     x = (*it).integers[2 * i + 1];
0183                     y = (*it).integers[2 * i + 2];
0184                     {
0185                     }
0186                     QPointF p(x * m_scaleX + m_xMargin, (m_gh - y) * m_scaleY + m_yMargin);
0187                     polygon[i] = p;
0188                 }
0189                 m_boundingRect = polygon.boundingRect();
0190                 //         qCDebug(KGRAPHVIEWERLIB_LOG) << "'" << element()->id() << "' set rect for polygon to " << rect;
0191             }
0192         }
0193     }
0194     setPos(0, 0);
0195 }
0196 
0197 /// TODO: optimize more!
0198 void CanvasElement::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
0199 {
0200     if (m_lastRenderOpRev != element()->renderOperationsRevision()) {
0201         m_fontSizeCache.clear();
0202     }
0203 
0204     Q_UNUSED(option)
0205     Q_UNUSED(widget)
0206     /// computes the scaling of line width
0207     qreal widthScaleFactor = (m_scaleX + m_scaleY) / 2;
0208     if (widthScaleFactor < 1) {
0209         widthScaleFactor = 1;
0210     }
0211 
0212 #if RENDER_DEBUG
0213     QString msg;
0214     QTextStream dd(&msg);
0215     for (const DotRenderOp &op : element()->renderOperations()) {
0216         dd << element()->id() << " an op: " << op.renderop << " ";
0217         for (int i : op.integers) {
0218             dd << i << " ";
0219         }
0220         dd << op.str << Qt::endl;
0221     }
0222     qCDebug(KGRAPHVIEWERLIB_LOG) << msg;
0223 #endif
0224 
0225     if (element()->renderOperations().isEmpty() && m_view->isReadWrite()) {
0226         qCWarning(KGRAPHVIEWERLIB_LOG) << element()->id() << ": no render operation. This should not happen.";
0227         return;
0228     }
0229 
0230     QListIterator<DotRenderOp> it(element()->renderOperations());
0231     //   it.toBack();
0232 
0233     QColor lineColor = Dot2QtConsts::componentData().qtColor(element()->lineColor());
0234     QColor backColor = Dot2QtConsts::componentData().qtColor(element()->backColor());
0235     if (m_hovered && m_view->highlighting()) {
0236         backColor = backColor.lighter();
0237     }
0238 
0239     const QPen oldPen = p->pen();
0240     const QBrush oldBrush = p->brush();
0241     const QFont oldFont = p->font();
0242 
0243     while (it.hasNext()) {
0244         const DotRenderOp &dro = it.next();
0245         if (dro.renderop == "c") {
0246             QColor c(dro.str.mid(0, 7));
0247             bool ok;
0248             c.setAlpha(255 - dro.str.mid(8).toInt(&ok, 16));
0249             lineColor = c;
0250             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "c" << dro.str.mid(0,7) << lineColor;
0251         } else if (dro.renderop == "C") {
0252             QColor c(dro.str.mid(0, 7));
0253             bool ok;
0254             c.setAlpha(255 - dro.str.mid(8).toInt(&ok, 16));
0255             if (m_hovered && m_view->highlighting()) {
0256                 c = c.lighter();
0257             }
0258             backColor = c;
0259             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "C" << dro.str.mid(0,7) << backColor;
0260         } else if (dro.renderop == "e" || dro.renderop == "E") {
0261             QPen pen = oldPen;
0262             qreal w = m_scaleX * dro.integers[2] * 2;
0263             qreal h = m_scaleY * dro.integers[3] * 2;
0264             qreal x = m_xMargin + (dro.integers[0] * m_scaleX) - w / 2;
0265             qreal y = ((m_gh - dro.integers[1]) * m_scaleY) + m_yMargin - h / 2;
0266             QRectF rect(x, y, w, h);
0267             pen.setColor(lineColor);
0268             if (element()->attributes().contains("penwidth")) {
0269                 bool ok;
0270                 int lineWidth = element()->attributes()["penwidth"].toInt(&ok);
0271                 pen.setWidth(int(lineWidth * widthScaleFactor));
0272             }
0273 
0274             p->setBrush(backColor);
0275             p->setPen(pen);
0276 
0277             //       qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << "drawEllipse" << lineColor << backColor << rect;
0278             //       rect = QRectF(0,0,100,100);
0279             p->drawEllipse(rect);
0280         } else if (dro.renderop == "p" || dro.renderop == "P") {
0281             //       std::cerr << "Drawing polygon for node '"<<element()->id()<<"': ";
0282             QPolygonF points(dro.integers[0]);
0283             for (int i = 0; i < dro.integers[0]; i++) {
0284                 qreal x, y;
0285                 x = dro.integers[2 * i + 1];
0286                 y = dro.integers[2 * i + 2];
0287                 QPointF p((x * m_scaleX) + m_xMargin, ((m_gh - y) * m_scaleY) + m_yMargin);
0288                 /*        qCDebug(KGRAPHVIEWERLIB_LOG) << "    point: (" << dro.integers[2*i+1] << ","
0289                                   << dro.integers[2*i+2] << ") " */
0290                 points[i] = p;
0291             }
0292 
0293             QPen pen = oldPen;
0294             pen.setColor(lineColor);
0295             if (element()->style() == "bold") {
0296                 pen.setStyle(Qt::SolidLine);
0297                 pen.setWidth(2);
0298             }
0299             if (element()->attributes().contains("penwidth")) {
0300                 bool ok;
0301                 int lineWidth = element()->attributes()["penwidth"].toInt(&ok);
0302                 pen.setWidth(int(lineWidth * widthScaleFactor));
0303             } else if (element()->style() != "filled") {
0304                 pen.setStyle(Dot2QtConsts::componentData().qtPenStyle(element()->style()));
0305             }
0306             if (element()->style().left(12) == "setlinewidth") {
0307                 bool ok;
0308                 uint lineWidth = element()->style().mid(12, element()->style().length() - 1 - 12).toInt(&ok);
0309                 pen.setWidth(lineWidth);
0310             }
0311             p->setPen(pen);
0312             p->setBrush(backColor);
0313             /*      if (element()->style() == "filled")
0314                   {
0315                     p->setBrush(Dot2QtConsts::componentData().qtColor(element()->backColor()));
0316                 //     QCanvasPolygon::paint(p);
0317                   }
0318                   else
0319                   {
0320                     p->setBrush(canvas()->backgroundColor());
0321                   }*/
0322             //       qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << "drawPolygon" << points;
0323             p->drawPolygon(points);
0324             if (!element()->shapeFile().isEmpty()) {
0325                 QPixmap pix(element()->shapeFile());
0326                 if (!pix.isNull()) {
0327                     p->drawPixmap(int(points.boundingRect().left()), int(points.boundingRect().top()), pix);
0328                 }
0329             }
0330         }
0331     }
0332 
0333     p->setBrush(oldBrush);
0334     p->setPen(oldPen);
0335 
0336     it.toFront();
0337     while (it.hasNext()) {
0338         const DotRenderOp &dro = it.next();
0339         if (dro.renderop == "c") {
0340             QColor c(dro.str.mid(0, 7));
0341             bool ok;
0342             c.setAlpha(255 - dro.str.mid(8).toInt(&ok, 16));
0343             lineColor = c;
0344             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "c" << dro.str.mid(0,7) << lineColor;
0345         } else if (dro.renderop == "C") {
0346             QColor c(dro.str.mid(0, 7));
0347             bool ok;
0348             c.setAlpha(255 - dro.str.mid(8).toInt(&ok, 16));
0349             if (m_hovered && m_view->highlighting()) {
0350                 c = c.lighter();
0351             }
0352             backColor = c;
0353             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "C" << dro.str.mid(0,7) << backColor;
0354         } else if (dro.renderop == "L") {
0355             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Label";
0356             QPolygonF points(dro.integers[0]);
0357             for (int i = 0; i < dro.integers[0]; i++) {
0358                 qreal x, y;
0359                 x = dro.integers[2 * i + 1];
0360                 y = dro.integers[2 * i + 2];
0361                 QPointF p((x * m_scaleX) + m_xMargin, ((m_gh - y) * m_scaleY) + m_yMargin);
0362                 points[i] = p;
0363             }
0364             QPen pen(lineColor);
0365             if (element()->style() == "bold") {
0366                 pen.setStyle(Qt::SolidLine);
0367                 pen.setWidth(2);
0368             } else if (element()->style() != "filled") {
0369                 pen.setStyle(Dot2QtConsts::componentData().qtPenStyle(element()->style()));
0370             }
0371             p->setPen(pen);
0372             //       qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << "drawPolyline" << points;
0373             p->drawPolyline(points);
0374         }
0375     }
0376     p->setPen(oldPen);
0377 
0378     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Drawing" << element()->id() << "labels";
0379     QString color = lineColor.name();
0380     it.toFront();
0381     uint num_T = 0;
0382     while (it.hasNext()) {
0383         const DotRenderOp &dro = it.next();
0384         if (dro.renderop == "c" || dro.renderop == "C") {
0385             color = dro.str.mid(0, 7);
0386             //       qCDebug(KGRAPHVIEWERLIB_LOG) << dro.renderop << color;
0387         } else if (dro.renderop == "F") {
0388             element()->setFontName(dro.str);
0389             element()->setFontSize(dro.integers[0]);
0390             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "F" << element()->fontName() << element()->fontColor() << element()->fontSize();
0391         } else if (dro.renderop == "T") {
0392             ++num_T;
0393             // we suppose here that the color has been set just before
0394             element()->setFontColor(color);
0395             // draw a label
0396             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Drawing a label " << dro.integers[0]
0397             //       << " " << dro.integers[1] << " " << dro.integers[2]
0398             //       << " " << dro.integers[3] << " " << dro.str
0399             //         << " (" << element()->fontName() << ", " << element()->fontSize()
0400             //         << ", " << element()->fontColor() << ")";
0401 
0402             int fontWidth = 0;
0403             bool cacheValid = false;
0404             //       qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << " initial fontSize " << fontSize;
0405             if (m_lastRenderOpRev == element()->renderOperationsRevision()) {
0406                 FontSizeCache::iterator cacheIt = m_fontSizeCache.find(num_T);
0407                 if (cacheIt != m_fontSizeCache.end()) {
0408                     m_font->setPointSize(cacheIt->first);
0409                     fontWidth = cacheIt->second;
0410                     cacheValid = true;
0411                 }
0412             }
0413             if (!cacheValid) {
0414                 int stringWidthGoal = int(dro.integers[3] * m_scaleX);
0415                 int fontSize = element()->fontSize();
0416                 m_font->setPointSize(fontSize);
0417 
0418                 QFontMetrics fm(*m_font);
0419                 fontWidth = fm.horizontalAdvance(dro.str);
0420                 while (fontWidth > stringWidthGoal && fontSize > 1) {
0421                     // use floor'ed extrapolated font size
0422                     fontSize = double(stringWidthGoal) / fontWidth * fontSize;
0423                     m_font->setPointSize(fontSize);
0424                     fm = QFontMetrics(*m_font);
0425                     fontWidth = fm.horizontalAdvance(dro.str);
0426                 }
0427                 m_fontSizeCache[num_T] = qMakePair(fontSize, fontWidth);
0428             }
0429 
0430             p->setFont(*m_font);
0431             QPen pen(m_pen);
0432             pen.setColor(element()->fontColor());
0433             p->setPen(pen);
0434             qreal x = (m_scaleX * ((dro.integers[0]) + (((-dro.integers[2]) * (fontWidth)) / 2) - ((fontWidth) / 2))) + m_xMargin;
0435             qreal y = ((m_gh - (dro.integers[1])) * m_scaleY) + m_yMargin;
0436             QPointF point(x, y);
0437             //       qCDebug(KGRAPHVIEWERLIB_LOG) << element()->id() << "drawText" << point << " " << fontSize;
0438             p->drawText(point, dro.str);
0439         }
0440     }
0441 
0442     if (element()->isSelected()) {
0443         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "element is selected: draw selection marks";
0444         p->setBrush(Qt::black);
0445         p->setPen(Qt::black);
0446         p->drawRect(QRectF(m_boundingRect.topLeft(), QSizeF(6, 6)));
0447         p->drawRect(QRectF(m_boundingRect.topRight() - QPointF(6, 0), QSizeF(6, 6)));
0448         p->drawRect(QRectF(m_boundingRect.bottomLeft() - QPointF(0, 6), QSizeF(6, 6)));
0449         p->drawRect(QRectF(m_boundingRect.bottomRight() - QPointF(6, 6), QSizeF(6, 6)));
0450     }
0451 
0452     p->setPen(oldPen);
0453     p->setBrush(oldBrush);
0454     p->setFont(oldFont);
0455 
0456     m_lastRenderOpRev = element()->renderOperationsRevision();
0457 }
0458 
0459 void CanvasElement::mousePressEvent(QGraphicsSceneMouseEvent *event)
0460 {
0461     qCDebug(KGRAPHVIEWERLIB_LOG) << m_element->id() << boundingRect();
0462     if (m_view->isReadOnly()) {
0463         return;
0464     }
0465     if (m_view->editingMode() == DotGraphView::AddNewEdge) {
0466         m_view->createNewEdgeDraftFrom(this);
0467         return;
0468     } else if (m_view->editingMode() == DotGraphView::DrawNewEdge) {
0469         m_view->finishNewEdgeTo(this);
0470         return;
0471     }
0472     if (event->button() == Qt::LeftButton) {
0473         m_element->setSelected(!m_element->isSelected());
0474         if (m_element->isSelected()) {
0475             emit(selected(this, event->modifiers()));
0476         }
0477         update();
0478     } else if (event->button() == Qt::RightButton) {
0479         // opens the selected edge contextual menu and if necessary select the edge
0480         if (!m_element->isSelected()) {
0481             m_element->setSelected(true);
0482             emit(selected(this, event->modifiers()));
0483             update();
0484         }
0485 
0486         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "opens the contextual menu";
0487         //     m_popup->exec(event->screenPos());
0488         emit(elementContextMenuEvent(m_element->id(), event->screenPos()));
0489     }
0490 }
0491 
0492 void CanvasElement::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0493 {
0494     Q_UNUSED(event)
0495     //   qCDebug(KGRAPHVIEWERLIB_LOG) ;
0496 }
0497 
0498 void CanvasElement::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0499 {
0500     Q_UNUSED(event)
0501     //   qCDebug(KGRAPHVIEWERLIB_LOG) ;
0502 }
0503 
0504 void CanvasElement::slotRemoveElement()
0505 {
0506     m_view->removeSelectedElements();
0507 }
0508 
0509 void CanvasElement::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
0510 {
0511     Q_UNUSED(event)
0512     //   qCDebug(KGRAPHVIEWERLIB_LOG);
0513     m_hovered = true;
0514     update();
0515     emit hoverEnter(this);
0516 }
0517 
0518 void CanvasElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
0519 {
0520     Q_UNUSED(event)
0521     //   qCDebug(KGRAPHVIEWERLIB_LOG);
0522     m_hovered = false;
0523     update();
0524     emit hoverLeave(this);
0525 }
0526 
0527 }
0528 
0529 #include "moc_canvaselement.cpp"