/* * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM) * * Copyright (C) 2013 Open Education Foundation * * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour * l'Education Numérique en Afrique (GIP ENA) * * This file is part of OpenBoard. * * OpenBoard is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License, * with a specific linking exception for the OpenSSL project's * "OpenSSL" library (or with modified versions of it that use the * same license as the "OpenSSL" library). * * OpenBoard is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBoard. If not, see . */ #include #include #include "tools/UBGraphicsTriangle.h" #include "core/UBApplication.h" #include "board/UBBoardController.h" #include "board/UBDrawingController.h" #include "domain/UBGraphicsScene.h" #include "core/memcheck.h" const QRect UBGraphicsTriangle::sDefaultRect = QRect(0, 0, 800, 400); const UBGraphicsTriangle::UBGraphicsTriangleOrientation UBGraphicsTriangle::sDefaultOrientation = UBGraphicsTriangle::BottomLeft; UBGraphicsTriangle::UBGraphicsTriangle() : UBAbstractDrawRuler() , QGraphicsPolygonItem() , angle(0) , mResizing1(false) , mResizing2(false) , mRotating(false) , mShouldPaintInnerTriangle(true) { setRect(sDefaultRect, sDefaultOrientation); create(*this); mHFlipSvgItem = new QGraphicsSvgItem(":/images/hflipTool.svg", this); mHFlipSvgItem->setVisible(false); mHFlipSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); mVFlipSvgItem = new QGraphicsSvgItem(":/images/vflipTool.svg", this); mVFlipSvgItem->setVisible(false); mVFlipSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); mRotateSvgItem = new QGraphicsSvgItem(":/images/rotateTool.svg", this); mRotateSvgItem->setVisible(false); mRotateSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); setData(UBGraphicsItemData::itemLayerType, QVariant(itemLayerType::CppTool)); //Necessary to set if we want z value to be assigned correctly setFlag(QGraphicsItem::ItemIsSelectable, false); updateResizeCursor(); } void UBGraphicsTriangle::updateResizeCursor() { QPixmap pix(":/images/cursors/resize.png"); QTransform itemTransform = sceneTransform(); QRectF itemRect = boundingRect(); QPointF topLeft = itemTransform.map(itemRect.topLeft()); QPointF topRight = itemTransform.map(itemRect.topRight()); QPointF bottomLeft = itemTransform.map(itemRect.bottomLeft()); QLineF topLine(topLeft, topRight); QLineF leftLine(topLeft, bottomLeft); qreal angle = topLine.angle(); QTransform tr1; tr1.rotate(- angle); mResizeCursor1 = QCursor(pix.transformed(tr1, Qt::SmoothTransformation), pix.width() / 2, pix.height() / 2); angle = leftLine.angle(); QTransform tr2; tr2.rotate(- angle); mResizeCursor2 = QCursor(pix.transformed(tr2, Qt::SmoothTransformation), pix.width() / 2, pix.height() / 2); } UBGraphicsTriangle::~UBGraphicsTriangle() { } UBItem* UBGraphicsTriangle::deepCopy(void) const { UBGraphicsTriangle* copy = new UBGraphicsTriangle(); copyItemParameters(copy); // TODO UB 4.7 ... complete all members ? return copy; } void UBGraphicsTriangle::copyItemParameters(UBItem *copy) const { UBGraphicsTriangle* cp = dynamic_cast(copy); if (cp) { cp->setPos(this->pos()); cp->setPolygon(this->polygon()); cp->setTransform(this->transform()); } } void UBGraphicsTriangle::setRect(qreal x, qreal y, qreal w, qreal h, UBGraphicsTriangleOrientation orientation) { QPolygonF polygon; polygon << QPointF(x, y) << QPoint(x, y + h) << QPoint(x+w, y + h); setPolygon(polygon); // Save the bounds rect bounds_rect.setX(x); bounds_rect.setY(y); bounds_rect.setWidth(w); bounds_rect.setHeight(h); setOrientation(orientation); } void UBGraphicsTriangle::setOrientation(UBGraphicsTriangleOrientation orientation) { mOrientation = orientation; calculatePoints(bounds_rect); QPolygonF polygon; polygon << A1 << B1 << C1; setPolygon(polygon); } QRectF UBGraphicsTriangle::bounding_Rect() const { QRectF bounds = QRectF(0,0,0,0); bounds.setX(bounds_rect.x()); bounds.setY(bounds_rect.y()); bounds.setWidth(bounds_rect.width()); bounds.setHeight(bounds_rect.height()); return bounds; } UBGraphicsScene* UBGraphicsTriangle::scene() const { return static_cast(QGraphicsPolygonItem::scene()); } void UBGraphicsTriangle::calculatePoints(const QRectF& r) { switch(mOrientation) { case BottomLeft: A1.setX(r.left()); A1.setY(r.top()); B1.setX(r.left()); B1.setY(r.bottom()); C1.setX(r.right()); C1.setY(r.bottom()); break; case TopLeft: A1.setX(r.left()); A1.setY(r.bottom()); B1.setX(r.left()); B1.setY(r.top()); C1.setX(r.right()); C1.setY(r.top()); break; case TopRight: A1.setX(r.right()); A1.setY(r.bottom()); B1.setX(r.right()); B1.setY(r.top()); C1.setX(r.left()); C1.setY(r.top()); break; case BottomRight: A1.setX(r.right()); A1.setY(r.top()); B1.setX(r.right()); B1.setY(r.bottom()); C1.setX(r.left()); C1.setY(r.bottom()); break; } C = sqrt(rect().width() * rect().width() + rect().height() * rect().height()); qreal L = (C * d + rect().width() * d)/ rect().height(); qreal K = (C * d + rect().height() * d)/ rect().width(); switch(mOrientation) { case BottomLeft: A2.setX(r.left() + d); A2.setY(r.top() + K); B2.setX(r.left() + d); B2.setY(r.bottom() - d); C2.setX(r.right() - L); C2.setY(r.bottom() - d); break; case TopLeft: A2.setX(r.left() + d); A2.setY(r.bottom() - K); B2.setX(r.left() + d); B2.setY(r.top() + d); C2.setX(r.right() - L); C2.setY(r.top() + d); break; case TopRight: A2.setX(r.right() - d); A2.setY(r.bottom() - K); B2.setX(r.right() - d); B2.setY(r.top() + d); C2.setX(r.left() + L); C2.setY(r.top() + d); break; case BottomRight: A2.setX(r.right() - d); A2.setY(r.top() + K); B2.setX(r.right() - d); B2.setY(r.bottom() - d); C2.setX(r.left() + L); C2.setY(r.bottom() - d); break; } bool paintInnerTriangle = true; switch(mOrientation) { case BottomLeft: if (B2.x() > C2.x() || B2.y() < A2.y()) paintInnerTriangle = false; break; case TopLeft: if (B2.x() > C2.x() || B2.y() > A2.y()) paintInnerTriangle = false; break; case TopRight: if (B2.x() < C2.x() || B2.y() > A2.y()) paintInnerTriangle = false; break; case BottomRight: if (B2.x() < C2.x() || B2.y() < A2.y()) paintInnerTriangle = false; break; } mShouldPaintInnerTriangle = paintInnerTriangle; W1 = rect().height() * d / C; H1 = rect().width() * d / C; switch(mOrientation) { case BottomLeft: CC.setX(r.right() - L + W1); CC.setY(r.bottom() - d - H1); break; case TopLeft: CC.setX(r.right() - L + W1); CC.setY(r.top() + d + H1); break; case TopRight: CC.setX(r.left() + L - W1); CC.setY(r.top() + d + H1); break; case BottomRight: CC.setX(r.left() + L - W1); CC.setY(r.top() - d - H1); break; } } void UBGraphicsTriangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->setPen(Qt::NoPen); QPolygonF polygon; if (mShouldPaintInnerTriangle) { QLinearGradient gradient1(QPointF(A1.x(), 0), QPointF(A2.x(), 0)); gradient1.setColorAt(0, edgeFillColor()); gradient1.setColorAt(1, middleFillColor()); painter->setBrush(gradient1); polygon << A1 << A2 << B2 << B1; painter->drawPolygon(polygon); polygon.clear(); QLinearGradient gradient2(QPointF(0, B1.y()), QPointF(0, B2.y())); gradient2.setColorAt(0, edgeFillColor()); gradient2.setColorAt(1, middleFillColor()); painter->setBrush(gradient2); polygon << B1 << B2 << C2 << C1; painter->drawPolygon(polygon); polygon.clear(); QLinearGradient gradient3(CC, C2); gradient3.setColorAt(0, edgeFillColor()); gradient3.setColorAt(1, middleFillColor()); painter->setBrush(gradient3); polygon << C1 << C2 << A2 << A1; painter->drawPolygon(polygon); polygon.clear(); painter->setBrush(Qt::NoBrush); painter->setPen(drawColor()); polygon << A1 << B1 << C1; painter->drawPolygon(polygon); polygon.clear(); polygon << A2 << B2 << C2; painter->drawPolygon(polygon); } else { QLinearGradient gradient(QPointF(A1.x(), 0), QPointF(C1.x(), 0)); gradient.setColorAt(0, edgeFillColor()); gradient.setColorAt(1, middleFillColor()); painter->setBrush(gradient); painter->setPen(drawColor()); polygon << A1 << B1 << C1; painter->drawPolygon(polygon); polygon.clear(); } paintGraduations(painter); mAntiScaleRatio = 1 / (UBApplication::boardController->systemScaleFactor() * UBApplication::boardController->currentZoom()); QTransform antiScaleTransform; antiScaleTransform.scale(mAntiScaleRatio, mAntiScaleRatio); mCloseSvgItem->setTransform(antiScaleTransform); mHFlipSvgItem->setTransform(antiScaleTransform); mVFlipSvgItem->setTransform(antiScaleTransform); mRotateSvgItem->setTransform(antiScaleTransform); mCloseSvgItem->setPos(closeButtonRect().topLeft()); //qDebug() << "UBGraphicsTriangle Paint"<<"closeButtonRect().topLeft()=" //<setPos(hFlipRect().topLeft()); mVFlipSvgItem->setPos(vFlipRect().topLeft()); mRotateSvgItem->setPos(rotateRect().topLeft()); if (mShowButtons || mResizing1 || mResizing2) { painter->setBrush(QColor(0, 0, 0)); if (mShowButtons || mResizing1) painter->drawPolygon(resize1Polygon()); if (mShowButtons || mResizing2) painter->drawPolygon(resize2Polygon()); } } QPainterPath UBGraphicsTriangle::shape() const { QPainterPath tShape; QPolygonF tPolygon; //qDebug() << "UBGraphicsTriangle shape()"<<"A1 ="<activeScene()->backgroundGridSize(); double pixelsPerMillimeter = sPixelsPerCentimeter/10.0; // When a "centimeter" is too narrow, we only display every 5th number, and every 5th millimeter mark double numbersWidth = fontMetrics.width("00"); bool shouldDisplayAllNumbers = (numbersWidth <= (sPixelsPerCentimeter - 5)); for (int millimeters = 0; millimeters < (rect().width() - sLeftEdgeMargin - sRoundingRadius) / pixelsPerMillimeter; millimeters++) { double graduationX = rotationCenter().x() + kx * pixelsPerMillimeter * millimeters; double graduationHeight = 0; if (millimeters % UBGeometryUtils::millimetersPerCentimeter == 0) graduationHeight = UBGeometryUtils::centimeterGraduationHeight; else if (millimeters % UBGeometryUtils::millimetersPerHalfCentimeter == 0) graduationHeight = UBGeometryUtils::halfCentimeterGraduationHeight; else graduationHeight = UBGeometryUtils::millimeterGraduationHeight; qreal requiredSpace = graduationHeight + SEPARATOR ; /* B____C | / D|_/E <-- availableSpace Thalès |/ A */ qreal AD; switch(mOrientation) { case BottomLeft: AD = QLineF(rect().bottomRight(), QPointF(graduationX, rotationCenter().y())).length(); break; case TopLeft: AD = QLineF(rect().topRight(), QPointF(graduationX, rotationCenter().y())).length(); break; case TopRight: AD = QLineF(rect().topLeft(), QPointF(graduationX, rotationCenter().y())).length(); break; case BottomRight: AD = QLineF(rect().bottomLeft(), QPointF(graduationX , rotationCenter().y())).length(); break; } qreal AB = rect().width(); qreal BC = rect().height(); qreal DE = AD * BC / AB, availableSpace = DE; if (availableSpace < requiredSpace) break; if (shouldDisplayAllNumbers || millimeters % UBGeometryUtils::millimetersPerHalfCentimeter == 0) painter->drawLine(QLineF(graduationX, rotationCenter().y(), graduationX, rotationCenter().y() - ky * graduationHeight)); if ((shouldDisplayAllNumbers && millimeters % UBGeometryUtils::millimetersPerCentimeter == 0) || millimeters % (UBGeometryUtils::millimetersPerCentimeter*5) == 0) { QString text = QString("%1").arg((int)(millimeters / UBGeometryUtils::millimetersPerCentimeter)); qreal textWidth = fontMetrics.width(text); qreal textHeight = fontMetrics.tightBoundingRect(text).height(); requiredSpace = graduationHeight + textHeight + textWidth + SEPARATOR ; if (requiredSpace <= availableSpace) { int textY = (ky > 0) ? rotationCenter().y() - SEPARATOR - UBGeometryUtils::centimeterGraduationHeight - textHeight : rotationCenter().y() + SEPARATOR + UBGeometryUtils::centimeterGraduationHeight; painter->drawText(QRectF(graduationX - textWidth / 2, textY, textWidth, textHeight),Qt::AlignVCenter, text); } } } painter->restore(); } void UBGraphicsTriangle::rotateAroundCenter(qreal angle) { qreal oldAngle = this->angle; this->angle = angle; QTransform transform; rotateAroundCenter(transform, rotationCenter()); setTransform(transform, true); this->angle = oldAngle + angle; // We have to store absolute value for FLIP case } void UBGraphicsTriangle::rotateAroundCenter(QTransform& transform, QPointF center) { transform.translate(center.x(), center.y()); transform.rotate(angle); transform.translate(- center.x(), - center.y()); } QPointF UBGraphicsTriangle::rotationCenter() const { switch(mOrientation) { case BottomLeft: case TopLeft: return B1 + QPointF(sLeftEdgeMargin, 0); case TopRight: case BottomRight: return B1 - QPointF(sLeftEdgeMargin, 0); } return QPointF(0, 0); } QRectF UBGraphicsTriangle::closeButtonRect() const { switch(mOrientation) { case BottomLeft: return QRectF(B2.x() - mCloseSvgItem->boundingRect().width() - 5, B2.y() - mCloseSvgItem->boundingRect().height() - 5, mCloseSvgItem->boundingRect().width(), mCloseSvgItem->boundingRect().height()); case TopLeft: return QRectF(B2.x() - mCloseSvgItem->boundingRect().width() - 5, B2.y() + 5, mCloseSvgItem->boundingRect().width(), mCloseSvgItem->boundingRect().height()); case TopRight: return QRectF(B2.x() + 5, B2.y() + 5, mCloseSvgItem->boundingRect().width(), mCloseSvgItem->boundingRect().height()); case BottomRight: return QRectF(B2.x() + 5, B2.y() - mCloseSvgItem->boundingRect().height() - 5, mCloseSvgItem->boundingRect().width(), mCloseSvgItem->boundingRect().height()); } return QRectF(0,0,0,0); } QPolygonF UBGraphicsTriangle::resize1Polygon() const { qreal x1, y1; switch(mOrientation) { case BottomLeft: x1 = -1; y1 = -1; break; case TopLeft: x1 = -1; y1 = 1; break; case TopRight: x1 = 1; y1 = 1; break; case BottomRight: x1 = 1; y1 = -1; break; } QPointF P1(C1.x() + x1 * sArrowLength, C1.y()); QPointF P2(C1.x() + x1 * sArrowLength * rect().width()/C, C1.y() + y1 * sArrowLength * rect().height() / C); QPolygonF p; p << C1 << P1 << P2; return p; } QPolygonF UBGraphicsTriangle::resize2Polygon() const { qreal x1, y1; switch(mOrientation) { case BottomLeft: x1 = 1; y1 = 1; break; case TopLeft: x1 = 1; y1 = -1; break; case TopRight: x1 = -1; y1 = -1; break; case BottomRight: x1 = -1; y1 = 1; break; } QPointF P1(A1.x(), A1.y() + y1 * sArrowLength); QPointF P2(A1.x() + x1 * sArrowLength * rect().width()/C, A1.y() + y1 * sArrowLength * rect().height() / C); QPolygonF p; p << A1 << P1 << P2; return p; } QRectF UBGraphicsTriangle::hFlipRect() const { qreal dy = mVFlipSvgItem->boundingRect().height() + mCloseSvgItem->boundingRect().height() + 10; switch(mOrientation) { case BottomLeft: return QRectF(B2.x() - mHFlipSvgItem->boundingRect().width() - 5, B2.y() - mHFlipSvgItem->boundingRect().height() - 5 - dy, mHFlipSvgItem->boundingRect().width(), mHFlipSvgItem->boundingRect().height()); case TopLeft: return QRectF(B2.x() - mHFlipSvgItem->boundingRect().width() - 5, B2.y() + 5 + dy, mHFlipSvgItem->boundingRect().width(), mHFlipSvgItem->boundingRect().height()); case TopRight: return QRectF(B2.x() + 5, B2.y() + 5 + dy, mHFlipSvgItem->boundingRect().width(), mHFlipSvgItem->boundingRect().height()); case BottomRight: return QRectF(B2.x() + 5, B2.y() - mHFlipSvgItem->boundingRect().height() - 5 - dy, mHFlipSvgItem->boundingRect().width(), mHFlipSvgItem->boundingRect().height()); } return QRectF(0,0,0,0); } QRectF UBGraphicsTriangle::vFlipRect() const { qreal dy = mCloseSvgItem->boundingRect().height() + 5; switch(mOrientation) { case BottomLeft: return QRectF(B2.x() - mVFlipSvgItem->boundingRect().width() - 5, B2.y() - mVFlipSvgItem->boundingRect().height() - 5 - dy, mVFlipSvgItem->boundingRect().width(), mVFlipSvgItem->boundingRect().height()); case TopLeft: return QRectF(B2.x() - mVFlipSvgItem->boundingRect().width() - 5, B2.y() + 5 + dy, mVFlipSvgItem->boundingRect().width(), mVFlipSvgItem->boundingRect().height()); case TopRight: return QRectF(B2.x() + 5, B2.y() + 5 + dy, mVFlipSvgItem->boundingRect().width(), mVFlipSvgItem->boundingRect().height()); case BottomRight: return QRectF(B2.x() + 5, B2.y() - mVFlipSvgItem->boundingRect().height() - 5 - dy, mVFlipSvgItem->boundingRect().width(), mVFlipSvgItem->boundingRect().height()); } return QRectF(0,0,0,0); } QRectF UBGraphicsTriangle::rotateRect() const { QPointF p(C2); qreal buttonsX = vFlipRect().left(); switch(mOrientation) { case BottomLeft: p = QPointF(qMax(p.x() + 20, buttonsX), p.y() + 5); break; case TopLeft: p = QPointF(qMax(p.x() + 20, buttonsX), p.y() -5 - mRotateSvgItem->boundingRect().height()); break; case TopRight: p = QPointF(qMin(p.x() -20 - mRotateSvgItem->boundingRect().width(), buttonsX), p.y() - 5 - mRotateSvgItem->boundingRect().height()); break; case BottomRight: p = QPointF(qMin(p.x() -20 - mRotateSvgItem->boundingRect().width(), buttonsX), p.y() + 5); break; } return QRectF(p, QSizeF(mRotateSvgItem->boundingRect().size())); } QCursor UBGraphicsTriangle::resizeCursor1() const { return mResizeCursor1; } QCursor UBGraphicsTriangle::resizeCursor2() const { return mResizeCursor2; } QCursor UBGraphicsTriangle::flipCursor() const { return Qt::ArrowCursor; } void UBGraphicsTriangle::mousePressEvent(QGraphicsSceneMouseEvent *event) { lastRect = rect().toRect(); lastPos = sceneTransform().inverted().map(event->screenPos()); if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) { mResizing1 = true; event->accept(); } else if (resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) { mResizing2 = true; event->accept(); } else if(rotateRect().contains(event->pos())) { mRotating = true; event->accept(); } else { QGraphicsItem::mousePressEvent(event); } mShowButtons = false; mCloseSvgItem->setVisible(false); mHFlipSvgItem->setVisible(false); mVFlipSvgItem->setVisible(false); mRotateSvgItem->setVisible(mRotating); update(); } void UBGraphicsTriangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (!mResizing1 && !mResizing2 && !mRotating) { QGraphicsItem::mouseMoveEvent(event); } else { QPoint currPos = sceneTransform().inverted().map(event->screenPos()); if (mResizing1) { if (mOrientation == TopLeft || mOrientation == BottomLeft) { int deltaX = currPos.x() - lastPos.x(); if (lastRect.width() + deltaX < sMinWidth) deltaX = sMinWidth - lastRect.width(); setRect(QRectF(lastRect.left(), lastRect.top(), lastRect.width() + deltaX, lastRect.height()), mOrientation); } else { int deltaX = lastPos.x() - currPos.x(); if (lastRect.width() + deltaX < sMinWidth) deltaX = sMinWidth - lastRect.width(); setRect(QRectF(lastRect.left() - deltaX, lastRect.top(), lastRect.width() + deltaX, lastRect.height()), mOrientation); } } //-----------------------------------------------// if (mResizing2) { if (mOrientation == BottomRight || mOrientation == BottomLeft) { int deltaY = lastPos.y() - currPos.y(); if (lastRect.height() + deltaY < sMinHeight) deltaY = sMinHeight - lastRect.height(); setRect(QRectF(lastRect.left(), lastRect.top() - deltaY, lastRect.width(), lastRect.height() + deltaY), mOrientation); } else { int deltaY = currPos.y() - lastPos.y(); if (lastRect.height() + deltaY < sMinHeight) deltaY = sMinHeight - lastRect.height(); setRect(QRectF(lastRect.left(), lastRect.top(), lastRect.width(), lastRect.height() + deltaY), mOrientation); } } //-----------------------------------------------// if (mRotating) { QLineF currentLine(rotationCenter(), event->pos()); QLineF lastLine(rotationCenter(), event->lastPos()); rotateAroundCenter(currentLine.angleTo(lastLine)); } //-----------------------------------------------// event->accept(); } } void UBGraphicsTriangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (mResizing1 || mResizing2 || mRotating) { if (mRotating) updateResizeCursor(); mResizing1 = false; mResizing2 = false; mRotating = false; event->accept(); } else if (closeButtonRect().contains(event->pos())) { hide(); event->accept(); } else if (hFlipRect().contains(event->pos())) { switch(mOrientation) { case BottomLeft: setOrientation(BottomRight); break; case BottomRight: setOrientation(BottomLeft); break; case TopLeft: setOrientation(TopRight); break; case TopRight: setOrientation(TopLeft); break; } } else if (vFlipRect().contains(event->pos())) { switch(mOrientation) { case BottomLeft: setOrientation(TopLeft); break; case BottomRight: setOrientation(TopRight); break; case TopLeft: setOrientation(BottomLeft); break; case TopRight: setOrientation(BottomRight); break; } } else { QGraphicsItem::mouseReleaseEvent(event); } mShowButtons = true; update(); if (scene()) scene()->setModified(true); } void UBGraphicsTriangle::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool (); if (currentTool == UBStylusTool::Selector || currentTool == UBStylusTool::Play) { mCloseSvgItem->setParentItem(this); mShowButtons = true; mCloseSvgItem->setVisible(true); mHFlipSvgItem->setVisible(contains(hFlipRect())); mVFlipSvgItem->setVisible(contains(vFlipRect())); mRotateSvgItem->setVisible(contains(rotateRect())); if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) setCursor(resizeCursor1()); else if(resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) setCursor(resizeCursor2()); else if (closeButtonRect().contains(event->pos())) setCursor(closeCursor()); else if (hFlipRect().contains(event->pos()) || vFlipRect().contains(event->pos())) setCursor(flipCursor()); else if (rotateRect().contains(event->pos())) setCursor(rotateCursor()); else setCursor(moveCursor()); event->accept(); update(); } else if (UBDrawingController::drawingController()->isDrawingTool()) { setCursor(drawRulerLineCursor()); UBDrawingController::drawingController()->setActiveRuler(this); event->accept(); } // //event->accept(); //** //update(); //** } void UBGraphicsTriangle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { mResizing1 = mResizing2 = mRotating = false; mShowButtons = false; setCursor(Qt::ArrowCursor); mCloseSvgItem->setVisible(false); mVFlipSvgItem->setVisible(false); mHFlipSvgItem->setVisible(false); mRotateSvgItem->setVisible(false); UBDrawingController::drawingController()->setActiveRuler(nullptr); event->accept(); update(); } void UBGraphicsTriangle::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool (); if (currentTool == UBStylusTool::Selector || currentTool == UBStylusTool::Play) { mCloseSvgItem->setVisible(mShowButtons); mVFlipSvgItem->setVisible(mShowButtons && contains(vFlipRect())); mHFlipSvgItem->setVisible(mShowButtons && contains(hFlipRect())); mRotateSvgItem->setVisible(mShowButtons && contains(rotateRect())); if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) setCursor(resizeCursor1()); else if (resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill)) setCursor(resizeCursor2()); else if (closeButtonRect().contains(event->pos())) setCursor(closeCursor()); else if (hFlipRect().contains(event->pos()) || vFlipRect().contains(event->pos())) setCursor(flipCursor()); else if (rotateRect().contains(event->pos())) setCursor(rotateCursor()); else setCursor(moveCursor()); event->accept(); } else if (UBDrawingController::drawingController()->isDrawingTool()) { event->accept(); } } void UBGraphicsTriangle::StartLine(const QPointF &scenePos, qreal width) { Q_UNUSED(width); QPointF itemPos = mapFromScene(scenePos); mStrokeWidth = UBDrawingController::drawingController()->currentToolWidth(); qreal y; if (mOrientation == 0 || mOrientation == 1) { y = rect().y() + rect().height() + mStrokeWidth / 2; } else if (mOrientation == 2 || mOrientation == 3) { y = rect().y() - mStrokeWidth / 2; } if (itemPos.x() < rect().x() + sLeftEdgeMargin) itemPos.setX(rect().x() + sLeftEdgeMargin); if (itemPos.x() > rect().x() + rect().width() - sLeftEdgeMargin) itemPos.setX(rect().x() + rect().width() - sLeftEdgeMargin); itemPos.setY(y); itemPos = mapToScene(itemPos); scene()->moveTo(itemPos); scene()->drawLineTo(itemPos, mStrokeWidth, true); } void UBGraphicsTriangle::DrawLine(const QPointF &scenePos, qreal width) { Q_UNUSED(width); QPointF itemPos = mapFromScene(scenePos); qreal y; if (mOrientation == 0 || mOrientation == 1) { y = rect().y() + rect().height() + mStrokeWidth / 2; } else if (mOrientation == 2 || mOrientation == 3) { y = rect().y() - mStrokeWidth / 2; } if (itemPos.x() < rect().x() + sLeftEdgeMargin) itemPos.setX(rect().x() + sLeftEdgeMargin); if (itemPos.x() > rect().x() + rect().width() - sLeftEdgeMargin) itemPos.setX(rect().x() + rect().width() - sLeftEdgeMargin); itemPos.setY(y); itemPos = mapToScene(itemPos); // We have to use "pointed" line for marker tool scene()->drawLineTo(itemPos, mStrokeWidth, UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Marker); } /** * @brief Check whether a given QRectF is inside the triangle (A1, B1, C1). * * Returns true if any corner of the rectangle is within the triangle or, if strict is set to true, * if all corners of the rectangle are within the triangle. */ bool UBGraphicsTriangle::contains(const QRectF &rect, bool strict) { QPolygonF poly; poly << A1 << B1 << C1 << A1; QPainterPath path; path.addPolygon(poly); QList points; points << rect.bottomRight() << rect.topLeft() << rect.topRight(); bool inside = path.contains(rect.bottomLeft()); foreach(QPointF p, points) { if (strict) inside = inside && path.contains(p); else inside = inside || path.contains(p); } return inside; } void UBGraphicsTriangle::EndLine() { }