1 /************************************************************************
2  **
3  **  @file   dialogpointfromcircleandtangent.cpp
4  **  @author Roman Telezhynskyi <dismine(at)gmail.com>
5  **  @date   3 6, 2015
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) 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 "dialogpointfromcircleandtangent.h"
30 
31 #include <climits>
32 #include <QColor>
33 #include <QComboBox>
34 #include <QDialog>
35 #include <QLabel>
36 #include <QLineEdit>
37 #include <QPlainTextEdit>
38 #include <QPointer>
39 #include <QPushButton>
40 #include <QTimer>
41 #include <QToolButton>
42 #include <Qt>
43 
44 #include "../vpatterndb/vtranslatevars.h"
45 #include "../vpatterndb/vcontainer.h"
46 #include "../../visualization/visualization.h"
47 #include "../../visualization/line/vistoolpointfromcircleandtangent.h"
48 #include "../ifc/xml/vdomdocument.h"
49 #include "../support/dialogeditwrongformula.h"
50 #include "../vmisc/vabstractapplication.h"
51 #include "../vmisc/vcommonsettings.h"
52 #include "ui_dialogpointfromcircleandtangent.h"
53 
54 //---------------------------------------------------------------------------------------------------------------------
DialogPointFromCircleAndTangent(const VContainer * data,quint32 toolId,QWidget * parent)55 DialogPointFromCircleAndTangent::DialogPointFromCircleAndTangent(const VContainer *data, quint32 toolId,
56                                                                  QWidget *parent)
57     : DialogTool(data, toolId, parent),
58       ui(new Ui::DialogPointFromCircleAndTangent),
59       timerCircleRadius(nullptr),
60       circleRadius(),
61       formulaBaseHeightCircleRadius(0),
62       pointName(),
63       flagCircleRadius(false),
64       flagName(true),
65       flagError(true)
66 {
67     ui->setupUi(this);
68 
69     ui->lineEditNamePoint->setClearButtonEnabled(true);
70 
71     ui->lineEditNamePoint->setText(
72                 VAbstractValApplication::VApp()->getCurrentDocument()->GenerateLabel(LabelType::NewLabel));
73 
74     this->formulaBaseHeightCircleRadius = ui->plainTextEditRadius->height();
75 
76     ui->plainTextEditRadius->installEventFilter(this);
77 
78     timerCircleRadius = new QTimer(this);
79     connect(timerCircleRadius, &QTimer::timeout, this, &DialogPointFromCircleAndTangent::EvalCircleRadius);
80 
81     InitOkCancelApply(ui);
82 
83     FillComboBoxPoints(ui->comboBoxCircleCenter);
84     FillComboBoxPoints(ui->comboBoxTangentPoint);
85     FillComboBoxCrossCirclesPoints(ui->comboBoxResult);
86 
87     connect(ui->lineEditNamePoint, &QLineEdit::textChanged, this, [this]()
88     {
89         CheckPointLabel(this, ui->lineEditNamePoint, ui->labelEditNamePoint, pointName, this->data, flagName);
90         CheckState();
91     });
92     connect(ui->comboBoxCircleCenter, &QComboBox::currentTextChanged,
93             this, &DialogPointFromCircleAndTangent::PointChanged);
94 
95     connect(ui->toolButtonExprRadius, &QPushButton::clicked, this,
96             &DialogPointFromCircleAndTangent::FXCircleRadius);
97 
98     connect(ui->plainTextEditRadius, &QPlainTextEdit::textChanged, this, [this]()
99     {
100         timerCircleRadius->start(formulaTimerTimeout);
101     });
102 
103     connect(ui->pushButtonGrowRadius, &QPushButton::clicked, this,
104             &DialogPointFromCircleAndTangent::DeployCircleRadiusTextEdit);
105 
106     vis = new VisToolPointFromCircleAndTangent(data);
107 
108     ui->tabWidget->setCurrentIndex(0);
109     SetTabStopDistance(ui->plainTextEditToolNotes);
110 }
111 
112 //---------------------------------------------------------------------------------------------------------------------
~DialogPointFromCircleAndTangent()113 DialogPointFromCircleAndTangent::~DialogPointFromCircleAndTangent()
114 {
115     delete ui;
116 }
117 
118 //---------------------------------------------------------------------------------------------------------------------
GetPointName() const119 QString DialogPointFromCircleAndTangent::GetPointName() const
120 {
121     return pointName;
122 }
123 
124 //---------------------------------------------------------------------------------------------------------------------
SetPointName(const QString & value)125 void DialogPointFromCircleAndTangent::SetPointName(const QString &value)
126 {
127     pointName = value;
128     ui->lineEditNamePoint->setText(pointName);
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
GetCircleCenterId() const132 quint32 DialogPointFromCircleAndTangent::GetCircleCenterId() const
133 {
134     return getCurrentObjectId(ui->comboBoxCircleCenter);
135 }
136 
137 //---------------------------------------------------------------------------------------------------------------------
SetCircleCenterId(const quint32 & value)138 void DialogPointFromCircleAndTangent::SetCircleCenterId(const quint32 &value)
139 {
140     setCurrentPointId(ui->comboBoxCircleCenter, value);
141 
142     VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
143     SCASSERT(point != nullptr)
144     point->setObject2Id(value);
145 }
146 
147 //---------------------------------------------------------------------------------------------------------------------
GetCircleRadius() const148 QString DialogPointFromCircleAndTangent::GetCircleRadius() const
149 {
150     return VAbstractApplication::VApp()->TrVars()
151             ->TryFormulaFromUser(ui->plainTextEditRadius->toPlainText(),
152                                  VAbstractApplication::VApp()->Settings()->GetOsSeparator());
153 }
154 
155 //---------------------------------------------------------------------------------------------------------------------
SetCircleRadius(const QString & value)156 void DialogPointFromCircleAndTangent::SetCircleRadius(const QString &value)
157 {
158     const QString formula = VAbstractApplication::VApp()->TrVars()
159             ->FormulaToUser(value, VAbstractApplication::VApp()->Settings()->GetOsSeparator());
160     // increase height if needed.
161     if (formula.length() > 80)
162     {
163         this->DeployCircleRadiusTextEdit();
164     }
165     ui->plainTextEditRadius->setPlainText(formula);
166 
167     VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
168     SCASSERT(point != nullptr)
169     point->setCRadius(formula);
170 
171     MoveCursorToEnd(ui->plainTextEditRadius);
172 }
173 
174 //---------------------------------------------------------------------------------------------------------------------
GetTangentPointId() const175 quint32 DialogPointFromCircleAndTangent::GetTangentPointId() const
176 {
177     return getCurrentObjectId(ui->comboBoxTangentPoint);
178 }
179 
180 //---------------------------------------------------------------------------------------------------------------------
SetTangentPointId(const quint32 & value)181 void DialogPointFromCircleAndTangent::SetTangentPointId(const quint32 &value)
182 {
183     setCurrentPointId(ui->comboBoxTangentPoint, value);
184 
185     VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
186     SCASSERT(point != nullptr)
187     point->setObject1Id(value);
188 }
189 
190 //---------------------------------------------------------------------------------------------------------------------
GetCrossCirclesPoint() const191 CrossCirclesPoint DialogPointFromCircleAndTangent::GetCrossCirclesPoint() const
192 {
193     return getCurrentCrossPoint<CrossCirclesPoint>(ui->comboBoxResult);
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
SetCrossCirclesPoint(const CrossCirclesPoint & p)197 void DialogPointFromCircleAndTangent::SetCrossCirclesPoint(const CrossCirclesPoint &p)
198 {
199     const qint32 index = ui->comboBoxResult->findData(static_cast<int>(p));
200     if (index != -1)
201     {
202         ui->comboBoxResult->setCurrentIndex(index);
203 
204         VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
205         SCASSERT(point != nullptr)
206         point->setCrossPoint(p);
207     }
208 }
209 
210 //---------------------------------------------------------------------------------------------------------------------
ChosenObject(quint32 id,const SceneObject & type)211 void DialogPointFromCircleAndTangent::ChosenObject(quint32 id, const SceneObject &type)
212 {
213     if (prepare == false)// After first choose we ignore all objects
214     {
215         if (type == SceneObject::Point)
216         {
217             VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
218             SCASSERT(point != nullptr)
219 
220             switch (number)
221             {
222                 case 0:
223                     if (SetObject(id, ui->comboBoxTangentPoint, tr("Select a circle center")))
224                     {
225                         number++;
226                         point->VisualMode(id);
227                     }
228                     break;
229                 case 1:
230                     if (getCurrentObjectId(ui->comboBoxTangentPoint) != id)
231                     {
232                         if (SetObject(id, ui->comboBoxCircleCenter, QString()))
233                         {
234                             number = 0;
235                             point->setObject2Id(id);
236                             point->RefreshGeometry();
237                             prepare = true;
238                             this->setModal(true);
239                             this->show();
240                         }
241                     }
242                     break;
243                 default:
244                     break;
245             }
246         }
247     }
248 }
249 
250 //---------------------------------------------------------------------------------------------------------------------
PointChanged()251 void DialogPointFromCircleAndTangent::PointChanged()
252 {
253     QColor color;
254     if (getCurrentObjectId(ui->comboBoxCircleCenter) == getCurrentObjectId(ui->comboBoxTangentPoint))
255     {
256         flagError = false;
257         color = errorColor;
258     }
259     else
260     {
261         flagError = true;
262         color = OkColor(this);
263     }
264     ChangeColor(ui->labelCircleCenter, color);
265     ChangeColor(ui->labelTangentPoint, color);
266     CheckState();
267 }
268 
269 //---------------------------------------------------------------------------------------------------------------------
DeployCircleRadiusTextEdit()270 void DialogPointFromCircleAndTangent::DeployCircleRadiusTextEdit()
271 {
272     DeployFormula(this, ui->plainTextEditRadius, ui->pushButtonGrowRadius, formulaBaseHeightCircleRadius);
273 }
274 
275 //---------------------------------------------------------------------------------------------------------------------
FXCircleRadius()276 void DialogPointFromCircleAndTangent::FXCircleRadius()
277 {
278     DialogEditWrongFormula *dialog = new DialogEditWrongFormula(data, toolId, this);
279     dialog->setWindowTitle(tr("Edit radius"));
280     dialog->SetFormula(GetCircleRadius());
281     dialog->setPostfix(UnitsToStr(VAbstractValApplication::VApp()->patternUnits(), true));
282     if (dialog->exec() == QDialog::Accepted)
283     {
284         SetCircleRadius(dialog->GetFormula());
285     }
286     delete dialog;
287 }
288 
289 //---------------------------------------------------------------------------------------------------------------------
EvalCircleRadius()290 void DialogPointFromCircleAndTangent::EvalCircleRadius()
291 {
292     FormulaData formulaData;
293     formulaData.formula = ui->plainTextEditRadius->toPlainText();
294     formulaData.variables = data->DataVariables();
295     formulaData.labelEditFormula = ui->labelEditRadius;
296     formulaData.labelResult = ui->labelResultCircleRadius;
297     formulaData.postfix = UnitsToStr(VAbstractValApplication::VApp()->patternUnits(), true);
298 
299     const qreal radius = Eval(formulaData, flagCircleRadius);
300 
301     if (radius < 0)
302     {
303         flagCircleRadius = false;
304         ChangeColor(ui->labelEditRadius, errorColor);
305         ui->labelResultCircleRadius->setText(tr("Error"));
306         ui->labelResultCircleRadius->setToolTip(tr("Radius can't be negative"));
307 
308         DialogPointFromCircleAndTangent::CheckState();
309     }
310 }
311 
312 //---------------------------------------------------------------------------------------------------------------------
ShowVisualization()313 void DialogPointFromCircleAndTangent::ShowVisualization()
314 {
315     AddVisualization<VisToolPointFromCircleAndTangent>();
316 }
317 
318 //---------------------------------------------------------------------------------------------------------------------
SaveData()319 void DialogPointFromCircleAndTangent::SaveData()
320 {
321     pointName = ui->lineEditNamePoint->text();
322 
323     VisToolPointFromCircleAndTangent *point = qobject_cast<VisToolPointFromCircleAndTangent *>(vis);
324     SCASSERT(point != nullptr)
325 
326     point->setObject1Id(GetTangentPointId());
327     point->setObject2Id(GetCircleCenterId());
328     point->setCRadius(ui->plainTextEditRadius->toPlainText());
329     point->setCrossPoint(GetCrossCirclesPoint());
330     point->RefreshGeometry();
331 }
332 
333 //---------------------------------------------------------------------------------------------------------------------
closeEvent(QCloseEvent * event)334 void DialogPointFromCircleAndTangent::closeEvent(QCloseEvent *event)
335 {
336     ui->plainTextEditRadius->blockSignals(true);
337     DialogTool::closeEvent(event);
338 }
339 
340 //---------------------------------------------------------------------------------------------------------------------
SetNotes(const QString & notes)341 void DialogPointFromCircleAndTangent::SetNotes(const QString &notes)
342 {
343     ui->plainTextEditToolNotes->setPlainText(notes);
344 }
345 
346 //---------------------------------------------------------------------------------------------------------------------
GetNotes() const347 QString DialogPointFromCircleAndTangent::GetNotes() const
348 {
349     return ui->plainTextEditToolNotes->toPlainText();
350 }
351