UBGraphicsTriangle.cpp 32.1 KB
Newer Older
Claudio Valerio's avatar
Claudio Valerio committed
1
/*
2
 * Copyright (C) 2015-2018 Département de l'Instruction Publique (DIP-SEM)
Craig Watson's avatar
Craig Watson committed
3
 *
Claudio Valerio's avatar
Claudio Valerio committed
4
 * Copyright (C) 2013 Open Education Foundation
Claudio Valerio's avatar
Claudio Valerio committed
5
 *
Claudio Valerio's avatar
Claudio Valerio committed
6 7
 * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
 * l'Education Numérique en Afrique (GIP ENA)
8
 *
Claudio Valerio's avatar
Claudio Valerio committed
9 10 11
 * This file is part of OpenBoard.
 *
 * OpenBoard is free software: you can redistribute it and/or modify
Claudio Valerio's avatar
Claudio Valerio committed
12 13
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License,
14 15 16 17
 * 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).
 *
Claudio Valerio's avatar
Claudio Valerio committed
18
 * OpenBoard is distributed in the hope that it will be useful,
Claudio Valerio's avatar
Claudio Valerio committed
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Claudio Valerio's avatar
Claudio Valerio committed
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Claudio Valerio's avatar
Claudio Valerio committed
21
 * GNU General Public License for more details.
Claudio Valerio's avatar
Claudio Valerio committed
22
 *
Claudio Valerio's avatar
Claudio Valerio committed
23
 * You should have received a copy of the GNU General Public License
Claudio Valerio's avatar
Claudio Valerio committed
24
 * along with OpenBoard. If not, see <http://www.gnu.org/licenses/>.
Claudio Valerio's avatar
Claudio Valerio committed
25
 */
26

27

Claudio Valerio's avatar
Claudio Valerio committed
28

Claudio Valerio's avatar
Claudio Valerio committed
29

30
#include <QPolygonF>
31
#include <QtWidgets/QGraphicsPolygonItem>
32

33
#include "tools/UBGraphicsTriangle.h"
34 35 36 37 38
#include "core/UBApplication.h"
#include "board/UBBoardController.h"
#include "board/UBDrawingController.h"
#include "domain/UBGraphicsScene.h"

39 40
#include "core/memcheck.h"

41
const QRect UBGraphicsTriangle::sDefaultRect =  QRect(0, 0, 800, 400);
Claudio Valerio's avatar
Claudio Valerio committed
42
const UBGraphicsTriangle::UBGraphicsTriangleOrientation UBGraphicsTriangle::sDefaultOrientation =
43 44
UBGraphicsTriangle::BottomLeft;

45
UBGraphicsTriangle::UBGraphicsTriangle()
Claudio Valerio's avatar
Claudio Valerio committed
46 47 48
    : UBAbstractDrawRuler()
    , QGraphicsPolygonItem()
    , angle(0)
49 50 51
    , mResizing1(false)
    , mResizing2(false)
    , mRotating(false)
Craig Watson's avatar
Craig Watson committed
52
    , mShouldPaintInnerTriangle(true)
unknown's avatar
unknown committed
53

54
{
55
    setRect(sDefaultRect, sDefaultOrientation);
56

57
    create(*this);
58

59
    mHFlipSvgItem = new QGraphicsSvgItem(":/images/hflipTool.svg", this);
unknown's avatar
unknown committed
60 61
    mHFlipSvgItem->setVisible(false);

shibakaneki's avatar
shibakaneki committed
62
    mHFlipSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control));
unknown's avatar
unknown committed
63

64
    mVFlipSvgItem = new QGraphicsSvgItem(":/images/vflipTool.svg", this);
unknown's avatar
unknown committed
65 66 67
    mVFlipSvgItem->setVisible(false);
    mVFlipSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control));

68
    mRotateSvgItem = new QGraphicsSvgItem(":/images/rotateTool.svg", this);
