1 /************************************************************************
2 **
3 ** @file vabstractspline.cpp
4 ** @author Roman Telezhynskyi <dismine(at)gmail.com>
5 ** @date 4 3, 2014
6 **
7 ** @brief
8 ** @copyright
9 ** This source code is part of the Valentina project, a pattern making
10 ** program, whose allow create and modeling patterns of clothing.
11 ** Copyright (C) 2013-2015 Valentina project
12 ** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
13 **
14 ** Valentina is free software: you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License as published by
16 ** the Free Software Foundation, either version 3 of the License, or
17 ** (at your option) any later version.
18 **
19 ** Valentina is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ** GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
26 **
27 *************************************************************************/
28
29 #include "vabstractspline.h"
30
31 #include <QColor>
32 #include <QFlags>
33 #include <QGraphicsScene>
34 #include <QGraphicsSceneMouseEvent>
35 #include <QGuiApplication>
36 #include <QKeyEvent>
37 #include <QLineF>
38 #include <QPen>
39 #include <QSharedPointer>
40 #include <Qt>
41 #include <new>
42
43 #include "../ifc/exception/vexception.h"
44 #include "../ifc/exception/vexceptionbadid.h"
45 #include "../ifc/xml/vabstractpattern.h"
46 #include "../qmuparser/qmutokenparser.h"
47 #include "../vgeometry/vgobject.h"
48 #include "../vgeometry/vpointf.h"
49 #include "../vgeometry/vspline.h"
50 #include "../vgeometry/vabstractarc.h"
51 #include "../vpatterndb/vcontainer.h"
52 #include "../vwidgets/vcontrolpointspline.h"
53 #include "../../../visualization/line/visline.h"
54 #include "../../vabstracttool.h"
55 #include "../vdrawtool.h"
56
57 //---------------------------------------------------------------------------------------------------------------------
VAbstractSpline(VAbstractPattern * doc,VContainer * data,quint32 id,const QString & notes,QGraphicsItem * parent)58 VAbstractSpline::VAbstractSpline(VAbstractPattern *doc, VContainer *data, quint32 id, const QString ¬es,
59 QGraphicsItem *parent)
60 :VDrawTool(doc, data, id, notes),
61 QGraphicsPathItem(parent),
62 controlPoints(),
63 sceneType(SceneObject::Unknown),
64 m_isHovered(false),
65 detailsMode(VAbstractApplication::VApp()->Settings()->IsShowCurveDetails()),
66 m_acceptHoverEvents(true)
67 {
68 InitDefShape();
69 setAcceptHoverEvents(m_acceptHoverEvents);
70 }
71
72 //---------------------------------------------------------------------------------------------------------------------
shape() const73 QPainterPath VAbstractSpline::shape() const
74 {
75 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
76 const QVector<QPointF> points = curve->GetPoints();
77
78 QPainterPath path;
79 for (qint32 i = 0; i < points.count()-1; ++i)
80 {
81 path.moveTo(points.at(i));
82 path.lineTo(points.at(i+1));
83 }
84
85 if (m_isHovered || detailsMode)
86 {
87 path.addPath(VAbstractCurve::ShowDirection(curve->DirectionArrows(),
88 ScaleWidth(VAbstractCurve::LengthCurveDirectionArrow(),
89 SceneScale(scene()))));
90 }
91 path.setFillRule(Qt::WindingFill);
92 return ItemShapeFromPath(path, pen());
93 }
94
95 //---------------------------------------------------------------------------------------------------------------------
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)96 void VAbstractSpline::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
97 {
98 const qreal width = ScaleWidth(m_isHovered ? VAbstractApplication::VApp()->Settings()->WidthMainLine()
99 : VAbstractApplication::VApp()->Settings()->WidthHairLine(),
100 SceneScale(scene()));
101
102 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
103 setPen(QPen(CorrectColor(this, curve->GetColor()), width, LineStyleToPenStyle(curve->GetPenStyle()), Qt::RoundCap));
104
105 auto PaintSpline = [this, curve](QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
106 {
107 if (m_isHovered || detailsMode)
108 {
109 painter->save();
110
111 QPen arrowPen(pen());
112 arrowPen.setStyle(Qt::SolidLine);
113
114 painter->setPen(arrowPen);
115 painter->setBrush(brush());
116
117 painter->drawPath(VAbstractCurve::ShowDirection(curve->DirectionArrows(),
118 ScaleWidth(VAbstractCurve::LengthCurveDirectionArrow(),
119 SceneScale(scene()))));
120
121 painter->restore();
122 }
123
124 PaintWithFixItemHighlightSelected<QGraphicsPathItem>(this, painter, option, widget);
125 };
126
127 PaintSpline(painter, option, widget);
128 }
129
130 //---------------------------------------------------------------------------------------------------------------------
getTagName() const131 QString VAbstractSpline::getTagName() const
132 {
133 return VAbstractPattern::TagSpline;
134 }
135
136 //---------------------------------------------------------------------------------------------------------------------
137 /**
138 * @brief FullUpdateFromFile update tool data form file.
139 */
FullUpdateFromFile()140 void VAbstractSpline::FullUpdateFromFile()
141 {
142 ReadAttributes();
143 RefreshGeometry();
144 }
145
146 //---------------------------------------------------------------------------------------------------------------------
Disable(bool disable,const QString & namePP)147 void VAbstractSpline::Disable(bool disable, const QString &namePP)
148 {
149 const bool enabled = !CorrectDisable(disable, namePP);
150 this->setEnabled(enabled);
151 emit setEnabledPoint(enabled);
152 }
153
154 //---------------------------------------------------------------------------------------------------------------------
DetailsMode(bool mode)155 void VAbstractSpline::DetailsMode(bool mode)
156 {
157 detailsMode = mode;
158 RefreshGeometry();
159 ShowHandles(detailsMode);
160 }
161
162 //---------------------------------------------------------------------------------------------------------------------
AllowHover(bool enabled)163 void VAbstractSpline::AllowHover(bool enabled)
164 {
165 // Manually handle hover events. Need for setting cursor for not selectable paths.
166 m_acceptHoverEvents = enabled;
167
168 for (auto point : qAsConst(controlPoints))
169 {
170 point->setAcceptHoverEvents(enabled);
171 }
172 }
173
174 //---------------------------------------------------------------------------------------------------------------------
AllowSelecting(bool enabled)175 void VAbstractSpline::AllowSelecting(bool enabled)
176 {
177 setFlag(QGraphicsItem::ItemIsSelectable, enabled);
178
179 for (auto point : qAsConst(controlPoints))
180 {
181 point->setFlag(QGraphicsItem::ItemIsSelectable, enabled);
182 }
183 }
184
185 //---------------------------------------------------------------------------------------------------------------------
MakeToolTip() const186 QString VAbstractSpline::MakeToolTip() const
187 {
188 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
189
190 const QString toolTip = QString("<table>"
191 "<tr> <td><b>%4:</b> %5</td> </tr>"
192 "<tr> <td><b>%1:</b> %2 %3</td> </tr>"
193 "</table>")
194 .arg(tr("Length"))
195 .arg(VAbstractValApplication::VApp()->fromPixel(curve->GetLength()))
196 .arg(UnitsToStr(VAbstractValApplication::VApp()->patternUnits(), true), tr("Label"), curve->ObjectName());
197 return toolTip;
198 }
199
200 //---------------------------------------------------------------------------------------------------------------------
201 /**
202 * @brief ShowTool highlight tool.
203 * @param id object id in container
204 * @param enable enable or disable highlight.
205 */
ShowTool(quint32 id,bool enable)206 void VAbstractSpline::ShowTool(quint32 id, bool enable)
207 {
208 ShowItem(this, id, enable);
209 }
210
211 //---------------------------------------------------------------------------------------------------------------------
RefreshGeometry()212 void VAbstractSpline::RefreshGeometry()
213 {
214 InitDefShape();
215 RefreshCtrlPoints();
216 SetVisualization();
217 }
218
219 //---------------------------------------------------------------------------------------------------------------------
220 /**
221 * @brief hoverEnterEvent handle hover enter events.
222 * @param event hover enter event.
223 */
224 // cppcheck-suppress unusedFunction
hoverEnterEvent(QGraphicsSceneHoverEvent * event)225 void VAbstractSpline::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
226 {
227 m_isHovered = true;
228 setToolTip(MakeToolTip());
229 QGraphicsPathItem::hoverEnterEvent(event);
230 }
231
232 //---------------------------------------------------------------------------------------------------------------------
233 /**
234 * @brief hoverLeaveEvent handle hover leave events.
235 * @param event hover leave event.
236 */
237 // cppcheck-suppress unusedFunction
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)238 void VAbstractSpline::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
239 {
240 m_isHovered = false;
241 QGraphicsPathItem::hoverLeaveEvent(event);
242 }
243
244 //---------------------------------------------------------------------------------------------------------------------
245 /**
246 * @brief itemChange hadle item change.
247 * @param change change.
248 * @param value value.
249 * @return value.
250 */
itemChange(QGraphicsItem::GraphicsItemChange change,const QVariant & value)251 QVariant VAbstractSpline::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
252 {
253 if (change == QGraphicsItem::ItemSelectedHasChanged)
254 {
255 emit ChangedToolSelection(value.toBool(), m_id, m_id);
256 }
257
258 return QGraphicsPathItem::itemChange(change, value);
259 }
260
261 //---------------------------------------------------------------------------------------------------------------------
262 /**
263 * @brief keyReleaseEvent handle key release events.
264 * @param event key release event.
265 */
keyReleaseEvent(QKeyEvent * event)266 void VAbstractSpline::keyReleaseEvent(QKeyEvent *event)
267 {
268 switch (event->key())
269 {
270 case Qt::Key_Delete:
271 try
272 {
273 DeleteToolWithConfirm();
274 }
275 catch(const VExceptionToolWasDeleted &e)
276 {
277 Q_UNUSED(e)
278 return;//Leave this method immediately!!!
279 }
280 break;
281 default:
282 break;
283 }
284 QGraphicsPathItem::keyReleaseEvent ( event );
285 }
286
287 //---------------------------------------------------------------------------------------------------------------------
mousePressEvent(QGraphicsSceneMouseEvent * event)288 void VAbstractSpline::mousePressEvent(QGraphicsSceneMouseEvent *event)
289 {
290 // Special for not selectable item first need to call standard mousePressEvent then accept event
291 QGraphicsPathItem::mousePressEvent(event);
292
293 // Somehow clicking on notselectable object do not clean previous selections.
294 if (not (flags() & ItemIsSelectable) && scene())
295 {
296 scene()->clearSelection();
297 }
298
299 event->accept();// Special for not selectable item first need to call standard mousePressEvent then accept event
300 }
301
302 //---------------------------------------------------------------------------------------------------------------------
303 /**
304 * @brief mouseReleaseEvent handle mouse release events.
305 * @param event mouse release event.
306 */
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)307 void VAbstractSpline::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
308 {
309 if (IsSelectedByReleaseEvent(this, event))
310 {
311 emit ChoosedTool(m_id, sceneType);
312 }
313 QGraphicsPathItem::mouseReleaseEvent(event);
314 }
315
316 //---------------------------------------------------------------------------------------------------------------------
SaveOptions(QDomElement & tag,QSharedPointer<VGObject> & obj)317 void VAbstractSpline::SaveOptions(QDomElement &tag, QSharedPointer<VGObject> &obj)
318 {
319 VDrawTool::SaveOptions(tag, obj);
320
321 const QSharedPointer<VAbstractCurve> curve = qSharedPointerCast<VAbstractCurve>(obj);
322 doc->SetAttribute(tag, AttrColor, curve->GetColor());
323 doc->SetAttribute(tag, AttrPenStyle, curve->GetPenStyle());
324 doc->SetAttribute(tag, AttrAScale, curve->GetApproximationScale());
325 doc->SetAttributeOrRemoveIf(tag, AttrAlias, curve->GetAliasSuffix(), curve->GetAliasSuffix().isEmpty());
326 }
327
328 //---------------------------------------------------------------------------------------------------------------------
RefreshCtrlPoints()329 void VAbstractSpline::RefreshCtrlPoints()
330 {
331 // do nothing
332 }
333
334 //---------------------------------------------------------------------------------------------------------------------
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)335 void VAbstractSpline::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
336 {
337 ShowContextMenu(event);
338 }
339
340 //---------------------------------------------------------------------------------------------------------------------
CorrectedSpline(const VSpline & spline,const SplinePointPosition & position,const QPointF & pos) const341 VSpline VAbstractSpline::CorrectedSpline(const VSpline &spline, const SplinePointPosition &position,
342 const QPointF &pos) const
343 {
344 VSpline spl;
345 if (position == SplinePointPosition::FirstPoint)
346 {
347 QLineF line(static_cast<QPointF>(spline.GetP1()), pos);
348 if (QGuiApplication::keyboardModifiers() == Qt::ShiftModifier)
349 {
350 line.setAngle(VisLine::CorrectAngle(line.angle()));
351 }
352
353 qreal newAngle1 = line.angle();
354 QString newAngle1F = QString().setNum(newAngle1);
355
356 qreal newLength1 = line.length();
357 QString newLength1F = QString().setNum(VAbstractValApplication::VApp()->fromPixel(newLength1));
358
359 if (not qmu::QmuTokenParser::IsSingle(spline.GetStartAngleFormula()))
360 {
361 newAngle1 = spline.GetStartAngle();
362 newAngle1F = spline.GetStartAngleFormula();
363 }
364
365 if (not qmu::QmuTokenParser::IsSingle(spline.GetC1LengthFormula()))
366 {
367 newLength1 = spline.GetC1Length();
368 newLength1F = spline.GetC1LengthFormula();
369 }
370
371 spl = VSpline(spline.GetP1(), spline.GetP4(), newAngle1, newAngle1F, spline.GetEndAngle(),
372 spline.GetEndAngleFormula(), newLength1, newLength1F, spline.GetC2Length(),
373 spline.GetC2LengthFormula());
374 }
375 else
376 {
377 QLineF line(static_cast<QPointF>(spline.GetP4()), pos);
378 if (QGuiApplication::keyboardModifiers() == Qt::ShiftModifier)
379 {
380 line.setAngle(VisLine::CorrectAngle(line.angle()));
381 }
382
383 qreal newAngle2 = line.angle();
384 QString newAngle2F = QString().setNum(newAngle2);
385
386 qreal newLength2 = line.length();
387 QString newLength2F = QString().setNum(VAbstractValApplication::VApp()->fromPixel(newLength2));
388
389 if (not qmu::QmuTokenParser::IsSingle(spline.GetEndAngleFormula()))
390 {
391 newAngle2 = spline.GetEndAngle();
392 newAngle2F = spline.GetEndAngleFormula();
393 }
394
395 if (not qmu::QmuTokenParser::IsSingle(spline.GetC2LengthFormula()))
396 {
397 newLength2 = spline.GetC2Length();
398 newLength2F = spline.GetC2LengthFormula();
399 }
400 spl = VSpline(spline.GetP1(), spline.GetP4(), spline.GetStartAngle(), spline.GetStartAngleFormula(),
401 newAngle2, newAngle2F, spline.GetC1Length(), spline.GetC1LengthFormula(),
402 newLength2, newLength2F);
403 }
404
405 return spl;
406 }
407
408 //---------------------------------------------------------------------------------------------------------------------
CurveSelected(bool selected)409 void VAbstractSpline::CurveSelected(bool selected)
410 {
411 setSelected(selected);
412
413 for (auto point : qAsConst(controlPoints))
414 {
415 point->blockSignals(true);
416 point->setSelected(selected);
417 point->blockSignals(false);
418 }
419 }
420
421 //---------------------------------------------------------------------------------------------------------------------
InitDefShape()422 void VAbstractSpline::InitDefShape()
423 {
424 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
425 this->setPath(curve->GetPath());
426 }
427
428 //---------------------------------------------------------------------------------------------------------------------
ShowHandles(bool show)429 void VAbstractSpline::ShowHandles(bool show)
430 {
431 for (auto point : qAsConst(controlPoints))
432 {
433 point->setVisible(show);
434 }
435 update();// Show direction
436 }
437
438 //---------------------------------------------------------------------------------------------------------------------
GetLineColor() const439 QString VAbstractSpline::GetLineColor() const
440 {
441 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
442 return curve->GetColor();
443 }
444
445 //---------------------------------------------------------------------------------------------------------------------
SetLineColor(const QString & value)446 void VAbstractSpline::SetLineColor(const QString &value)
447 {
448 QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
449 curve->SetColor(value);
450 QSharedPointer<VGObject> obj = qSharedPointerCast<VGObject>(curve);
451 SaveOption(obj);
452 }
453
454 //---------------------------------------------------------------------------------------------------------------------
GetPenStyle() const455 QString VAbstractSpline::GetPenStyle() const
456 {
457 const QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
458 return curve->GetPenStyle();
459 }
460
461 //---------------------------------------------------------------------------------------------------------------------
SetPenStyle(const QString & value)462 void VAbstractSpline::SetPenStyle(const QString &value)
463 {
464 QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
465 curve->SetPenStyle(value);
466 QSharedPointer<VGObject> obj = qSharedPointerCast<VGObject>(curve);
467 SaveOption(obj);
468 }
469
470 //---------------------------------------------------------------------------------------------------------------------
name() const471 QString VAbstractSpline::name() const
472 {
473 return ObjectName<VAbstractCurve>(m_id);
474 }
475
476 //---------------------------------------------------------------------------------------------------------------------
GetApproximationScale() const477 qreal VAbstractSpline::GetApproximationScale() const
478 {
479 return VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id)->GetApproximationScale();
480 }
481
482 //---------------------------------------------------------------------------------------------------------------------
GetDuplicate() const483 quint32 VAbstractSpline::GetDuplicate() const
484 {
485 return VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id)->GetDuplicate();
486 }
487
488 //---------------------------------------------------------------------------------------------------------------------
GetAliasSuffix() const489 QString VAbstractSpline::GetAliasSuffix() const
490 {
491 return ObjectAliasSuffix<VAbstractCurve>(m_id);
492 }
493
494 //---------------------------------------------------------------------------------------------------------------------
SetAliasSuffix(QString alias)495 void VAbstractSpline::SetAliasSuffix(QString alias)
496 {
497 QSharedPointer<VAbstractCurve> curve = VAbstractTool::data.GeometricObject<VAbstractCurve>(m_id);
498
499 const QString oldAliasSuffix = curve->GetAliasSuffix();
500 alias = alias.simplified().replace(QChar(QChar::Space), QChar('_'));
501 curve->SetAliasSuffix(alias);
502
503 QRegularExpression rx(NameRegExp());
504
505 if (alias.isEmpty() || (rx.match(curve->GetAlias()).hasMatch() && VAbstractTool::data.IsUnique(curve->GetAlias())))
506 {
507 QSharedPointer<VGObject> obj = qSharedPointerCast<VGObject>(curve);
508 SaveOption(obj);
509 }
510 else
511 {
512 curve->SetAliasSuffix(oldAliasSuffix);
513 }
514 }
515
516 //---------------------------------------------------------------------------------------------------------------------
GroupVisibility(quint32 object,bool visible)517 void VAbstractSpline::GroupVisibility(quint32 object, bool visible)
518 {
519 Q_UNUSED(object)
520 setVisible(visible);
521 }
522
523 // VToolAbstractArc
524 //---------------------------------------------------------------------------------------------------------------------
VToolAbstractArc(VAbstractPattern * doc,VContainer * data,quint32 id,const QString & notes,QGraphicsItem * parent)525 VToolAbstractArc::VToolAbstractArc(VAbstractPattern *doc, VContainer *data, quint32 id, const QString ¬es,
526 QGraphicsItem *parent)
527 : VAbstractSpline(doc, data, id, notes, parent)
528 {}
529
530 //---------------------------------------------------------------------------------------------------------------------
CenterPointName() const531 QString VToolAbstractArc::CenterPointName() const
532 {
533 QSharedPointer<VAbstractArc> arc = VAbstractTool::data.GeometricObject<VAbstractArc>(m_id);
534 SCASSERT(arc.isNull() == false)
535
536 return VAbstractTool::data.GetGObject(arc->GetCenter().id())->name();
537 }
538