Seamly2D
Code documentation
dialogrotation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2017 Seamly, LLC *
4  * *
5  * https://github.com/fashionfreedom/seamly2d *
6  * *
7  ***************************************************************************
8  **
9  ** Seamly2D is free software: you can redistribute it and/or modify
10  ** it under the terms of the GNU General Public License as published by
11  ** the Free Software Foundation, either version 3 of the License, or
12  ** (at your option) any later version.
13  **
14  ** Seamly2D is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  ** GNU General Public License for more details.
18  **
19  ** You should have received a copy of the GNU General Public License
20  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
21  **
22  **************************************************************************
23 
24  ************************************************************************
25  **
26  ** @file dialogrotation.cpp
27  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
28  ** @date 10 4, 2016
29  **
30  ** @brief
31  ** @copyright
32  ** This source code is part of the Valentine project, a pattern making
33  ** program, whose allow create and modeling patterns of clothing.
34  ** Copyright (C) 2016 Seamly2D project
35  ** <https://github.com/fashionfreedom/seamly2d> All Rights Reserved.
36  **
37  ** Seamly2D is free software: you can redistribute it and/or modify
38  ** it under the terms of the GNU General Public License as published by
39  ** the Free Software Foundation, either version 3 of the License, or
40  ** (at your option) any later version.
41  **
42  ** Seamly2D is distributed in the hope that it will be useful,
43  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
44  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45  ** GNU General Public License for more details.
46  **
47  ** You should have received a copy of the GNU General Public License
48  ** along with Seamly2D. If not, see <http://www.gnu.org/licenses/>.
49  **
50  *************************************************************************/
51 
52 #include "dialogrotation.h"
53 
54 #include <QColor>
55 #include <QComboBox>
56 #include <QDialog>
57 #include <QLabel>
58 #include <QLineEdit>
59 #include <QLineF>
60 #include <QPlainTextEdit>
61 #include <QPointF>
62 #include <QPointer>
63 #include <QPushButton>
64 #include <QRegularExpression>
65 #include <QRegularExpressionMatch>
66 #include <QSharedPointer>
67 #include <QStringList>
68 #include <QTimer>
69 #include <QToolButton>
70 #include <Qt>
71 #include <new>
72 
73 #include "../../visualization/visualization.h"
74 #include "../../visualization/line/operation/vistoolrotation.h"
75 #include "../ifc/xml/vabstractpattern.h"
76 #include "../ifc/xml/vdomdocument.h"
77 #include "../qmuparser/qmudef.h"
78 #include "../support/edit_formula_dialog.h"
79 #include "../vgeometry/vpointf.h"
80 #include "../vmisc/vabstractapplication.h"
81 #include "../vmisc/vcommonsettings.h"
82 #include "../vpatterndb/vcontainer.h"
83 #include "../vpatterndb/vtranslatevars.h"
84 #include "../vwidgets/vabstractmainwindow.h"
85 #include "../vwidgets/vmaingraphicsscene.h"
86 #include "ui_dialogrotation.h"
87 
88 //---------------------------------------------------------------------------------------------------------------------
89 DialogRotation::DialogRotation(const VContainer *data, const quint32 &toolId, QWidget *parent)
90  : DialogTool(data, toolId, parent)
91  , ui(new Ui::DialogRotation)
92  , angleFlag(false)
93  , angleTimer(nullptr)
94  , angleFormula()
95  , m_objects()
96  , stage1(true)
97  , m_suffix()
98  , m_firstRelease(false)
99 {
100  ui->setupUi(this);
101  setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
102  setWindowIcon(QIcon(":/toolicon/32x32/rotation.png"));
103 
104  ui->plainTextEditFormula->installEventFilter(this);
105  ui->suffix_LineEdit->setText(qApp->getCurrentDocument()->GenerateSuffix(qApp->Settings()->getRotateSuffix()));
106 
107  angleTimer = new QTimer(this);
108  connect(angleTimer, &QTimer::timeout, this, &DialogRotation::evaluateAngle);
109 
111 
112  FillComboBoxPoints(ui->rotation_ComboBox);
113 
114  flagName = true;
115  CheckState();
116 
117  connect(ui->suffix_LineEdit, &QLineEdit::textChanged, this, &DialogRotation::suffixChanged);
118  connect(ui->formula_ToolButton, &QPushButton::clicked, this, &DialogRotation::editAngleFormula);
119  connect(ui->plainTextEditFormula, &QPlainTextEdit::textChanged, this, &DialogRotation::angleChanged);
120  connect(ui->rotation_ComboBox, &QComboBox::currentTextChanged, this, &DialogRotation::pointChanged);
121 
122  vis = new VisToolRotation(data);
123 }
124 
125 //---------------------------------------------------------------------------------------------------------------------
127 {
128  delete ui;
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
133 {
134  return getCurrentObjectId(ui->rotation_ComboBox);
135 }
136 
137 //---------------------------------------------------------------------------------------------------------------------
138 void DialogRotation::setOriginPointId(const quint32 &value)
139 {
140  ChangeCurrentData(ui->rotation_ComboBox, value);
141  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
142  SCASSERT(operation != nullptr)
143  operation->SetOriginPointId(value);
144 }
145 
146 //---------------------------------------------------------------------------------------------------------------------
148 {
149  return qApp->TrVars()->TryFormulaFromUser(angleFormula, qApp->Settings()->GetOsSeparator());
150 }
151 
152 //---------------------------------------------------------------------------------------------------------------------
153 void DialogRotation::SetAngle(const QString &value)
154 {
155  angleFormula = qApp->TrVars()->FormulaToUser(value, qApp->Settings()->GetOsSeparator());
156  ui->plainTextEditFormula->setPlainText(angleFormula);
157 
158  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
159  SCASSERT(operation != nullptr)
160  operation->SetAngle(angleFormula);
161 
162  MoveCursorToEnd(ui->plainTextEditFormula);
163 }
164 
165 //---------------------------------------------------------------------------------------------------------------------
167 {
168  return m_suffix;
169 }
170 
171 //---------------------------------------------------------------------------------------------------------------------
172 void DialogRotation::setSuffix(const QString &value)
173 {
174  m_suffix = value;
175  ui->suffix_LineEdit->setText(value);
176 }
177 
178 //---------------------------------------------------------------------------------------------------------------------
180 {
181  return m_objects;
182 }
183 
184 //---------------------------------------------------------------------------------------------------------------------
186 {
187  m_objects = value;
188 
189  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
190  SCASSERT(operation != nullptr)
191  operation->setObjects(sourceToObjects(m_objects));
192 }
193 
194 //---------------------------------------------------------------------------------------------------------------------
196 {
197  if (stage1 && not click)
198  {
199  if (m_objects.isEmpty())
200  {
201  return;
202  }
203 
204  stage1 = false;
205 
206  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
207  SCASSERT(scene != nullptr)
208  scene->clearSelection();
209 
210  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
211  SCASSERT(operation != nullptr)
212  operation->setObjects(sourceToObjects(m_objects));
213  operation->VisualMode();
214 
215  scene->ToggleArcSelection(false);
216  scene->ToggleElArcSelection(false);
217  scene->ToggleSplineSelection(false);
218  scene->ToggleSplinePathSelection(false);
219 
220  scene->ToggleArcHover(false);
221  scene->ToggleElArcHover(false);
222  scene->ToggleSplineHover(false);
223  scene->ToggleSplinePathHover(false);
224 
225  qApp->getSceneView()->allowRubberBand(false);
226 
227  emit ToolTip(tr("Select rotation point"));
228  }
229  else if (not stage1 && prepare && click)
230  {
231  // The check need to ignore first release of mouse button.
232  // User can select point by clicking on a label.
233  if (not m_firstRelease)
234  {
235  m_firstRelease = true;
236  return;
237  }
238 
239  /*We will ignore click if pointer is in point circle*/
240  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
241  SCASSERT(scene != nullptr)
242  try
243  {
245  const QLineF line = QLineF(static_cast<QPointF>(*point), scene->getScenePos());
246 
247  //Radius of point circle, but little bigger. Need handle with hover sizes.
248  if (line.length() <= scaledRadius(sceneScale(qApp->getCurrentScene())) * 1.5)
249  {
250  return;
251  }
252  }
253  catch (const VExceptionBadId &)
254  {
255  return;
256  }
257 
258  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
259  SCASSERT(operation != nullptr)
260 
261  SetAngle(operation->Angle());//Show in dialog angle that a user choose
262  setModal(true);
263  emit ToolTip("");
264  angleTimer->start();
265  show();
266  }
267 }
268 
269 //---------------------------------------------------------------------------------------------------------------------
270 void DialogRotation::ChosenObject(quint32 id, const SceneObject &type)
271 {
272  if (not stage1 && not prepare)// After first choose we ignore all objects
273  {
274  if (type == SceneObject::Point)
275  {
276  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
277  SCASSERT(operation != nullptr)
278 
279  auto object = std::find_if(m_objects.begin(), m_objects.end(),
280  [id](const SourceItem &item) { return item.id == id; });
281 
282  if (object != m_objects.end())
283  {
284  if (m_objects.size() > 1)
285  {
286  // It's not really logical for a user that a center of rotation no need to select.
287  // To fix this issue we just silently remove it from the list.
288  m_objects.erase(object);
289  operation->setObjects(sourceToObjects(m_objects));
290  }
291  else
292  {
293  emit ToolTip(tr("Select rotation point that is not part of the list of objects"));
294  return;
295  }
296  }
297 
298  if (SetObject(id, ui->rotation_ComboBox, ""))
299  {
300 
301  VAbstractMainWindow *window = qobject_cast<VAbstractMainWindow *>(qApp->getMainWindow());
302  SCASSERT(window != nullptr)
303  connect(operation, &Visualization::ToolTip, window, &VAbstractMainWindow::ShowToolTip);
304 
305  operation->SetOriginPointId(id);
306  operation->RefreshGeometry();
307 
308  prepare = true;
309  }
310  }
311  }
312 }
313 
314 //---------------------------------------------------------------------------------------------------------------------
315 void DialogRotation::SelectedObject(bool selected, quint32 id, quint32 tool)
316 {
317  Q_UNUSED(tool)
318  if (stage1)
319  {
320  auto object = std::find_if(m_objects.begin(), m_objects.end(),
321  [id](const SourceItem &item) { return item.id == id; });
322 
323  if (selected)
324  {
325  if (object == m_objects.cend())
326  {
327  SourceItem item;
328  item.id = id;
329  m_objects.append(item);
330  }
331  }
332  else
333  {
334  if (object != m_objects.end())
335  {
336  m_objects.erase(object);
337  }
338  }
339  }
340 }
341 
342 //---------------------------------------------------------------------------------------------------------------------
344 {
345  labelEditFormula = ui->editAngle_Label;
346  labelResultCalculation = ui->resultAngle_Label;
347  ValFormulaChanged(angleFlag, ui->plainTextEditFormula, angleTimer, degreeSymbol);
348 }
349 
350 //---------------------------------------------------------------------------------------------------------------------
352 {
353  EditFormulaDialog *dialog = new EditFormulaDialog(data, toolId, this);
354  dialog->setWindowTitle(tr("Edit angle"));
355  dialog->SetFormula(GetAngle());
356  dialog->setPostfix(degreeSymbol);
357  if (dialog->exec() == QDialog::Accepted)
358  {
359  SetAngle(dialog->GetFormula());
360  }
361  delete dialog;
362 }
363 
364 //---------------------------------------------------------------------------------------------------------------------
366 {
367  QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
368  if (edit)
369  {
370  const QString suffix = edit->text();
371  if (suffix.isEmpty())
372  {
373  flagName = false;
374  ChangeColor(ui->suffix_Label, Qt::red);
375  CheckState();
376  return;
377  }
378  else
379  {
380  if (m_suffix != suffix)
381  {
382  QRegularExpression rx(NameRegExp());
383  const QStringList uniqueNames = VContainer::AllUniqueNames();
384  for (int i=0; i < uniqueNames.size(); ++i)
385  {
386  const QString name = uniqueNames.at(i) + suffix;
387  if (not rx.match(name).hasMatch() || not data->IsUnique(name))
388  {
389  flagName = false;
390  ChangeColor(ui->suffix_Label, Qt::red);
391  CheckState();
392  return;
393  }
394  }
395  }
396  }
397 
398  flagName = true;
399  ChangeColor(ui->suffix_Label, okColor);
400  }
401  CheckState();
402 }
403 
404 //---------------------------------------------------------------------------------------------------------------------
406 {
407  SCASSERT(ok_Button != nullptr)
408  ok_Button->setEnabled(angleFlag && flagName && flagError);
409  SCASSERT(apply_Button != nullptr)
410  apply_Button->setEnabled(ok_Button->isEnabled());
411 }
412 
413 //---------------------------------------------------------------------------------------------------------------------
415 {
416  AddVisualization<VisToolRotation>();
417 }
418 
419 //---------------------------------------------------------------------------------------------------------------------
421 {
422  m_suffix = ui->suffix_LineEdit->text();
423 
424  angleFormula = ui->plainTextEditFormula->toPlainText();
425  angleFormula.replace("\n", " ");
426 
427  VisToolRotation *operation = qobject_cast<VisToolRotation *>(vis);
428  SCASSERT(operation != nullptr)
429 
430  operation->setObjects(sourceToObjects(m_objects));
431  operation->SetOriginPointId(getOriginPointId());
432  operation->SetAngle(angleFormula);
433  operation->RefreshGeometry();
434 }
435 
436 //---------------------------------------------------------------------------------------------------------------------
437 void DialogRotation::closeEvent(QCloseEvent *event)
438 {
439  ui->plainTextEditFormula->blockSignals(true);
440  DialogTool::closeEvent(event);
441 }
442 
443 //---------------------------------------------------------------------------------------------------------------------
445 {
446  quint32 id = getCurrentObjectId(ui->rotation_ComboBox);
447 
448  auto objectId = std::find_if(m_objects.begin(), m_objects.end(),
449  [id](const SourceItem &item) { return item.id == id; });
450 
451  QColor color = okColor;
452  if (objectId != m_objects.end())
453  {
454  flagError = false;
455  color = errorColor;
456  }
457  else
458  {
459  flagError = true;
460  color = okColor;
461  }
462  ChangeColor(ui->originPoint_Label, color);
463  CheckState();
464 }
465 
466 //---------------------------------------------------------------------------------------------------------------------
468 {
469  labelEditFormula = ui->editAngle_Label;
470  Eval(ui->plainTextEditFormula->toPlainText(), angleFlag, ui->resultAngle_Label, degreeSymbol, false);
471 }
virtual void CheckState() Q_DECL_FINAL
CheckState enable, when all is correct, or disable, when something wrong, button ok.
void SetAngle(const QString &value)
virtual void ShowVisualization() Q_DECL_OVERRIDE
virtual ~DialogRotation()
virtual void ChosenObject(quint32 id, const SceneObject &type) Q_DECL_OVERRIDE
virtual void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE
closeEvent handle when dialog cloded
void setOriginPointId(const quint32 &value)
DialogRotation(const VContainer *data, const quint32 &toolId, QWidget *parent=nullptr)
QVector< SourceItem > getSourceObjects() const
virtual void ShowDialog(bool click) Q_DECL_OVERRIDE
QVector< SourceItem > m_objects
angle formula of angle
virtual void SelectedObject(bool selected, quint32 id, quint32 tool) Q_DECL_OVERRIDE
void setSuffix(const QString &value)
QString GetAngle() const
Ui::DialogRotation * ui
virtual void SaveData() Q_DECL_OVERRIDE
SaveData Put dialog data in local variables.
QString getSuffix() const
QString angleFormula
angleTimer timer of check formula of angle *‍/
quint32 getOriginPointId() const
void setSourceObjects(const QVector< SourceItem > &value)
QTimer * angleTimer
angleFlag true if value of angle is correct *‍/
The DialogTool class parent for all dialog of tools.
Definition: dialogtool.h:107
void ChangeCurrentData(QComboBox *box, const QVariant &value) const
ChangeCurrentData select item in combobox by id.
Definition: dialogtool.cpp:419
const QColor okColor
Definition: dialogtool.h:219
void ToolTip(const QString &toolTip)
ToolTip emit tooltipe for tool.
void FillComboBoxPoints(QComboBox *box, FillComboBox rule=FillComboBox::Whole, const quint32 &ch1=NULL_ID, const quint32 &ch2=NULL_ID) const
FillComboBoxPoints fill comboBox list of points.
Definition: dialogtool.cpp:242
bool flagName
flagName true if name is correct
Definition: dialogtool.h:183
void MoveCursorToEnd(QPlainTextEdit *plainTextEdit) const
Definition: dialogtool.cpp:432
QPushButton * ok_Button
ok_Button button ok
Definition: dialogtool.h:199
qreal Eval(const QString &text, bool &flag, QLabel *label, const QString &postfix, bool checkZero=true, bool checkLessThanZero=false)
Eval evaluate formula and show result.
Definition: dialogtool.cpp:805
const QColor errorColor
Definition: dialogtool.h:220
virtual void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE
closeEvent handle when dialog cloded
Definition: dialogtool.cpp:192
void ValFormulaChanged(bool &flag, QLineEdit *edit, QTimer *timer, const QString &postfix=QString())
ValFormulaChanged handle change formula.
Definition: dialogtool.cpp:744
bool SetObject(const quint32 &id, QComboBox *box, const QString &toolTip)
Definition: dialogtool.cpp:974
QPushButton * apply_Button
apply_Button button apply
Definition: dialogtool.h:202
quint32 toolId
Definition: dialogtool.h:225
QLabel * labelEditFormula
labelEditFormula label used when need show wrong formula
Definition: dialogtool.h:217
void initializeOkCancelApply(T *ui)
initializeOkCancelApply initialize OK / Cancel and Apply buttons
Definition: dialogtool.h:365
bool flagError
flagError use this flag if for you do not enought
Definition: dialogtool.h:193
const VContainer * data
data container with data
Definition: dialogtool.h:177
bool prepare
prepare show if we prepare. Show dialog after finish working with visual part of tool
Definition: dialogtool.h:228
QLabel * labelResultCalculation
labelResultCalculation label with result of calculation
Definition: dialogtool.h:211
QPointer< Visualization > vis
Definition: dialogtool.h:236
void ChangeColor(QWidget *widget, const QColor &color)
quint32 getCurrentObjectId(QComboBox *box) const
getCurrentPointId return current point id stored in combobox
Definition: dialogtool.cpp:959
The EditFormulaDialog class dialog for editing wrong formula.
QString GetFormula() const
void SetFormula(const QString &value)
void setPostfix(const QString &value)
virtual void ShowToolTip(const QString &toolTip)=0
The VContainer class container of all variables.
Definition: vcontainer.h:141
static bool IsUnique(const QString &name)
Definition: vcontainer.cpp:585
const QSharedPointer< T > GeometricObject(const quint32 &id) const
Definition: vcontainer.h:266
static QStringList AllUniqueNames()
Definition: vcontainer.cpp:591
The VExceptionBadId class for exception bad id.
The VMainGraphicsScene class main scene.
void ToggleArcHover(bool enabled)
QPointF getScenePos() const
void ToggleSplinePathSelection(bool enabled)
void ToggleElArcHover(bool enabled)
void ToggleElArcSelection(bool enabled)
void ToggleSplinePathHover(bool enabled)
void ToggleSplineHover(bool enabled)
void ToggleSplineSelection(bool enabled)
void ToggleArcSelection(bool enabled)
The VPointF class keep data of point.
Definition: vpointf.h:75
void setObjects(QVector< quint32 > objects)
virtual void VisualMode(const quint32 &pointId=NULL_ID) Q_DECL_OVERRIDE
void SetAngle(const QString &expression)
QString Angle() const
void SetOriginPointId(quint32 value)
virtual void RefreshGeometry() Q_DECL_OVERRIDE
void ToolTip(const QString &toolTip)
const QString degreeSymbol
Definition: def.cpp:196
#define SCASSERT(cond)
Definition: def.h:317
SceneObject
Definition: def.h:103
qreal sceneScale(QGraphicsScene *scene)
Definition: global.cpp:63
qreal scaledRadius(qreal scale)
Definition: global.cpp:103
QString NameRegExp()
Definition: qmudef.cpp:281
QVector< quint32 > sourceToObjects(const QVector< SourceItem > &source)
#define qApp
Definition: vapplication.h:67