unknown's avatar
unknown committed
69 70 71
    mRotateSvgItem->setVisible(false);
    mRotateSvgItem->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control));

shibakaneki's avatar
shibakaneki committed
72
    setData(UBGraphicsItemData::itemLayerType, QVariant(itemLayerType::CppTool)); //Necessary to set if we want z value to be assigned correctly
Ivan Ilyin's avatar
Ivan Ilyin committed
73
    setFlag(QGraphicsItem::ItemIsSelectable, false);
shibakaneki's avatar
shibakaneki committed
74

75
    updateResizeCursor();
76 77
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

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);
}


104
UBGraphicsTriangle::~UBGraphicsTriangle()
105 106 107 108 109
{
}

UBItem* UBGraphicsTriangle::deepCopy(void) const
{
110
    UBGraphicsTriangle* copy = new UBGraphicsTriangle();
111

112
    copyItemParameters(copy);
113 114 115 116 117 118 119

    // TODO UB 4.7 ... complete all members ?

    return copy;

}

120 121 122 123
void UBGraphicsTriangle::copyItemParameters(UBItem *copy) const
{
    UBGraphicsTriangle* cp = dynamic_cast<UBGraphicsTriangle*>(copy);
    if (cp)
Claudio Valerio's avatar
Claudio Valerio committed
124
    {
125 126 127 128 129 130
        cp->setPos(this->pos());
        cp->setPolygon(this->polygon());
        cp->setTransform(this->transform());
    }
}

131 132
void UBGraphicsTriangle::setRect(qreal x, qreal y, qreal w, qreal h, UBGraphicsTriangleOrientation orientation)
{
133 134 135
    QPolygonF polygon;
    polygon << QPointF(x, y) << QPoint(x, y + h) << QPoint(x+w, y + h);
    setPolygon(polygon);
136

137 138 139
    //  Save the bounds rect
    bounds_rect.setX(x);  bounds_rect.setY(y);  bounds_rect.setWidth(w); bounds_rect.setHeight(h);

140
    setOrientation(orientation);
unknown's avatar
unknown committed
141
}
142

unknown's avatar
unknown committed
143 144
void UBGraphicsTriangle::setOrientation(UBGraphicsTriangleOrientation orientation)
{
145
    mOrientation = orientation;
146 147

    calculatePoints(bounds_rect);
148 149 150 151

    QPolygonF polygon;
    polygon << A1 << B1 << C1;
    setPolygon(polygon);
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167

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;
}

168 169
UBGraphicsScene* UBGraphicsTriangle::scene() const
{
170
    return static_cast<UBGraphicsScene*>(QGraphicsPolygonItem::scene());
171 172
}

173
void UBGraphicsTriangle::calculatePoints(const QRectF& r)
174
{
175

176 177
    switch(mOrientation)
    {
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

    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;
199
    }
200

201 202 203
    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();
204

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    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;
    }
Craig Watson's avatar
Craig Watson committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

    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;

251 252
    W1 = rect().height() * d / C;
    H1 = rect().width() * d / C;
253

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
    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;
    }
}
270

271 272
void UBGraphicsTriangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
273

274
    painter->setPen(Qt::NoPen);
275

276
    QPolygonF polygon;
277

Craig Watson's avatar
Craig Watson committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    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);
    }
314

Craig Watson's avatar
Craig Watson committed
315 316 317 318 319 320 321 322 323 324
    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();
    }
325 326


327
    paintGraduations(painter);
unknown's avatar
unknown committed
328

329
    mAntiScaleRatio = 1 / (UBApplication::boardController->systemScaleFactor() * UBApplication::boardController->currentZoom());
unknown's avatar
unknown committed
330 331 332 333
    QTransform antiScaleTransform;
    antiScaleTransform.scale(mAntiScaleRatio, mAntiScaleRatio);

    mCloseSvgItem->setTransform(antiScaleTransform);
