diff --git a/resources/images/toolPalette/aristoTool.png b/resources/images/toolPalette/aristoTool.png new file mode 100644 index 00000000..225c0b1e Binary files /dev/null and b/resources/images/toolPalette/aristoTool.png differ diff --git a/resources/sankore.qrc b/resources/sankore.qrc index d9263dbd..94ef9a07 100644 --- a/resources/sankore.qrc +++ b/resources/sankore.qrc @@ -166,6 +166,7 @@ images/toolPalette/triangleTool.png images/toolPalette/protractorTool.png images/toolPalette/compassTool.png + images/toolPalette/aristoTool.png images/toolPalette/maskTool.png images/toolPalette/magnifierTool.png images/extraPalette/blackout.png diff --git a/src/board/UBBoardController.cpp b/src/board/UBBoardController.cpp index 9ccd5bba..cb2a1a3e 100644 --- a/src/board/UBBoardController.cpp +++ b/src/board/UBBoardController.cpp @@ -1276,6 +1276,11 @@ UBItem *UBBoardController::downloadFinished(bool pSuccess, QUrl sourceUrl, QStri mActiveScene->addMask(pPos); UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); } + else if (sourceUrl.toString() == UBToolsManager::manager()->aristo.id) + { + mActiveScene->addAristo(pPos); + UBDrawingController::drawingController()->setStylusTool(UBStylusTool::Selector); + } else { showMessage(tr("Unknown tool type %1").arg(sourceUrl.toString())); diff --git a/src/core/UB.h b/src/core/UB.h index afc0f91e..c47c9c9b 100644 --- a/src/core/UB.h +++ b/src/core/UB.h @@ -145,6 +145,7 @@ struct UBGraphicsItemType TriangleItemType, MagnifierItemType, cacheItemType, + AristoItemType, groupContainerType, ToolWidgetItemType }; diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index 19a7e851..27abf659 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -39,6 +39,7 @@ #include "tools/UBGraphicsTriangle.h" #include "tools/UBGraphicsCurtainItem.h" #include "tools/UBGraphicsCache.h" +#include "tools/UBGraphicsAristo.h" #include "document/UBDocumentProxy.h" @@ -2071,6 +2072,22 @@ void UBGraphicsScene::addCompass(QPointF center) setModified(true); } +void UBGraphicsScene::addAristo(QPointF center) +{ + UBGraphicsAristo* aristo = new UBGraphicsAristo(); + mTools << aristo; + + aristo->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Tool)); + + addItem(aristo); + + QPointF itemSceneCenter = aristo->sceneBoundingRect().center(); + aristo->moveBy(center.x() - itemSceneCenter.x(), center.y() - itemSceneCenter.y()); + + aristo->setVisible(true); + setModified(true); +} + void UBGraphicsScene::addCache() { UBGraphicsCache* cache = new UBGraphicsCache(); diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index 027ef706..eae7db84 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -220,6 +220,7 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem void addCompass(QPointF center); void addTriangle(QPointF center); void addMagnifier(UBMagnifierParams params); + void addAristo(QPointF center); void addMask(const QPointF ¢er = QPointF()); void addCache(); diff --git a/src/tools/UBGraphicsAristo.cpp b/src/tools/UBGraphicsAristo.cpp new file mode 100644 index 00000000..0cdeb69f --- /dev/null +++ b/src/tools/UBGraphicsAristo.cpp @@ -0,0 +1,757 @@ +/* + * This program 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#include +#include + +#include "tools/UBGraphicsAristo.h" +#include "core/UBApplication.h" +#include "board/UBBoardController.h" +#include "board/UBDrawingController.h" +#include "domain/UBGraphicsScene.h" + +#include "core/memcheck.h" + +const QRect UBGraphicsAristo::sDefaultRect = QRect(0, 0, 800, 400); +const UBGraphicsAristo::UBGraphicsAristoOrientation UBGraphicsAristo::sDefaultOrientation = UBGraphicsAristo::Bottom; + +UBGraphicsAristo::UBGraphicsAristo() + : UBAbstractDrawRuler() + , QGraphicsPolygonItem() + , angle(0) + , mResizing(false) + , mRotating(false) + , mMarking(false) + , mSpan(180) + , mStartAngle(0) + , mCurrentAngle(0) + + +{ + setRect(sDefaultRect, sDefaultOrientation); + + create(*this); + + mHFlipSvgItem = new QGraphicsSvgItem(":/images/vflipTool.svg", this); + mHFlipSvgItem->setVisible(false); + mHFlipSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); + + mResizeSvgItem = new QGraphicsSvgItem(":/images/resizeTool.svg", this); + mResizeSvgItem->setVisible(false); + mResizeSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); + + mRotateSvgItem = new QGraphicsSvgItem(":/images/rotateTool.svg", this); + mRotateSvgItem->setVisible(false); + mRotateSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); + + mMarkerSvgItem = new QGraphicsSvgItem(":/images/angleMarker.svg", this); + mMarkerSvgItem->setVisible(false); + mMarkerSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Tool)); +} + +UBGraphicsAristo::~UBGraphicsAristo() +{ +} + +UBItem* UBGraphicsAristo::deepCopy(void) const +{ + UBGraphicsAristo* copy = new UBGraphicsAristo(); + copyItemParameters(copy); + return copy; +} + +void UBGraphicsAristo::copyItemParameters(UBItem *copy) const +{ + UBGraphicsAristo* cp = dynamic_cast(copy); + if (cp) + { + /* TODO: copy all members */ + cp->setPos(this->pos()); + cp->setPolygon(this->polygon()); + cp->setTransform(this->transform()); + } +} + +void UBGraphicsAristo::setRect(qreal x, qreal y, qreal w, qreal h, UBGraphicsAristoOrientation orientation) +{ + QPolygonF polygon; + polygon << QPointF(x, y) << QPoint(x, y + h) << QPoint(x+w, y + h); + setPolygon(polygon); + + setOrientation(orientation); +} + +void UBGraphicsAristo::setOrientation(UBGraphicsAristoOrientation orientation) +{ + mOrientation = orientation; + calculatePoints(rect()); + + QPolygonF polygon; + polygon << A << B << C; + setPolygon(polygon); +} + +UBGraphicsScene* UBGraphicsAristo::scene() const +{ + return static_cast(QGraphicsPolygonItem::scene()); +} + +/* calculatePoints() is used to calculate polygon's apexes coordinates. + * This function handles orientation changes too. + */ +void UBGraphicsAristo::calculatePoints(const QRectF& r) +{ + switch(mOrientation) + { + case Bottom: + A.setX(r.left()); A.setY(r.top()); + B.setX(r.right()); B.setY(r.top()); + C.setX(r.center().x()); C.setY(A.y() + r.width() / 2); + break; + case Top: + A.setX(r.left()); A.setY(r.bottom()); + B.setX(r.right()); B.setY(r.bottom()); + C.setX(r.center().x()); C.setY(A.y() - r.width() / 2); + break; + } +} + +void UBGraphicsAristo::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + QPolygonF polygon; + + painter->setBrush(Qt::NoBrush); + painter->setPen(drawColor()); + + polygon << A << B << C; + painter->drawPolygon(polygon); + polygon.clear(); + + paintGraduations(painter); + + mCloseSvgItem->setPos(closeButtonRect().topLeft() + rotationCenter()); + mHFlipSvgItem->setPos(hFlipRect().topLeft() + rotationCenter()); + mRotateSvgItem->setPos(rotateRect().topLeft() + rotationCenter()); + mResizeSvgItem->setPos(resizeButtonRect().topLeft() + rotationCenter()); + + + paintMarker(painter); + mMarkerSvgItem->setVisible(true); +} + +QPainterPath UBGraphicsAristo::shape() const +{ + QPainterPath tShape; + QPolygonF tPolygon; + + tPolygon << A << B << C; + tShape.addPolygon(tPolygon); + tPolygon.clear(); + + return tShape; +} + +/* paintMarker() adjust marker button according to the current angle, draw the line allowing user to set precisely the angle, and draw the current angle's value. */ +void UBGraphicsAristo::paintMarker(QPainter *painter) +{ + /* adjusting marker button */ + mMarkerSvgItem->setPos(markerButtonRect().topLeft() + rotationCenter()); + mMarkerSvgItem->resetTransform(); + mMarkerSvgItem->translate(-markerButtonRect().left(), -markerButtonRect().top()); + mMarkerSvgItem->rotate(mCurrentAngle); + mMarkerSvgItem->translate(markerButtonRect().left(), markerButtonRect().top()); + + + qreal co = cos((mCurrentAngle) * PI/180); + qreal si = sin((mCurrentAngle) * PI/180); + + /* Setting point composing the line (from point C) which intersects the line we want to draw. */ + QPointF referencePoint; + if (mOrientation == Bottom) { + if ((int)mCurrentAngle % 360 < 90) + referencePoint = B; + else + referencePoint = A; + } + else if (mOrientation == Top) { + if ((int)mCurrentAngle % 360 < 270 && (int)mCurrentAngle % 360 > 0) + referencePoint = A; + else + referencePoint = B; + } + + /* getting intersection point to draw the wanted line */ + QLineF intersectedLine(rotationCenter(), QPointF(rotationCenter().x()+co, rotationCenter().y()+si)); + QPointF intersectionPoint; + if (intersectedLine.intersect(QLineF(referencePoint, C), &intersectionPoint)) + painter->drawLine(QLineF(intersectionPoint, rotationCenter())); + + /* drawing angle value */ + qreal rightAngle = mOrientation == Bottom ? mCurrentAngle : 360 - mCurrentAngle; + + + QString angleText = QString("%1°").arg(rightAngle, 0, 'f', 1); + + QFont font1 = painter->font(); +#ifdef Q_WS_MAC + font1.setPointSizeF(font1.pointSizeF() - 3); +#endif + QFontMetricsF fm1(font1); + + if (mOrientation == Bottom) + painter->drawText(rotationCenter().x() - fm1.width(angleText)/2 - radius()/8, rotationCenter().y() + radius()/8 - fm1.height()/2, fm1.width(angleText), fm1.height(), Qt::AlignCenter, angleText); + else + painter->drawText(rotationCenter().x() - fm1.width(angleText)/2 - radius()/8, rotationCenter().y() - radius()/8 - fm1.height()/2, fm1.width(angleText), fm1.height(), Qt::AlignCenter, angleText); + + +} + +/* paintGraduations() paints graduations on the ruler side (length graduations) and the two other sides (angle graduation) */ +void UBGraphicsAristo::paintGraduations(QPainter *painter) +{ + paintRulerGraduations(painter); + paintProtractorGraduations(painter); +} + +void UBGraphicsAristo::paintRulerGraduations(QPainter *painter) +{ + /* defining useful constants */ + const int centimeterGraduationHeight = 15; + const int halfCentimeterGraduationHeight = 10; + const int millimeterGraduationHeight = 5; + const int millimetersPerCentimeter = 10; + const int millimetersPerHalfCentimeter = 5; + + painter->save(); + painter->setFont(font()); + QFontMetricsF fontMetrics(painter->font()); + + /* Browsing milliters in half width of ruler side */ + for (int millimeters = 0; millimeters < (rect().width() / 2 - sLeftEdgeMargin - sRoundingRadius) / sPixelsPerMillimeter; millimeters++) + { + /* defining graduationHeight ; values are different to draw bigger lines if millimiter considered is a centimeter or a half centimeter */ + int graduationHeight = (0 == millimeters % millimetersPerCentimeter) ? + centimeterGraduationHeight : + ((0 == millimeters % millimetersPerHalfCentimeter) ? + halfCentimeterGraduationHeight : millimeterGraduationHeight); + + /* correcting graduationHeight: draw the line in the other direction in case ruler is top-oriented, to stay inside the tool and inside the rect */ + graduationHeight = mOrientation == Bottom ? graduationHeight : - graduationHeight; + + /* drawing graduation to the left and to the right of origin, which is the center of graduated side */ + painter->drawLine(QLine(rotationCenter().x() + sPixelsPerMillimeter * millimeters, rotationCenter().y(), rotationCenter().x() + sPixelsPerMillimeter * millimeters, rotationCenter().y() + graduationHeight)); + if (millimeters != 0) + painter->drawLine(QLine(rotationCenter().x() - sPixelsPerMillimeter * millimeters, rotationCenter().y(), rotationCenter().x() - sPixelsPerMillimeter * millimeters, rotationCenter().y() + graduationHeight)); + + /* drawing associated value if considered graduation is a centimeter */ + if (0 == millimeters % millimetersPerCentimeter) + { + /* defining graduation value */ + QString text = QString("%1").arg((int)(millimeters / millimetersPerCentimeter)); + + /* staying inside polygon */ + if (rotationCenter().x() + sPixelsPerMillimeter * millimeters + fontMetrics.width(text) / 2 < rect().right()) + { + qreal textWidth = fontMetrics.width(text); + qreal textHeight = fontMetrics.tightBoundingRect(text).height() + 5; + + /* text y-coordinate is different according to tool's orientation */ + qreal textY = mOrientation == Bottom ? rect().top() + 5 + centimeterGraduationHeight : rect().bottom() - 5 - centimeterGraduationHeight + graduationHeight; + + /* if text's rect is not out of polygon's bounds, drawing value below or above graduation */ + QPointF intersectionPoint; + + bool paint = false; + + if (mOrientation == Bottom && QLineF(QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters - textWidth / 2, rotationCenter().y()), QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters - textWidth / 2, textY + textHeight)).intersect(QLineF(A, C), &intersectionPoint) != QLineF::BoundedIntersection && QLineF(QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters + textWidth / 2, rotationCenter().y()), QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters + textWidth / 2, textY + textHeight)).intersect(QLineF(A, C), &intersectionPoint) != QLineF::BoundedIntersection) { + paint = true; + } + else if (mOrientation == Top && QLineF(QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters - textWidth / 2, rotationCenter().y()), QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters - textWidth / 2, textY - textHeight)).intersect(QLineF(A, C), &intersectionPoint) != QLineF::BoundedIntersection && QLineF(QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters + textWidth / 2, rotationCenter().y()), QPointF(rotationCenter().x() - sPixelsPerMillimeter * millimeters + textWidth / 2, textY - textHeight)).intersect(QLineF(A, C), &intersectionPoint) != QLineF::BoundedIntersection) { + paint = true; + } + + if (paint) { + painter->drawText( + QRectF(rotationCenter().x() + sPixelsPerMillimeter * millimeters - textWidth / 2, textY, textWidth, textHeight), + Qt::AlignVCenter, text); + if (millimeters != 0) + painter->drawText( + QRectF(rotationCenter().x() - sPixelsPerMillimeter * millimeters - textWidth / 2, textY, textWidth, textHeight), + Qt::AlignVCenter, text); + } + } + } + } + painter->restore(); +} + +void UBGraphicsAristo::paintProtractorGraduations(QPainter* painter) +{ + /* defining useful constants */ + const int tenDegreeGraduationLength = 15; + const int fiveDegreeGraduationLength = 10; + const int oneDegreeGraduationLength = 5; + + painter->save(); + + QFont font1 = painter->font(); +#ifdef Q_WS_MAC + font1.setPointSizeF(font1.pointSizeF() - 3); +#endif + QFontMetricsF fm1(font1); + + //Font for internal arc + QFont font2 = painter->font(); + font2.setPointSizeF(font1.pointSizeF()/1.5); + QFontMetricsF fm2(font2); + + /* defining virtual arc diameter */ + qreal rad = radius(); + + QPointF center = rotationCenter(); + + /* browsing angles */ + for (int angle = 1; angle < mSpan; angle++) + { + int graduationLength = (0 == angle % 10) ? tenDegreeGraduationLength : ((0 == angle % 5) ? fiveDegreeGraduationLength : oneDegreeGraduationLength); + + qreal co = cos(((qreal)angle + mStartAngle) * PI/180); + qreal si = sin(((qreal)angle + mStartAngle) * PI/180); + + /* inverse sinus according to the orientation, to draw graduations on the polygon */ + si = mOrientation == Bottom ? -si : si; + + /* drawing the graduation around the virtual arc */ + if (angle >= sArcAngleMargin && angle <= mSpan - sArcAngleMargin) + painter->drawLine(QLineF(QPointF(center.x()+ rad/2*co, center.y() - rad/2*si), + QPointF(center.x()+ (rad/2 + graduationLength)*co, + center.y() - (rad/2 + graduationLength)*si))); + + + QPointF intersectionPoint; + QLineF referenceLine; + if (angle < 90) + referenceLine.setP1(B); + else + referenceLine.setP1(A); + referenceLine.setP2(C); + + /* if angle is 10-multiple, drawing it's value, rotated to be easily red */ + if (0 == angle % 10) { + QString grad = QString("%1").arg((int)(angle)); + QString grad2 = QString("%1").arg((int)mSpan - angle); + + painter->setFont(font2); + + painter->save(); + painter->translate(center.x() + (rad/2 + graduationLength*1.5)*co, center.y() - (rad/2 + graduationLength*1.5)*si); + int degrees = mOrientation == Bottom ? angle : -angle; + painter->rotate(-90 + degrees); + painter->drawText(- fm2.width(grad)/2, - fm2.height()/2, fm2.width(grad), fm2.height(), Qt::AlignCenter, grad); + painter->restore(); + + painter->setFont(font1); + + + /* drawing the graduation near tool's side */ + if (QLineF(QPointF(center.x()+ rad/2*co, center.y() - rad/2*si), + QPointF(center.x()+ (rad/2 + graduationLength)*co, + center.y() - (rad/2 + graduationLength)*si)).intersect(referenceLine, &intersectionPoint) == QLineF::UnboundedIntersection) + + painter->drawLine(QLineF(QPointF(center.x() + (rad/2 + graduationLength*1.5 + fm2.width(grad)/2)*co, + center.y() - (rad/2 + graduationLength*1.5 + fm2.height()/2)*si), + intersectionPoint)); + + } + + /* drawing the graduation near tool's side */ + else + if (QLineF(QPointF(center.x()+ rad/2*co, center.y() - rad/2*si), + QPointF(center.x()+ (rad/2 + graduationLength)*co, + center.y() - (rad/2 + graduationLength)*si)).intersect(referenceLine, &intersectionPoint) == QLineF::UnboundedIntersection) + + painter->drawLine(QLineF(QPointF(intersectionPoint.x() - (graduationLength*1.5)*co, + intersectionPoint.y() + (graduationLength*1.5)*si), + intersectionPoint)); + } + + painter->restore(); +} + + +void UBGraphicsAristo::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 UBGraphicsAristo::rotateAroundCenter(QTransform& transform, QPointF center) +{ + transform.translate(center.x(), center.y()); + transform.rotate(angle); + transform.translate(- center.x(), - center.y()); +} + +void UBGraphicsAristo::resize(qreal factor) +{ + prepareGeometryChange(); + translate(rotationCenter().x(), rotationCenter().y()); + scale(factor, factor); + translate(-rotationCenter().x(), -rotationCenter().y()); +} + + +QPointF UBGraphicsAristo::rotationCenter() const +{ + return QPointF((A.x() + B.x()) / 2, (A.y() + B.y()) / 2); +} + +QRectF UBGraphicsAristo::closeButtonRect() const +{ + qreal y = radius() / 4 + hFlipRect().height() + 3 + rotateRect().height() + 3; + if (mOrientation == Top) + y = -y; + return QRectF(- mCloseSvgItem->boundingRect().width() / 2, y, mCloseSvgItem->boundingRect().width(), mCloseSvgItem->boundingRect().height()); +} + +QRectF UBGraphicsAristo::resizeButtonRect() const +{ + return QRectF((B - rotationCenter()).x() - 100 - mResizeSvgItem->boundingRect().width()/2, - mResizeSvgItem->boundingRect().height()/2, mResizeSvgItem->boundingRect().width(), mResizeSvgItem->boundingRect().height()); +} + +QRectF UBGraphicsAristo::hFlipRect() const +{ + qreal y = radius() / 4; + if (mOrientation == Top) + y = -y; + + return QRectF(- mHFlipSvgItem->boundingRect().width() / 2, y, mHFlipSvgItem->boundingRect().width(), mHFlipSvgItem->boundingRect().height()); +} + +QRectF UBGraphicsAristo::rotateRect() const +{ + qreal y = radius() / 4 + hFlipRect().height() + 3; + if (mOrientation == Top) + y = -y; + return QRectF(- mRotateSvgItem->boundingRect().width() / 2, y, mRotateSvgItem->boundingRect().width(), mRotateSvgItem->boundingRect().height()); + +} + +QRectF UBGraphicsAristo::markerButtonRect() const +{ + return QRectF (radius()/2 - mMarkerSvgItem->boundingRect().width(), - mMarkerSvgItem->boundingRect().height()/2, mMarkerSvgItem->boundingRect().width(), mMarkerSvgItem->boundingRect().height()); +} + +QCursor UBGraphicsAristo::flipCursor() const +{ + return Qt::ArrowCursor; +} + +QCursor UBGraphicsAristo::resizeCursor() const +{ + return Qt::ArrowCursor; +} + +QCursor UBGraphicsAristo::markerCursor() const +{ + return Qt::ArrowCursor; +} + +void UBGraphicsAristo::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + switch (toolFromPos(event->pos())) { + case Rotate: + mRotating = true; + event->accept(); + break; + case Resize: + mResizing = true; + event->accept(); + break; + case MoveMarker: + mMarking = true; + event->accept(); + break; + default: + QGraphicsItem::mousePressEvent(event); + break; + } + + mShowButtons = false; + mHFlipSvgItem->setVisible(false); + mCloseSvgItem->setVisible(false); + mRotateSvgItem->setVisible(mRotating); + mResizeSvgItem->setVisible(mResizing); + update(); +} + +void UBGraphicsAristo::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + + if (!mResizing && !mRotating && !mMarking) + { + QGraphicsItem::mouseMoveEvent(event); + } + else + { + QLineF currentLine(rotationCenter(), event->pos()); + QLineF lastLine(rotationCenter(), event->lastPos()); + + if (mRotating) { + + rotateAroundCenter(currentLine.angleTo(lastLine)); + } + else if (mResizing) { + QPointF delta = event->pos() - event->lastPos(); + setRect(QRectF(rect().topLeft(), QSizeF(rect().width() + delta.x(), rect().height() + delta.x() / 2)), mOrientation); + } + else if(mMarking) { + qreal angle = currentLine.angleTo(lastLine); + + mCurrentAngle += angle; + mCurrentAngle -= (int)(mCurrentAngle/360)*360; + + if (mOrientation == Bottom) { + if (mCurrentAngle >= 270) + mCurrentAngle = 0; + else if (mCurrentAngle > 180) + mCurrentAngle = 180; + } + else if (mOrientation == Top) { + if (mCurrentAngle < 90) + mCurrentAngle = 360; + else if (mCurrentAngle < 180) + mCurrentAngle = 180; + } + update(); + } + + event->accept(); + } +} + +void UBGraphicsAristo::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (mResizing || mRotating || mMarking) + { + mResizing = false; + mRotating = false; + mMarking = false; + event->accept(); + } + else + { + switch (toolFromPos(event->pos())) { + case Close : + hide(); + emit hidden(); + break; + case HorizontalFlip: + /* substracting difference to zero [2pi] twice, to obtain the desired angle */ + mCurrentAngle -= 2 * (mCurrentAngle - (int)(mCurrentAngle/360)*360) - 360; + /* setting new orientation */ + switch(mOrientation) { + case Bottom: + setOrientation(Top); + break; + case Top: + setOrientation(Bottom); + break; + } + default: + QGraphicsItem::mouseReleaseEvent(event); + break; + } + } + + mShowButtons = true; + update(); + if (scene()) + scene()->setModified(true); +} + +void UBGraphicsAristo::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool (); + + if (currentTool == UBStylusTool::Selector) { + mShowButtons = true; + mHFlipSvgItem->setVisible(true); + mRotateSvgItem->setVisible(true); + mResizeSvgItem->setVisible(true); + mCloseSvgItem->setVisible(true); + + switch (toolFromPos(event->pos())) { + case HorizontalFlip: + setCursor(flipCursor()); + break; + case Rotate: + setCursor(rotateCursor()); + break; + case Resize: + setCursor(resizeCursor()); + break; + case MoveMarker: + setCursor(markerCursor()); + break; + case Close: + setCursor(closeCursor()); + break; + default: + setCursor(moveCursor()); + break; + } + + event->accept(); + update(); + + } else if (UBDrawingController::drawingController()->isDrawingTool()) { + setCursor(drawRulerLineCursor()); + UBDrawingController::drawingController()->mActiveRuler = this; + event->accept(); + } +} + +void UBGraphicsAristo::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + mShowButtons = false; + setCursor(Qt::ArrowCursor); + mHFlipSvgItem->setVisible(false); + mRotateSvgItem->setVisible(false); + mResizeSvgItem->setVisible(false); + mCloseSvgItem->setVisible(false); + UBDrawingController::drawingController()->mActiveRuler = NULL; + event->accept(); + update(); +} + +void UBGraphicsAristo::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool (); + + if (currentTool == UBStylusTool::Selector) + { + mShowButtons = true; + mHFlipSvgItem->setVisible(true); + mRotateSvgItem->setVisible(true); + mResizeSvgItem->setVisible(true); + mCloseSvgItem->setVisible(true); + + switch (toolFromPos(event->pos())) { + case HorizontalFlip: + setCursor(flipCursor()); + break; + case Rotate: + setCursor(rotateCursor()); + break; + case Resize: + setCursor(resizeCursor()); + break; + case MoveMarker: + setCursor(markerCursor()); + break; + case Close: + setCursor(closeCursor()); + break; + default: + setCursor(moveCursor()); + break; + } + + event->accept(); + } + else if (UBDrawingController::drawingController()->isDrawingTool()) + event->accept(); +} + +/* + * toolfrompos() returns the item type corresponding to the given position. + * This method is used to reduce the amount of code in each event function and improve class' maintainability. + * pos: event's position ; a rotation is done to counter elements rotation, like the marker button. + */ +UBGraphicsAristo::Tool UBGraphicsAristo::toolFromPos(QPointF pos) +{ + pos = pos - rotationCenter(); + + qreal rotationAngle = mOrientation == Bottom ? - mCurrentAngle : 360 * (int)(mCurrentAngle / 360 + 1) - mCurrentAngle; + + QTransform t; + t.rotate(rotationAngle); + QPointF p2 = t.map(pos); + + if (resizeButtonRect().contains(pos)) + return Resize; + else if (closeButtonRect().contains(pos)) + return Close; + else if (rotateRect().contains(pos)) + return Rotate; + else if (markerButtonRect().contains(p2)) + return MoveMarker; + else if (hFlipRect().contains(pos)) + return HorizontalFlip; + else if (shape().contains(pos)) + return Move; + else + return None; +} + +void UBGraphicsAristo::StartLine(const QPointF &scenePos, qreal width) +{ + QPointF itemPos = mapFromScene(scenePos); + + qreal y; + + y = rotationCenter().y(); + + 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, width, true); +} + +void UBGraphicsAristo::DrawLine(const QPointF &scenePos, qreal width) +{ + QPointF itemPos = mapFromScene(scenePos); + + qreal y; + + y = rotationCenter().y(); + + 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, width, + UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Marker); +} + +void UBGraphicsAristo::EndLine() +{ +} diff --git a/src/tools/UBGraphicsAristo.h b/src/tools/UBGraphicsAristo.h new file mode 100644 index 00000000..ee791d74 --- /dev/null +++ b/src/tools/UBGraphicsAristo.h @@ -0,0 +1,165 @@ +/* + * This program 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#ifndef UBGRAPHICSARISTO_H_ +#define UBGRAPHICSARISTO_H_ + +#include +#include +#include + +#include "core/UB.h" +#include "domain/UBItem.h" +#include "tools/UBAbstractDrawRuler.h" + + +class UBGraphicsScene; +class UBItem; + +class UBGraphicsAristo : public UBAbstractDrawRuler, public QGraphicsPolygonItem, public UBItem +{ + Q_OBJECT + + public: + UBGraphicsAristo(); + virtual ~UBGraphicsAristo(); + + enum { Type = UBGraphicsItemType::AristoItemType }; + enum Tool {None, Move, Resize, Rotate, Close, MoveMarker, HorizontalFlip}; + + virtual int type() const + { + return Type; + } + + virtual UBItem* deepCopy(void) const; + virtual void copyItemParameters(UBItem *copy) const; + + virtual void StartLine(const QPointF& scenePos, qreal width); + virtual void DrawLine(const QPointF& position, qreal width); + virtual void EndLine(); + + enum UBGraphicsAristoOrientation + { + Bottom = 0, + Top + }; + + static UBGraphicsAristoOrientation orientationFromStr(QStringRef& str) + { + if (str == "Bottom") return Bottom; + if (str == "Top") return Top; + return sDefaultOrientation; + } + static QString orientationToStr(UBGraphicsAristoOrientation orientation) + { + QString result; + if (orientation == 0) result = "Bottom"; + else if (orientation == 1) result = "Top"; + + return result; + } + + void setRect(const QRectF &rect, UBGraphicsAristoOrientation orientation) + { + setRect(rect.x(), rect.y(), rect.width(), rect.height(), orientation); + } + + void setRect(qreal x, qreal y, qreal w, qreal h, UBGraphicsAristoOrientation orientation); + + void setOrientation(UBGraphicsAristoOrientation orientation); + + UBGraphicsAristoOrientation getOrientation() const {return mOrientation;} + + QRectF rect() const {return boundingRect();} + + UBGraphicsScene* scene() const; + + protected: + + virtual void paint (QPainter *painter, const QStyleOptionGraphicsItem *styleOption, QWidget *widget); + virtual QPainterPath shape() const; + + virtual void rotateAroundCenter(qreal angle); + virtual void resize(qreal factor); + + virtual QPointF rotationCenter() const; + + virtual QRectF closeButtonRect() const; + QRectF resizeButtonRect () const; + QRectF hFlipRect() const; + QRectF rotateRect() const; + QRectF markerButtonRect() const; + + QCursor flipCursor() const; + QCursor resizeCursor() const; + QCursor markerCursor() const; + + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + + private: + UBGraphicsAristo::Tool toolFromPos(QPointF pos); + QTransform calculateRotationTransform(); + qreal angle; + + void rotateAroundCenter(QTransform& transform, QPointF center); + + bool mResizing; + bool mRotating; + bool mMarking; + QRect lastRect; + qreal mSpan; + + // Coordinates are transformed.... + QPoint lastPos; + QGraphicsSvgItem* mHFlipSvgItem; + QGraphicsSvgItem* mRotateSvgItem; + QGraphicsSvgItem* mResizeSvgItem; + QGraphicsSvgItem* mMarkerSvgItem; + qreal mStartAngle; + qreal mCurrentAngle; + + static const QRect sDefaultRect; + static const UBGraphicsAristoOrientation sDefaultOrientation; + + void paintGraduations(QPainter *painter); + void paintRulerGraduations(QPainter *painter); + void paintProtractorGraduations(QPainter* painter); + void paintMarker(QPainter *painter); + inline qreal radius () const + { + return sqrt(((B.x() - A.x())*(B.x() - A.x()))+((B.y() - A.y())*(B.y() - A.y()))) * 9 / 16 - 20; + } + + + UBGraphicsAristoOrientation mOrientation; + + void calculatePoints(const QRectF& rect); + + QPointF A, B, C; + + static const int d = 70; // width of triangle border + static const int sArrowLength = 30; + static const int sMinWidth = 380; + static const int sMinHeight = 200; + static const int sArcAngleMargin = 5; +}; + +#endif /* UBGRAPHICSARISTO_H_ */ diff --git a/src/tools/UBToolsManager.cpp b/src/tools/UBToolsManager.cpp index 95b40eec..d30e4fa1 100644 --- a/src/tools/UBToolsManager.cpp +++ b/src/tools/UBToolsManager.cpp @@ -91,6 +91,12 @@ UBToolsManager::UBToolsManager(QObject *parent) mDescriptors << cache; // -------------------------------------------------------------------------------- + aristo.id = "uniboardTool://uniboard.mnemis.com/aristo"; + aristo.icon = QPixmap(":/images/toolPalette/aristoTool.png"); + aristo.label = tr("Aristo"); + aristo.version = "1.0"; + mToolsIcon.insert(aristo.id, ":/images/toolPalette/aristoTool.png"); + mDescriptors << aristo; } UBToolsManager::~UBToolsManager() diff --git a/src/tools/UBToolsManager.h b/src/tools/UBToolsManager.h index eee12d61..410b224f 100644 --- a/src/tools/UBToolsManager.h +++ b/src/tools/UBToolsManager.h @@ -76,6 +76,7 @@ class UBToolsManager : public QObject UBToolDescriptor triangle; UBToolDescriptor magnifier; UBToolDescriptor cache; + UBToolDescriptor aristo; QString iconFromToolId(QString id) { return mToolsIcon.value(id);} diff --git a/src/tools/tools.pri b/src/tools/tools.pri index 90e69659..0196f84d 100644 --- a/src/tools/tools.pri +++ b/src/tools/tools.pri @@ -1,20 +1,21 @@ - -HEADERS += src/tools/UBGraphicsRuler.h \ - src/tools/UBGraphicsTriangle.h \ +HEADERS += src/tools/UBGraphicsRuler.h \ + src/tools/UBGraphicsTriangle.h \ src/tools/UBGraphicsProtractor.h \ src/tools/UBGraphicsCompass.h \ + src/tools/UBGraphicsAristo.h \ src/tools/UBToolsManager.h \ src/tools/UBGraphicsCurtainItem.h \ src/tools/UBGraphicsCurtainItemDelegate.h \ src/tools/UBAbstractDrawRuler.h \ - src/tools/UBGraphicsCache.h - -SOURCES += src/tools/UBGraphicsRuler.cpp \ - src/tools/UBGraphicsTriangle.cpp \ + src/tools/UBGraphicsCache.h + +SOURCES += src/tools/UBGraphicsRuler.cpp \ + src/tools/UBGraphicsTriangle.cpp \ src/tools/UBGraphicsProtractor.cpp \ src/tools/UBGraphicsCompass.cpp \ + src/tools/UBGraphicsAristo.cpp \ src/tools/UBToolsManager.cpp \ src/tools/UBGraphicsCurtainItem.cpp \ src/tools/UBGraphicsCurtainItemDelegate.cpp \ src/tools/UBAbstractDrawRuler.cpp \ - src/tools/UBGraphicsCache.cpp + src/tools/UBGraphicsCache.cpp