1
/***************************************************************************
2
* Copyright (c) 2019 WandererFan <wandererfan@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
27
# include <QGraphicsScene>
28
# include <QGraphicsSceneMouseEvent>
30
# include <QPainterPath>
34
#include <Base/Console.h>
35
#include <Mod/TechDraw/App/ArrowPropEnum.h>
36
#include <Mod/TechDraw/App/DrawLeaderLine.h>
37
#include <Mod/TechDraw/App/DrawUtil.h>
38
#include <Mod/TechDraw/App/LineGroup.h>
40
#include "QGILeaderLine.h"
41
#include "PreferencesGui.h"
44
#include "QGIPrimPath.h"
46
#include "ViewProviderLeader.h"
50
using namespace TechDrawGui;
51
using namespace TechDraw;
53
//**************************************************************
54
QGILeaderLine::QGILeaderLine()
55
: m_lineColor(Qt::black),
56
m_lineStyle(Qt::SolidLine),
63
setHandlesChildEvents(false);
64
setAcceptHoverEvents(true);
65
setFlag(QGraphicsItem::ItemIsSelectable, true);
66
setFlag(QGraphicsItem::ItemIsMovable, false);
67
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
68
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
70
setCacheMode(QGraphicsItem::NoCache);
72
m_line = new QGIPrimPath();
74
m_line->setFlag(QGraphicsItem::ItemIsSelectable, false);
75
m_line->setAcceptHoverEvents(false);
76
m_line->setPos(0.0, 0.0);
78
m_editPath = new QGEPath(this);
79
addToGroup(m_editPath);
80
m_editPath->setPos(0.0, 0.0);
81
m_editPath->setFlag(QGraphicsItem::ItemIsSelectable, false);
82
m_editPath->setFlag(QGraphicsItem::ItemIsMovable, false);
83
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false);
84
m_editPath->setZValue(ZVALUE::DIMENSION);
87
m_arrow1 = new QGIArrow();
89
m_arrow1->setPos(0.0, 0.0);
91
m_arrow2 = new QGIArrow();
93
m_arrow2->setPos(0.0, 0.0);
96
setZValue(ZVALUE::DIMENSION);
98
QObject::connect(m_editPath,
99
&QGEPath::pointsUpdated,
101
&QGILeaderLine::onLineEditFinished);
104
void QGILeaderLine::setLeaderFeature(TechDraw::DrawLeaderLine* feat)
106
// Base::Console().Message("QGILL::setLeaderFeature()\n");
107
setViewFeature(static_cast<TechDraw::DrawView*>(feat));
109
float x = Rez::guiX(feat->X.getValue());
110
float y = Rez::guiX(-feat->Y.getValue());
119
QVariant QGILeaderLine::itemChange(GraphicsItemChange change, const QVariant& value)
121
// Base::Console().Message("QGILL::itemChange(%d)\n", change);
122
if (change == ItemSelectedHasChanged && scene()) {
131
else if (change == ItemSceneChange && scene()) {
134
return QGIView::itemChange(change, value);
137
//QGILL isn't draggable so skip QGIV::mousePress have event
138
void QGILeaderLine::mousePressEvent(QGraphicsSceneMouseEvent* event)
140
// Base::Console().Message("QGILL::mousePressEvent() - %s\n", getViewName());
141
QGraphicsItem::mousePressEvent(event);
144
//QGILL isn't draggable so skip QGIV::mouseRelease
145
void QGILeaderLine::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
147
// Base::Console().Message("QGILL::mouseReleaseEvent() - %s\n", getViewName());
148
QGraphicsItem::mouseReleaseEvent(event);
151
void QGILeaderLine::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
153
// Base::Console().Message("QGILL::hoverEnter() - selected; %d\n", isSelected());
158
QGIView::hoverEnterEvent(event);
161
void QGILeaderLine::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
163
// Base::Console().Message("QGILL::hoverLeave() - selected; %d\n", isSelected());
168
QGIView::hoverLeaveEvent(event);
171
void QGILeaderLine::setNormalColorAll()
173
// Base::Console().Message("QGILL::setNormalColorAll - normal color: %s\n", qPrintable(getNormalColor().name()));
174
QColor qc = prefNormalColor();
175
m_line->setNormalColor(qc);
176
m_editPath->setNormalColor(qc);
177
m_arrow1->setNormalColor(qc);
178
m_arrow1->setFillColor(qc);
179
m_arrow2->setNormalColor(qc);
180
m_arrow2->setFillColor(qc);
183
void QGILeaderLine::setPrettyNormal()
185
// Base::Console().Message("QGILL::setPrettyNormal()\n");
186
m_line->setPrettyNormal();
187
m_arrow1->setPrettyNormal();
188
m_arrow2->setPrettyNormal();
191
void QGILeaderLine::setPrettyPre()
193
// Base::Console().Message("QGILL::setPrettyPre()\n");
194
m_line->setPrettyPre();
195
m_arrow1->setPrettyPre();
196
m_arrow2->setPrettyPre();
199
void QGILeaderLine::setPrettySel()
201
// Base::Console().Message("QGILL::setPrettySel()\n");
202
m_line->setPrettySel();
203
m_arrow1->setPrettySel();
204
m_arrow2->setPrettySel();
208
void QGILeaderLine::closeEdit()
210
// Base::Console().Message("QGIL::closeEdit()\n");
212
m_editPath->onEndEdit();//tell QEPath that edit session ended
216
//signaled from QEPath
217
void QGILeaderLine::onLineEditFinished(QPointF tipDisplace, std::vector<QPointF> points)
219
// Base::Console().Message("QGILL::onLineEditFinished(%s, %d)\n",
220
// TechDraw::DrawUtil::formatVector(tipDisplace).c_str(),
223
auto featLeader = getFeature();
227
double baseScale = featLeader->getBaseScale();
229
if (!(TechDraw::DrawUtil::fpCompare(tipDisplace.x(), 0.0)
230
&& TechDraw::DrawUtil::fpCompare(tipDisplace.y(), 0.0))) {
231
//tip was moved. need to change AttachPoint
232
QPointF oldAttach = getAttachFromFeature();
233
QPointF newAttach = oldAttach + (tipDisplace / baseScale);
234
featLeader->setPosition(Rez::appX(newAttach.x()), Rez::appX(-newAttach.y()), true);
237
std::vector<Base::Vector3d> waypoints;
238
for (auto& p : points) {
239
QPointF moved = p - tipDisplace;
240
Base::Vector3d v(moved.x(), moved.y(), 0.0);
241
waypoints.push_back(v);
243
waypoints.at(0) = Base::Vector3d(0.0, 0.0, 0.0);
245
featLeader->WayPoints.setValues(waypoints);
246
if (featLeader->AutoHorizontal.getValue()) {
247
featLeader->adjustLastSegment();
250
Q_EMIT editComplete();//tell task editing is complete
257
void QGILeaderLine::startPathEdit()
260
auto featLeader(dynamic_cast<TechDraw::DrawLeaderLine*>(getViewObject()));
265
double scale = featLeader->getScale();
266
m_editPath->setScale(scale);
267
m_editPath->inEdit(true);
269
m_editPath->startPathEdit(getWayPointsFromFeature());
272
void QGILeaderLine::saveState()
274
// Base::Console().Message("QGILL::saveState()\n");
275
auto featLeader = getFeature();
277
m_savePoints = featLeader->WayPoints.getValues();
278
m_saveX = featLeader->X.getValue();
279
m_saveY = featLeader->Y.getValue();
283
void QGILeaderLine::restoreState()
285
// Base::Console().Message("QGILL::restoreState()\n");
286
auto featLeader = getFeature();
288
featLeader->WayPoints.setValues(m_savePoints);
289
featLeader->X.setValue(m_saveX);
290
featLeader->Y.setValue(m_saveY);
291
featLeader->recomputeFeature();
295
//******************************************************************************
297
void QGILeaderLine::updateView(bool update)
299
// Base::Console().Message("QGIL::updateView() %s\n", getViewObject()->getNameInDocument());
301
auto featLeader(dynamic_cast<TechDraw::DrawLeaderLine*>(getViewObject()));
303
Base::Console().Warning("QGILL::updateView - no feature!\n");
307
auto vp = static_cast<ViewProviderLeader*>(getViewProvider(getViewObject()));
314
void QGILeaderLine::draw()
316
// Base::Console().Message("QGILL::draw()- %s\n", getViewObject()->getNameInDocument());
323
TechDraw::DrawLeaderLine* featLeader = getFeature();
327
auto vp = static_cast<ViewProviderLeader*>(getViewProvider(getViewObject()));
333
TechDraw::DrawView* parent = featLeader->getBaseView();
335
scale = parent->getScale();
338
if (m_editPath->inEdit()) {
343
if (featLeader->isLocked()) {
344
setFlag(QGraphicsItem::ItemIsMovable, false);
347
setFlag(QGraphicsItem::ItemIsMovable, true);
350
m_lineStyle = static_cast<Qt::PenStyle>(vp->LineStyle.getValue());
351
double baseScale = featLeader->getBaseScale();
352
double x = Rez::guiX(featLeader->X.getValue());
353
double y = -Rez::guiX(featLeader->Y.getValue());
354
QPointF aPoint(x, y);
358
m_line->setFillStyle(Qt::NoBrush);
359
m_line->setStyle(m_lineStyle);
360
m_line->setWidth(getLineWidth());
362
m_line->setPos(0, 0);//make m_line coords == leader coords
364
std::vector<QPointF> qPoints = getWayPointsFromFeature();
365
if (featLeader->Scalable.getValue()) {
366
for (auto& p : qPoints) {
372
m_line->setPath(makeLeaderPath(qPoints));
378
else if (m_hasHover) {
384
update(boundingRect());
387
QPainterPath QGILeaderLine::makeLeaderPath(std::vector<QPointF> qPoints)
389
// Base::Console().Message("QGILeaderLine::makeLeaderPath()\n");
391
DrawLeaderLine* featLeader = getFeature();
393
Base::Console().Message("QGILL::makeLeaderPath - featLeader is nullptr\n");
397
QPointF startAdjVec(0.0, 0.0);
398
double startAdjLength(0.0);
399
QPointF endAdjVec(0.0, 0.0);
400
double endAdjLength(0.0);
401
if (qPoints.size() > 1) {
402
//make path adjustment to hide leaderline ends behind arrowheads
403
if (featLeader->StartSymbol.getValue() != ArrowType::NONE) {
404
startAdjLength = QGIArrow::getOverlapAdjust(featLeader->StartSymbol.getValue(),
405
QGIArrow::getPrefArrowSize());
407
if (featLeader->EndSymbol.getValue() != ArrowType::NONE) {
408
endAdjLength = QGIArrow::getOverlapAdjust(featLeader->EndSymbol.getValue(),
409
QGIArrow::getPrefArrowSize());
412
//get adjustment directions
413
startAdjVec = qPoints.at(1) - qPoints.front();
414
endAdjVec = (*(qPoints.end() - 2)) - qPoints.back();
416
//get adjustment vectors
417
QVector2D startTemp(startAdjVec);
418
QVector2D endTemp(endAdjVec);
419
startTemp.normalize();
421
startAdjVec = startTemp.toPointF() * startAdjLength;
422
endAdjVec = endTemp.toPointF() * endAdjLength;
424
qPoints.front() += startAdjVec;
425
qPoints.back() += endAdjVec;
426
result.moveTo(qPoints.front());
427
for (int i = 1; i < (int)qPoints.size(); i++) {
428
result.lineTo(qPoints.at(i));
434
QPointF QGILeaderLine::getAttachFromFeature()
436
// Base::Console().Message("QGILL::getAttachFromFeature()\n");
437
TechDraw::DrawLeaderLine* featLeader = getFeature();
439
Base::Console().Message("QGIL::getAttachFromLeader - no feature\n");
442
double x = Rez::guiX(featLeader->X.getValue());
443
double y = -Rez::guiX(featLeader->Y.getValue());
444
return QPointF(x, y);
447
std::vector<QPointF> QGILeaderLine::getWayPointsFromFeature()
449
std::vector<QPointF> qPoints;
451
DrawLeaderLine* featLeader = getFeature();
453
Base::Console().Message("QGILL::getWayPointsFromFeature - featLeader is nullptr\n");
457
std::vector<Base::Vector3d> vPoints = featLeader->WayPoints.getValues();
458
for (auto& d : vPoints) {
459
QPointF temp(d.x, d.y);
460
qPoints.push_back(temp);
462
if (qPoints.empty()) {
463
Base::Console().Warning("QGILeaderLine::getWayPointsFromFeature - no points\n");
468
void QGILeaderLine::setArrows(std::vector<QPointF> pathPoints)
470
// Base::Console().Message("QGILL::setArrows()\n");
471
Base::Vector3d stdX(1.0, 0.0, 0.0);
472
TechDraw::DrawLeaderLine* featLeader = getFeature();
474
QPointF lastOffset = (pathPoints.back() - pathPoints.front());
476
if (featLeader->StartSymbol.getValue() != ArrowType::NONE) {
477
m_arrow1->setStyle(featLeader->StartSymbol.getValue());
478
m_arrow1->setWidth(getLineWidth());
479
m_arrow1->setSize(QGIArrow::getPrefArrowSize());
480
m_arrow1->setDirMode(true);
481
m_arrow1->setDirection(stdX);
482
if (pathPoints.size() > 1) {
483
auto it = pathPoints.begin();
485
QPointF e = (*(it + 1));
486
QPointF qsVec = s - e;
487
Base::Vector3d sVec(qsVec.x(), qsVec.y(), 0.0);
488
m_arrow1->setDirection(sVec);
489
m_arrow1->setPos(0.0, 0.0);
498
if (featLeader->EndSymbol.getValue() != ArrowType::NONE) {
499
m_arrow2->setStyle(featLeader->EndSymbol.getValue());
500
m_arrow2->setWidth(getLineWidth());
501
m_arrow2->setSize(QGIArrow::getPrefArrowSize());
502
m_arrow2->setDirMode(true);
503
m_arrow2->setDirection(-stdX);
504
if (pathPoints.size() > 1) {
505
auto itr = pathPoints.rbegin();
507
QPointF e = (*(itr + 1));
508
QPointF qeVec = s - e;
509
Base::Vector3d eVec(qeVec.x(), qeVec.y(), 0.0);
510
m_arrow2->setDirection(eVec);
511
m_arrow2->setPos(lastOffset);
521
void QGILeaderLine::drawBorder()
523
////Leaders have no border!
524
// QGIView::drawBorder(); //good for debugging
527
//******************************************************************************
530
void QGILeaderLine::abandonEdit()
532
// Base::Console().Message("QGIL::abandonEdit()\n");
533
m_editPath->clearMarkers();
538
double QGILeaderLine::getLineWidth()
540
auto vp = static_cast<ViewProviderLeader*>(getViewProvider(getViewObject()));
542
return Rez::guiX(LineGroup::getDefaultWidth("Graphic"));
544
return Rez::guiX(vp->LineWidth.getValue());
547
TechDraw::DrawLeaderLine* QGILeaderLine::getFeature()
549
TechDraw::DrawLeaderLine* result = static_cast<TechDraw::DrawLeaderLine*>(getViewObject());
553
double QGILeaderLine::getEdgeFuzz() const
555
return PreferencesGui::edgeFuzz();
558
QColor QGILeaderLine::prefNormalColor()
560
// Base::Console().Message("QGILL::getNormalColor()\n");
561
setNormalColor(PreferencesGui::leaderQColor());
563
auto vp = dynamic_cast<ViewProviderLeader*>(getViewProvider(getViewObject()));
565
QColor normal = vp->Color.getValue().asValue<QColor>();
566
setNormalColor(PreferencesGui::getAccessibleQColor(normal));
568
return getNormalColor();
571
QRectF QGILeaderLine::boundingRect() const
573
return childrenBoundingRect();
576
void QGILeaderLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
579
QStyleOptionGraphicsItem myOption(*option);
580
myOption.state &= ~QStyle::State_Selected;
582
// painter->setPen(Qt::blue);
583
// painter->drawRect(boundingRect()); //good for debugging
585
QGIView::paint(painter, &myOption, widget);
588
#include <Mod/TechDraw/Gui/moc_QGILeaderLine.cpp>