334 335 336
    mHFlipSvgItem->setTransform(antiScaleTransform);
    mVFlipSvgItem->setTransform(antiScaleTransform);
    mRotateSvgItem->setTransform(antiScaleTransform);
unknown's avatar
unknown committed
337 338

    mCloseSvgItem->setPos(closeButtonRect().topLeft());
339

Craig Watson's avatar
Craig Watson committed
340 341
    //qDebug() << "UBGraphicsTriangle Paint"<<"closeButtonRect().topLeft()="
    //<<closeButtonRect().topLeft();
342

343 344 345 346 347 348 349 350 351 352 353 354
    mHFlipSvgItem->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());
    }
355 356


357 358
}

359 360 361 362 363
QPainterPath UBGraphicsTriangle::shape() const
{
    QPainterPath tShape;
    QPolygonF tPolygon;

Craig Watson's avatar
Craig Watson committed
364
    //qDebug() << "UBGraphicsTriangle shape()"<<"A1 ="<<A1<<"B1 ="<<B1<<"C1 ="<<C1;
365

366 367 368 369
    tPolygon << A1 << B1 << C1;
    tShape.addPolygon(tPolygon);
    tPolygon.clear();

Craig Watson's avatar
Craig Watson committed
370 371 372 373 374
    if (mShouldPaintInnerTriangle) {
        tPolygon << A2 << B2 << C2;
        tShape.addPolygon(tPolygon);
        tPolygon.clear();
    }
375

Craig Watson's avatar
Craig Watson committed
376 377
    //qDebug() << "UBGraphicsTriangle shape()"<<"A1 ="<<A1<<"B1 ="<<B1<<"C1 ="<<C1;
    //qDebug() << "UBGraphicsTriangle shape()"<<"A2 ="<<A2<<"B2 ="<<B2<<"C2 ="<<C2;
378

379 380 381
    return tShape;
}

382 383
void UBGraphicsTriangle::paintGraduations(QPainter *painter)
{
cfauconnier's avatar
cfauconnier committed
384
    const int SEPARATOR = 5;
385 386 387
    qreal kx = (mOrientation == TopLeft || mOrientation == BottomLeft) ? 1 : -1;
    qreal ky = (mOrientation == BottomLeft || mOrientation == BottomRight) ? 1 : -1;

388 389 390
    painter->save();
    painter->setFont(font());
    QFontMetricsF fontMetrics(painter->font());
cfauconnier's avatar
cfauconnier committed
391

392 393
    // Update the width of one "centimeter" to correspond to the width of the background grid (whether it is displayed or not)
    sPixelsPerCentimeter = UBApplication::boardController->activeScene()->backgroundGridSize();
394
    double pixelsPerMillimeter = sPixelsPerCentimeter/10.0;
395 396 397 398 399 400

    // 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++)
401
    {
402 403
        double graduationX = rotationCenter().x() + kx * pixelsPerMillimeter * millimeters;
        double graduationHeight = 0;
cfauconnier's avatar
cfauconnier committed
404

405 406 407 408 409 410 411 412
        if (millimeters % UBGeometryUtils::millimetersPerCentimeter == 0)
            graduationHeight = UBGeometryUtils::centimeterGraduationHeight;

        else if (millimeters % UBGeometryUtils::millimetersPerHalfCentimeter == 0)
            graduationHeight = UBGeometryUtils::halfCentimeterGraduationHeight;

        else
            graduationHeight = UBGeometryUtils::millimeterGraduationHeight;
413

cfauconnier's avatar
cfauconnier committed
414 415 416 417 418 419 420 421 422 423
        qreal requiredSpace = graduationHeight + SEPARATOR ;
        /*     B____C
                |  /
               D|_/E <-- availableSpace Thalès
                |/
                A
        */

        qreal AD;
        switch(mOrientation)
424
        {
cfauconnier's avatar
cfauconnier committed
425 426
            case BottomLeft:
                AD = QLineF(rect().bottomRight(), QPointF(graduationX, rotationCenter().y())).length();
427
                break;
cfauconnier's avatar
cfauconnier committed
428 429 430 431 432 433 434 435
            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();
436
                break;
437
        }
Claudio Valerio's avatar
Claudio Valerio committed
438

cfauconnier's avatar
cfauconnier committed
439 440 441 442
        qreal AB = rect().width();
        qreal BC = rect().height();
        qreal DE =  AD * BC / AB, availableSpace = DE;

443
        if (availableSpace < requiredSpace)
cfauconnier's avatar
cfauconnier committed
444 445
            break;

446 447 448 449 450
        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)
451
        {
452
            QString text = QString("%1").arg((int)(millimeters / UBGeometryUtils::millimetersPerCentimeter));
453
            qreal textWidth = fontMetrics.width(text);
cfauconnier's avatar
cfauconnier committed
454
            qreal textHeight = fontMetrics.tightBoundingRect(text).height();
455

cfauconnier's avatar
cfauconnier committed
456
            requiredSpace = graduationHeight + textHeight + textWidth + SEPARATOR ;
457

cfauconnier's avatar
cfauconnier committed
458
            if (requiredSpace <= availableSpace)
459
            {
cfauconnier's avatar
cfauconnier committed
460 461 462
                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);
463
            }
464 465 466 467 468 469
        }
    }
    painter->restore();
}


