commit
72958a79ca
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 7.7 KiB |
@ -0,0 +1,828 @@ |
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include "UBGraphicsAristo.h" |
||||
#include "board/UBBoardController.h" |
||||
#include "board/UBDrawingController.h" |
||||
#include "core/UBApplication.h" |
||||
#include "domain/UBGraphicsScene.h" |
||||
|
||||
#include <QColor> |
||||
#include <QFont> |
||||
#include <QFontMetricsF> |
||||
#include <QGraphicsItem> |
||||
#include <QLineF> |
||||
#include <QPolygonF> |
||||
#include <QRadialGradient> |
||||
#include <QString> |
||||
|
||||
#include "core/memcheck.h" |
||||
|
||||
const QRectF UBGraphicsAristo::sDefaultRect = QRectF(0, 0, 800, 500); |
||||
const UBGraphicsAristo::Orientation UBGraphicsAristo::sDefaultOrientation = UBGraphicsAristo::Bottom; |
||||
|
||||
UBGraphicsAristo::UBGraphicsAristo() |
||||
: UBAbstractDrawRuler() |
||||
, QGraphicsPathItem() |
||||
, mMarking(false) |
||||
, mResizing(false) |
||||
, mRotating(false) |
||||
, mOrientation(Undefined) |
||||
, mRotatedAngle(0) |
||||
, mMarkerAngle(0) |
||||
, mStartAngle(0) |
||||
, mSpan(180) |
||||
, mHFlipSvgItem(0) |
||||
, mMarkerSvgItem(0) |
||||
, mResizeSvgItem(0) |
||||
, mRotateSvgItem(0) |
||||
{ |
||||
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)); |
||||
mMarkerSvgItem->setVisible(true); |
||||
|
||||
create(*this); |
||||
setBoundingRect(sDefaultRect); |
||||
setOrientation(sDefaultOrientation); |
||||
} |
||||
|
||||
UBGraphicsAristo::~UBGraphicsAristo() |
||||
{ |
||||
/* NOOP */ |
||||
} |
||||
|
||||
/*
|
||||
* setOrientation() modify the tool orientation. |
||||
* makeGeometryChange() is called so points are recomputed, control items are positionnated and shape is determined according to this modification. |
||||
*/ |
||||
void UBGraphicsAristo::setOrientation(Orientation orientation) |
||||
{ |
||||
mOrientation = orientation; |
||||
makeGeometryChange(); |
||||
} |
||||
|
||||
/* calculatePoints() is used to calculate polygon's apexes coordinates.
|
||||
* This function handles orientation changes too. |
||||
*/ |
||||
void UBGraphicsAristo::calculatePoints() |
||||
{ |
||||
switch (mOrientation) { |
||||
case Bottom: |
||||
C.setX(boundingRect().center().x()); |
||||
C.setY(boundingRect().bottom()); |
||||
|
||||
A.setX(boundingRect().left()); |
||||
A.setY(boundingRect().bottom() - boundingRect().width() / 2); |
||||
|
||||
B.setX(boundingRect().right()); |
||||
B.setY(boundingRect().bottom() - boundingRect().width() / 2); |
||||
break; |
||||
case Top: |
||||
C.setX(boundingRect().center().x()); |
||||
C.setY(boundingRect().top()); |
||||
|
||||
A.setX(boundingRect().left()); |
||||
A.setY(boundingRect().top() + boundingRect().width() / 2); |
||||
|
||||
B.setX(boundingRect().right()); |
||||
B.setY(boundingRect().top() + boundingRect().width() / 2); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* setItemsPos() places control items according to A, B and C positions. |
||||
* Call this function after A, B or C position modification, mostly after calling calculatePoints(). |
||||
* These positions has to be set when calling setPath() to allow hover events on items which are not into the main polygon. |
||||
*/ |
||||
void UBGraphicsAristo::setItemsPos() |
||||
{ |
||||
mCloseSvgItem->setPos(closeButtonRect().topLeft() + rotationCenter()); |
||||
mHFlipSvgItem->setPos(hFlipRect().topLeft() + rotationCenter()); |
||||
mRotateSvgItem->setPos(rotateRect().topLeft() + rotationCenter()); |
||||
mResizeSvgItem->setPos(resizeButtonRect().topLeft() + rotationCenter());
|
||||
mMarkerSvgItem->setPos(markerButtonRect().topLeft() + rotationCenter()); |
||||
} |
||||
|
||||
/*
|
||||
* determinePath() modify the shape according to apexes coordinates and control item positions. |
||||
* This is useful when orientation is modified. |
||||
* Returns the painter path corresponding to object parameters. |
||||
*/ |
||||
QPainterPath UBGraphicsAristo::determinePath() |
||||
{ |
||||
QPainterPath path; |
||||
|
||||
QPolygonF polygon; |
||||
polygon << A << B << C; |
||||
path.addPolygon(polygon); |
||||
|
||||
path.addPath(mResizeSvgItem->shape().translated(mResizeSvgItem->pos())); |
||||
path.addPath(mMarkerSvgItem->shape().translated(mMarkerSvgItem->pos())); |
||||
|
||||
return path; |
||||
} |
||||
|
||||
/*
|
||||
* setBoundingRect() is a helper to set the given rectangle as the new shape to limit apexes coordinates. |
||||
* This is useful when instanciating or resizing the object. |
||||
* makeGeometryChange() is called so points are recomputed, control items are positionnated and shape is determined according to this modification.
|
||||
* Setting bounds' width less than 300 is not allowed. |
||||
*/ |
||||
void UBGraphicsAristo::setBoundingRect(QRectF boundingRect) |
||||
{ |
||||
if (boundingRect.width() < 300) |
||||
return; |
||||
|
||||
QPainterPath path; |
||||
path.addRect(boundingRect); |
||||
setPath(path); |
||||
if (mOrientation != Undefined) |
||||
makeGeometryChange(); |
||||
} |
||||
|
||||
void UBGraphicsAristo::makeGeometryChange() |
||||
{ |
||||
calculatePoints(); |
||||
setItemsPos(); |
||||
setPath(determinePath()); |
||||
} |
||||
|
||||
|
||||
UBItem* UBGraphicsAristo::deepCopy(void) const |
||||
{ |
||||
UBGraphicsAristo* copy = new UBGraphicsAristo(); |
||||
copyItemParameters(copy); |
||||
return copy; |
||||
} |
||||
|
||||
void UBGraphicsAristo::copyItemParameters(UBItem *copy) const |
||||
{ |
||||
UBGraphicsAristo* cp = dynamic_cast<UBGraphicsAristo*>(copy); |
||||
if (cp) |
||||
{
|
||||
/* TODO: copy all members */ |
||||
cp->setPos(this->pos()); |
||||
cp->setTransform(this->transform()); |
||||
cp->setBoundingRect(boundingRect()); |
||||
cp->setOrientation(mOrientation); |
||||
cp->mRotatedAngle = mRotatedAngle; |
||||
cp->mMarkerAngle = mMarkerAngle; |
||||
} |
||||
} |
||||
|
||||
|
||||
void UBGraphicsAristo::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) |
||||
{ |
||||
QPolygonF polygon; |
||||
|
||||
painter->setBrush(fillBrush()); |
||||
painter->setPen(drawColor()); |
||||
|
||||
polygon << A << B << C; |
||||
painter->drawPolygon(polygon); |
||||
polygon.clear(); |
||||
|
||||
paintGraduations(painter); |
||||
paintMarker(painter);
|
||||
} |
||||
|
||||
QBrush UBGraphicsAristo::fillBrush() const |
||||
{ |
||||
QColor fillColor = edgeFillColor();// scene()->isDarkBackground() ? sDarkBackgroundFillColor : sFillColor;
|
||||
QColor fillColorCenter = middleFillColor();//scene()->isDarkBackground() ? sDarkBackgroundFillColorCenter : sFillColorCenter;
|
||||
QColor transparentWhite = Qt::white; |
||||
transparentWhite.setAlpha(scene()->isDarkBackground() ? sDrawTransparency : sFillTransparency); |
||||
QRadialGradient radialGradient(boundingRect().center(), radius(), boundingRect().center()); |
||||
radialGradient.setColorAt(0, fillColorCenter); |
||||
radialGradient.setColorAt(1, fillColor); |
||||
return radialGradient; |
||||
} |
||||
|
||||
/* 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 < (boundingRect().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 < boundingRect().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 ? A.y() + 5 + centimeterGraduationHeight : A.y() - 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(); |
||||
} |
||||
|
||||
/* 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->resetTransform(); |
||||
mMarkerSvgItem->translate(-markerButtonRect().left(), -markerButtonRect().top()); |
||||
mMarkerSvgItem->rotate(mMarkerAngle); |
||||
mMarkerSvgItem->translate(markerButtonRect().left(), markerButtonRect().top()); |
||||
|
||||
|
||||
qreal co = cos((mMarkerAngle) * PI/180); |
||||
qreal si = sin((mMarkerAngle) * 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)mMarkerAngle % 360 < 90) |
||||
referencePoint = B; |
||||
else |
||||
referencePoint = A; |
||||
} |
||||
else if (mOrientation == Top) { |
||||
if ((int)mMarkerAngle % 360 < 270 && (int)mMarkerAngle % 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 ? mMarkerAngle : 360 - mMarkerAngle; |
||||
|
||||
|
||||
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); |
||||
} |
||||
|
||||
|
||||
void UBGraphicsAristo::rotateAroundCenter(qreal angle) |
||||
{ |
||||
qreal oldAngle = mRotatedAngle; |
||||
mRotatedAngle = angle; |
||||
QTransform transform; |
||||
rotateAroundCenter(transform, rotationCenter()); |
||||
setTransform(transform, true); |
||||
mRotatedAngle = 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(mRotatedAngle); |
||||
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::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::markerButtonRect() const |
||||
{ |
||||
return QRectF (radius()/2 - mMarkerSvgItem->boundingRect().width(), - mMarkerSvgItem->boundingRect().height()/2, mMarkerSvgItem->boundingRect().width(), mMarkerSvgItem->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::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()); |
||||
|
||||
} |
||||
|
||||
QCursor UBGraphicsAristo::flipCursor() const |
||||
{ |
||||
return Qt::ArrowCursor; |
||||
} |
||||
|
||||
QCursor UBGraphicsAristo::markerCursor() const |
||||
{ |
||||
return Qt::ArrowCursor; |
||||
} |
||||
|
||||
QCursor UBGraphicsAristo::resizeCursor() 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(); |
||||
setBoundingRect(QRectF(boundingRect().topLeft(), QSizeF(boundingRect().width() + delta.x(), boundingRect().height() + delta.x()))); |
||||
} |
||||
else if(mMarking) { |
||||
qreal angle = currentLine.angleTo(lastLine); |
||||
|
||||
mMarkerAngle += angle; |
||||
mMarkerAngle -= (int)(mMarkerAngle/360)*360; |
||||
|
||||
if (mOrientation == Bottom) { |
||||
if (mMarkerAngle >= 270) |
||||
mMarkerAngle = 0; |
||||
else if (mMarkerAngle > 180) |
||||
mMarkerAngle = 180; |
||||
} |
||||
else if (mOrientation == Top) { |
||||
if (mMarkerAngle < 90) |
||||
mMarkerAngle = 360; |
||||
else if (mMarkerAngle < 180) |
||||
mMarkerAngle = 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 */ |
||||
mMarkerAngle -= 2 * (mMarkerAngle - (int)(mMarkerAngle/360)*360) - 360; |
||||
/* setting new orientation */ |
||||
switch(mOrientation) { |
||||
case Bottom: |
||||
setOrientation(Top); |
||||
break; |
||||
case Top: |
||||
setOrientation(Bottom); |
||||
break; |
||||
default: |
||||
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 ? - mMarkerAngle : Top ? 360 * (int)(mMarkerAngle / 360 + 1) - mMarkerAngle : 0; |
||||
|
||||
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() < boundingRect().x() + sLeftEdgeMargin) |
||||
itemPos.setX(boundingRect().x() + sLeftEdgeMargin); |
||||
if (itemPos.x() > boundingRect().x() + boundingRect().width() - sLeftEdgeMargin) |
||||
itemPos.setX(boundingRect().x() + boundingRect().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() < boundingRect().x() + sLeftEdgeMargin) |
||||
itemPos.setX(boundingRect().x() + sLeftEdgeMargin); |
||||
if (itemPos.x() > boundingRect().x() + boundingRect().width() - sLeftEdgeMargin) |
||||
itemPos.setX(boundingRect().x() + boundingRect().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() |
||||
{ |
||||
/* NOOP */ |
||||
} |
||||
|
||||
|
||||
UBGraphicsScene* UBGraphicsAristo::scene() const |
||||
{ |
||||
return static_cast<UBGraphicsScene*>(QGraphicsPathItem::scene()); |
||||
} |
@ -0,0 +1,156 @@ |
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#ifndef UBGRAPHICSARISTO_H_ |
||||
#define UBGRAPHICSARISTO_H_ |
||||
|
||||
#include "core/UB.h" |
||||
#include "domain/UBItem.h" |
||||
#include "domain/UBGraphicsScene.h" |
||||
#include "tools/UBAbstractDrawRuler.h" |
||||
|
||||
#include <QtGlobal> |
||||
#include <QBrush> |
||||
#include <QCursor> |
||||
#include <QGraphicsPathItem> |
||||
#include <QGraphicsSceneHoverEvent> |
||||
#include <QGraphicsSceneMouseEvent> |
||||
#include <QGraphicsSvgItem> |
||||
#include <QObject> |
||||
#include <QPainter> |
||||
#include <QPainterPath> |
||||
#include <QPointF> |
||||
#include <QRectF> |
||||
#include <QStyleOptionGraphicsItem> |
||||
#include <QTransform> |
||||
#include <QWidget> |
||||
|
||||
class UBGraphicsAristo : public UBAbstractDrawRuler, public QGraphicsPathItem, public UBItem |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
UBGraphicsAristo(); |
||||
virtual ~UBGraphicsAristo(); |
||||
|
||||
enum { |
||||
Type = UBGraphicsItemType::AristoItemType
|
||||
}; |
||||
|
||||
enum Tool { |
||||
None, |
||||
Move, |
||||
Resize, |
||||
Rotate, |
||||
Close, |
||||
MoveMarker, |
||||
HorizontalFlip |
||||
}; |
||||
|
||||
enum Orientation |
||||
{ |
||||
Bottom = 0, |
||||
Top, |
||||
Undefined |
||||
}; |
||||
|
||||
void setOrientation(Orientation orientation); |
||||
void setBoundingRect(QRectF boundingRect);
|
||||
|
||||
virtual UBItem* deepCopy() 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(); |
||||
|
||||
virtual int type() const |
||||
{ |
||||
return Type; |
||||
} |
||||
UBGraphicsScene* scene() const; |
||||
|
||||
protected: |
||||
virtual void paint (QPainter *painter, const QStyleOptionGraphicsItem *styleOption, QWidget *widget); |
||||
|
||||
virtual void rotateAroundCenter(qreal angle); |
||||
virtual void resize(qreal factor); |
||||
|
||||
virtual QPointF rotationCenter() const; |
||||
|
||||
virtual QRectF closeButtonRect() const; |
||||
QRectF hFlipRect() const; |
||||
QRectF markerButtonRect() const; |
||||
QRectF resizeButtonRect () const;
|
||||
QRectF rotateRect() const; |
||||
|
||||
QCursor flipCursor() const;
|
||||
QCursor markerCursor() const; |
||||
QCursor resizeCursor() 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: |
||||
Tool toolFromPos(QPointF pos); |
||||
|
||||
QTransform calculateRotationTransform(); |
||||
void rotateAroundCenter(QTransform& transform, QPointF center); |
||||
|
||||
void calculatePoints(); |
||||
QPainterPath determinePath(); |
||||
void setItemsPos(); |
||||
void makeGeometryChange(); |
||||
|
||||
QBrush fillBrush() const; |
||||
void paintGraduations(QPainter *painter); |
||||
void paintMarker(QPainter *painter); |
||||
void paintProtractorGraduations(QPainter* painter); |
||||
void paintRulerGraduations(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; |
||||
}
|
||||
|
||||
bool mMarking; |
||||
bool mResizing; |
||||
bool mRotating; |
||||
|
||||
Orientation mOrientation; |
||||
|
||||
qreal mRotatedAngle; |
||||
qreal mMarkerAngle; |
||||
qreal mStartAngle; |
||||
|
||||
qreal mSpan; |
||||
|
||||
QGraphicsSvgItem* mHFlipSvgItem; |
||||
QGraphicsSvgItem* mMarkerSvgItem; |
||||
QGraphicsSvgItem* mResizeSvgItem; |
||||
QGraphicsSvgItem* mRotateSvgItem;
|
||||
|
||||
QPointF A, B, C; |
||||
|
||||
static const int sArcAngleMargin = 5; |
||||
static const Orientation sDefaultOrientation;
|
||||
static const QRectF sDefaultRect; |
||||
}; |
||||
|
||||
#endif /* UBGRAPHICSARISTO_H_ */ |
@ -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 |
||||
src/tools/UBGraphicsCache.h |
||||
|
||||
SOURCES += src/tools/UBGraphicsRuler.cpp \ |
||||
src/tools/UBGraphicsTriangle.cpp \ |
||||
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 |
||||
|
Loading…
Reference in new issue