unknown's avatar
unknown committed
470
void UBGraphicsTriangle::rotateAroundCenter(qreal angle)
471
{
472
    qreal oldAngle = this->angle;
unknown's avatar
unknown committed
473
    this->angle = angle;
unknown's avatar
unknown committed
474
    QTransform transform;
475
    rotateAroundCenter(transform, rotationCenter());
unknown's avatar
unknown committed
476
    setTransform(transform, true);
477
    this->angle = oldAngle + angle; // We have to store absolute value for FLIP case
unknown's avatar
unknown committed
478 479
}

480
void UBGraphicsTriangle::rotateAroundCenter(QTransform& transform, QPointF center)
unknown's avatar
unknown committed
481
{
482
    transform.translate(center.x(), center.y());
unknown's avatar
unknown committed
483
    transform.rotate(angle);
484
    transform.translate(- center.x(), - center.y());
485 486
}

unknown's avatar
unknown committed
487

488
QPointF    UBGraphicsTriangle::rotationCenter() const
489
{
490 491 492 493 494 495 496 497 498 499
    switch(mOrientation)
    {
        case BottomLeft:
        case TopLeft:
            return B1 + QPointF(sLeftEdgeMargin, 0);
        case TopRight:
        case BottomRight:
            return B1 - QPointF(sLeftEdgeMargin, 0);
    }
    return QPointF(0, 0);
500 501
}

502
QRectF    UBGraphicsTriangle::closeButtonRect() const
503
{
504 505 506
    switch(mOrientation)
    {
        case BottomLeft:
Claudio Valerio's avatar
Claudio Valerio committed
507 508
            return QRectF(B2.x() - mCloseSvgItem->boundingRect().width() - 5,
              B2.y() - mCloseSvgItem->boundingRect().height() - 5,
509 510
              mCloseSvgItem->boundingRect().width(),
              mCloseSvgItem->boundingRect().height());
511
        case TopLeft:
Claudio Valerio's avatar
Claudio Valerio committed
512 513
            return QRectF(B2.x() - mCloseSvgItem->boundingRect().width() - 5,
              B2.y() + 5,
514 515
              mCloseSvgItem->boundingRect().width(),
              mCloseSvgItem->boundingRect().height());
516
        case TopRight:
Claudio Valerio's avatar
Claudio Valerio committed
517 518
            return QRectF(B2.x() + 5,
              B2.y() + 5,
519 520
              mCloseSvgItem->boundingRect().width(),
              mCloseSvgItem->boundingRect().height());
521
        case BottomRight:
Claudio Valerio's avatar
Claudio Valerio committed
522 523
            return QRectF(B2.x() + 5,
              B2.y() - mCloseSvgItem->boundingRect().height() - 5,
524 525
              mCloseSvgItem->boundingRect().width(),
              mCloseSvgItem->boundingRect().height());
526 527
    }
    return QRectF(0,0,0,0);
unknown's avatar
unknown committed
528 529 530 531
}

QPolygonF UBGraphicsTriangle::resize1Polygon() const
{
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    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);
554
    QPolygonF p;
Claudio Valerio's avatar
Claudio Valerio committed
555
    p << C1 << P1 << P2;
556
    return p;
unknown's avatar
unknown committed
557 558 559 560
}

QPolygonF UBGraphicsTriangle::resize2Polygon() const
{
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
    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);
Claudio Valerio's avatar
Claudio Valerio committed
582
    QPointF P2(A1.x() + x1 * sArrowLength * rect().width()/C,
583
        A1.y() + y1 * sArrowLength * rect().height() / C);
584
    QPolygonF p;
Claudio Valerio's avatar
Claudio Valerio committed
585
    p << A1 << P1 << P2;
586
    return p;
unknown's avatar
unknown committed
587 588
}

589
QRectF    UBGraphicsTriangle::hFlipRect() const
unknown's avatar
unknown committed
590
{
591 592 593 594
    qreal dy = mVFlipSvgItem->boundingRect().height() + mCloseSvgItem->boundingRect().height() + 10;
    switch(mOrientation)
    {
        case BottomLeft:
Claudio Valerio's avatar
Claudio Valerio committed
595 596
            return QRectF(B2.x() - mHFlipSvgItem->boundingRect().width() - 5,
              B2.y() - mHFlipSvgItem->boundingRect().height() - 5 - dy,
597
              mHFlipSvgItem->boundingRect().width(),
598
              mHFlipSvgItem->boundingRect().height());
599
        case TopLeft:
Claudio Valerio's avatar
Claudio Valerio committed
600 601
            return QRectF(B2.x() - mHFlipSvgItem->boundingRect().width() - 5,
              B2.y() + 5 + dy,
602 603
              mHFlipSvgItem->boundingRect().width(),
              mHFlipSvgItem->boundingRect().height());
604
        case TopRight:
Claudio Valerio's avatar
Claudio Valerio committed
605 606
            return QRectF(B2.x() + 5,
              B2.y() + 5 + dy,
607 608
              mHFlipSvgItem->boundingRect().width(),
              mHFlipSvgItem->boundingRect().height());
609
        case BottomRight:
Claudio Valerio's avatar
Claudio Valerio committed
610 611
            return QRectF(B2.x() + 5,
              B2.y() - mHFlipSvgItem->boundingRect().height() - 5 - dy,
612 613
              mHFlipSvgItem->boundingRect().width(),
              mHFlipSvgItem->boundingRect().height());
614 615
    }
    return QRectF(0,0,0,0);
unknown's avatar
unknown committed
616 617
}

618
QRectF    UBGraphicsTriangle::vFlipRect() const
unknown's avatar
unknown committed
619
{
620 621 622 623
    qreal dy = mCloseSvgItem->boundingRect().height() + 5;
    switch(mOrientation)
    {
        case BottomLeft:
Claudio Valerio's avatar
Claudio Valerio committed
624 625
            return QRectF(B2.x() - mVFlipSvgItem->boundingRect().width() - 5,
              B2.y() - mVFlipSvgItem->boundingRect().height() - 5 - dy,
626
              mVFlipSvgItem->boundingRect().width(),
627
              mVFlipSvgItem->boundingRect().height());
628
        case TopLeft:
Claudio Valerio's avatar
Claudio Valerio committed
629 630
            return QRectF(B2.x() - mVFlipSvgItem->boundingRect().width() - 5,
              B2.y() + 5 + dy,
631 632
              mVFlipSvgItem->boundingRect().width(),
              mVFlipSvgItem->boundingRect().height());
633
        case TopRight:
Claudio Valerio's avatar
Claudio Valerio committed
634 635
            return QRectF(B2.x() + 5,
              B2.y() + 5 + dy,
636 637
              mVFlipSvgItem->boundingRect().width(),
              mVFlipSvgItem->boundingRect().height());
638
        case BottomRight:
Claudio Valerio's avatar
Claudio Valerio committed
639 640
            return QRectF(B2.x() + 5,
              B2.y() - mVFlipSvgItem->boundingRect().height() - 5 - dy,
641 642
              mVFlipSvgItem->boundingRect().width(),
              mVFlipSvgItem->boundingRect().height());
643 644
    }
    return QRectF(0,0,0,0);
unknown's avatar
unknown committed
645 646
}

647
QRectF    UBGraphicsTriangle::rotateRect() const
unknown's avatar
unknown committed
648
{
649
    QPointF p(C2);
Craig Watson's avatar
Craig Watson committed
650 651
    qreal buttonsX = vFlipRect().left();

652 653 654
    switch(mOrientation)
    {
        case BottomLeft:
Craig Watson's avatar
Craig Watson committed
655
            p = QPointF(qMax(p.x() + 20, buttonsX), p.y() + 5);
656 657
            break;
        case TopLeft:
Craig Watson's avatar
Craig Watson committed
658
            p = QPointF(qMax(p.x() + 20, buttonsX), p.y() -5 - mRotateSvgItem->boundingRect().height());
659 660
            break;
        case TopRight:
Craig Watson's avatar
Craig Watson committed
661
            p = QPointF(qMin(p.x() -20 - mRotateSvgItem->boundingRect().width(), buttonsX), p.y() - 5 - mRotateSvgItem->boundingRect().height());
662 663
            break;
        case BottomRight:
Craig Watson's avatar
Craig Watson committed
664
            p = QPointF(qMin(p.x() -20 - mRotateSvgItem->boundingRect().width(), buttonsX), p.y() + 5);
665 666
            break;
    }
667
    return QRectF(p, QSizeF(mRotateSvgItem->boundingRect().size()));
668
}
unknown's avatar
unknown committed
669

670
QCursor    UBGraphicsTriangle::resizeCursor1() const
671 672
{
    return mResizeCursor1;
unknown's avatar
unknown committed
673 674
}

675
QCursor    UBGraphicsTriangle::resizeCursor2() const
unknown's avatar
unknown committed
676
{
677
    return mResizeCursor2;
unknown's avatar
unknown committed
678 679
}

680
QCursor    UBGraphicsTriangle::flipCursor() const
unknown's avatar
unknown committed
681
{
682
    return Qt::ArrowCursor;
unknown's avatar
unknown committed
683 684 685 686 687
}


void UBGraphicsTriangle::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
688
    lastRect = rect().toRect();
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
689
    lastPos = sceneTransform().inverted().map(event->screenPos());
690 691

    if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
unknown's avatar
unknown committed
692 693 694 695
    {
        mResizing1 = true;
        event->accept();
    }
Claudio Valerio's avatar
Claudio Valerio committed
696
    else
697 698 699 700 701
    if (resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
    {
        mResizing2 = true;
        event->accept();
    }
Claudio Valerio's avatar
Claudio Valerio committed
702
    else
703
    if(rotateRect().contains(event->pos()))
unknown's avatar
unknown committed
704
    {
705
        mRotating = true;
unknown's avatar
unknown committed
706 707 708 709
        event->accept();
    }
    else
    {
710
        QGraphicsItem::mousePressEvent(event);
unknown's avatar
unknown committed
711
    }
712 713 714 715 716 717
    mShowButtons = false;
    mCloseSvgItem->setVisible(false);
    mHFlipSvgItem->setVisible(false);
    mVFlipSvgItem->setVisible(false);
    mRotateSvgItem->setVisible(mRotating);
    update();
unknown's avatar
unknown committed
718 719 720 721
}

void UBGraphicsTriangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Claudio Valerio's avatar
Claudio Valerio committed
722

unknown's avatar
unknown committed
723 724
    if (!mResizing1 && !mResizing2 && !mRotating)
    {
725
        QGraphicsItem::mouseMoveEvent(event);
unknown's avatar
unknown committed
726 727 728
    }
    else
    {
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
729
        QPoint currPos = sceneTransform().inverted().map(event->screenPos());
730 731 732

        if (mResizing1)
        {
733 734
            if (mOrientation == TopLeft || mOrientation == BottomLeft)
            {
735 736 737 738 739 740
                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);
741 742 743
            }
            else
            {
744 745 746 747 748 749
                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);
750
            }
751 752 753 754 755 756
        }

        //-----------------------------------------------//

        if (mResizing2)
        {
757 758
            if (mOrientation == BottomRight || mOrientation == BottomLeft)
            {
759 760 761 762 763 764
                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);
765 766 767
            }
            else
            {
768 769 770 771 772 773
                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);
774
            }
775 776 777 778 779

        }

        //-----------------------------------------------//

unknown's avatar
unknown committed
780 781 782 783 784 785 786
        if (mRotating)
        {
            QLineF currentLine(rotationCenter(), event->pos());
            QLineF lastLine(rotationCenter(), event->lastPos());
            rotateAroundCenter(currentLine.angleTo(lastLine));
        }

787 788
        //-----------------------------------------------//

unknown's avatar
unknown committed
789 790 791 792 793 794
        event->accept();
    }
}

void UBGraphicsTriangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
795
    if (mResizing1 || mResizing2 || mRotating)
unknown's avatar
unknown committed
796
    {
797 798
        if (mRotating)
            updateResizeCursor();
unknown's avatar
unknown committed
799
        mResizing1 = false;
800 801
        mResizing2 = false;
        mRotating = false;
unknown's avatar
unknown committed
802 803 804 805
        event->accept();
    }
    else if (closeButtonRect().contains(event->pos()))
    {
806
        hide();
unknown's avatar
unknown committed
807 808
        event->accept();
    }
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    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;
        }
    }
unknown's avatar
unknown committed
845 846
    else
    {
847
        QGraphicsItem::mouseReleaseEvent(event);
unknown's avatar
unknown committed
848
    }
849 850
    mShowButtons = true;
    update();
unknown's avatar
unknown committed
851 852
    if (scene())
        scene()->setModified(true);
853 854
}

unknown's avatar
unknown committed
855
void UBGraphicsTriangle::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
856
{
857
    UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool ();
unknown's avatar
unknown committed
858

859 860 861
    if (currentTool == UBStylusTool::Selector ||
        currentTool == UBStylusTool::Play)
    {
862
        mCloseSvgItem->setParentItem(this);
unknown's avatar
unknown committed
863

864 865
        mShowButtons = true;
        mCloseSvgItem->setVisible(true);
Craig Watson's avatar
Craig Watson committed
866 867 868
        mHFlipSvgItem->setVisible(contains(hFlipRect()));
        mVFlipSvgItem->setVisible(contains(vFlipRect()));
        mRotateSvgItem->setVisible(contains(rotateRect()));
unknown's avatar
unknown committed
869

870
        if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
871 872
            setCursor(resizeCursor1());
        else if(resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
873 874 875 876 877 878 879 880 881 882 883 884 885
            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();
886 887 888 889 890

    } else if (UBDrawingController::drawingController()->isDrawingTool())  {
            setCursor(drawRulerLineCursor());
            UBDrawingController::drawingController()->mActiveRuler = this;
            event->accept();
891
    }
892 893 894 895

    //
    //event->accept(); //**
    //update(); //**
unknown's avatar
unknown committed
896 897 898 899
}

void UBGraphicsTriangle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
900
    mResizing1 = mResizing2 = mRotating = false;
unknown's avatar
unknown committed
901 902 903
    mShowButtons = false;
    setCursor(Qt::ArrowCursor);
    mCloseSvgItem->setVisible(false);
904 905
    mVFlipSvgItem->setVisible(false);
    mHFlipSvgItem->setVisible(false);
unknown's avatar
unknown committed
906
    mRotateSvgItem->setVisible(false);
907
    UBDrawingController::drawingController()->mActiveRuler = NULL;
unknown's avatar
unknown committed
908 909 910 911 912 913
    event->accept();
    update();
}

void UBGraphicsTriangle::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
914
    UBStylusTool::Enum currentTool = (UBStylusTool::Enum)UBDrawingController::drawingController ()->stylusTool ();
unknown's avatar
unknown committed
915

916 917
    if (currentTool == UBStylusTool::Selector ||
        currentTool == UBStylusTool::Play)
918 919
    {
        mCloseSvgItem->setVisible(mShowButtons);
Craig Watson's avatar
Craig Watson committed
920 921 922
        mVFlipSvgItem->setVisible(mShowButtons && contains(vFlipRect()));
        mHFlipSvgItem->setVisible(mShowButtons && contains(hFlipRect()));
        mRotateSvgItem->setVisible(mShowButtons && contains(rotateRect()));
unknown's avatar
unknown committed
923

924
        if (resize1Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
925 926
            setCursor(resizeCursor1());
        else if (resize2Polygon().containsPoint(event->pos().toPoint(), Qt::OddEvenFill))
927 928 929 930
            setCursor(resizeCursor2());
        else if (closeButtonRect().contains(event->pos()))
            setCursor(closeCursor());
        else if (hFlipRect().contains(event->pos())
931 932
                 || vFlipRect().contains(event->pos()))
            setCursor(flipCursor());
933 934 935 936 937
        else if (rotateRect().contains(event->pos()))
            setCursor(rotateCursor());
        else
            setCursor(moveCursor());

938 939
        event->accept();
    }  else if (UBDrawingController::drawingController()->isDrawingTool())  {
940 941
        event->accept();
    }
942
}
943 944
void UBGraphicsTriangle::StartLine(const QPointF &scenePos, qreal width)
{
945
    Q_UNUSED(width);
946
    QPointF itemPos = mapFromScene(scenePos);
947
    mStrokeWidth = UBDrawingController::drawingController()->currentToolWidth();
948 949 950 951

    qreal y;

    if (mOrientation == 0 || mOrientation == 1) {
952
        y = rect().y() + rect().height() + mStrokeWidth / 2;
953
    } else if (mOrientation == 2 || mOrientation == 3) {
954
        y = rect().y() - mStrokeWidth / 2;
955 956 957 958 959 960 961 962 963 964 965
    }

    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);
966
    scene()->drawLineTo(itemPos, mStrokeWidth, true);
967 968 969 970
}

void UBGraphicsTriangle::DrawLine(const QPointF &scenePos, qreal width)
{
971
    Q_UNUSED(width);
972 973 974 975 976
    QPointF itemPos = mapFromScene(scenePos);

    qreal y;

    if (mOrientation == 0 || mOrientation == 1) {
977
        y = rect().y() + rect().height() + mStrokeWidth / 2;
978
    } else if (mOrientation == 2 || mOrientation == 3) {
979
        y = rect().y() - mStrokeWidth / 2;
980 981 982 983 984 985 986 987 988 989 990
    }

    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
991
    scene()->drawLineTo(itemPos, mStrokeWidth,
992 993 994
            UBDrawingController::drawingController()->stylusTool() != UBStylusTool::Marker);
}

Craig Watson's avatar
Craig Watson committed
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/**
 * @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<QPointF> 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;
}

1024 1025 1026 1027
void UBGraphicsTriangle::EndLine()
{
}