Engauge Digitizer 2
Loading...
Searching...
No Matches
DlgEditPointAxis.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include "DlgEditPointAxis.h"
11#include "DocumentModelCoords.h"
13#include "EngaugeAssert.h"
14#include "FormatCoordsUnits.h"
15#include "FormatDateTime.h"
18#include "Logger.h"
19#include "MainWindow.h"
20#include "MainWindowModel.h"
21#include <QDoubleValidator>
22#include <QGridLayout>
23#include <QGroupBox>
24#include <QHBoxLayout>
25#include <QLabel>
26#include <QLineEdit>
27#include <QRect>
28#include "QtToString.h"
29#include <QVBoxLayout>
30#include "Transformation.h"
31
32const Qt::Alignment ALIGNMENT = Qt::AlignCenter;
33
35
36const bool IS_X_THETA = true;
37const bool IS_NOT_X_THETA = false;
38
40 const DocumentModelCoords &modelCoords,
41 const DocumentModelGeneral &modelGeneral,
42 const MainWindowModel &modelMainWindow,
43 const Transformation &transformation,
44 DocumentAxesPointsRequired documentAxesPointsRequired,
45 bool isXOnly,
46 const double *xInitialValue,
47 const double *yInitialValue) :
48 QDialog (&mainWindow),
49 m_documentAxesPointsRequired (documentAxesPointsRequired),
50 m_modelCoords (modelCoords),
51 m_modelGeneral (modelGeneral),
52 m_modelMainWindow (modelMainWindow)
53{
54 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::DlgEditPointAxis";
55
56 // Either one or two coordinates are desired
57 bool isX = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || isXOnly;
58 bool isY = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) || !isXOnly;
59
60 QVBoxLayout *layout = new QVBoxLayout;
61 setLayout (layout);
62
63 setCursor (QCursor (Qt::ArrowCursor));
64 setModal(true);
65 setWindowTitle (tr ("Edit Axis Point"));
66
67 createCoords (layout);
68 createHints (layout,
69 documentAxesPointsRequired);
70 createOkCancel (layout);
71
72 initializeGraphCoordinates (xInitialValue,
73 yInitialValue,
74 transformation,
75 isX,
76 isY);
77
78 updateControls ();
79}
80
82{
83 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::~DlgEditPointAxis";
84}
85
86void DlgEditPointAxis::createCoords (QVBoxLayout *layoutOuter)
87{
88 // Constraints on x and y are needed for log scaling
89 bool isConstraintX = (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LOG);
90 bool isConstraintY = (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LOG);
91 DlgValidatorFactory dlgValidatorFactory;
92 m_validatorGraphX = dlgValidatorFactory.createCartesianOrPolarWithPolarPolar (m_modelCoords.coordScaleXTheta(),
93 isCartesian (),
94 m_modelCoords.coordUnitsX(),
95 m_modelCoords.coordUnitsTheta(),
96 m_modelCoords.coordUnitsDate(),
97 m_modelCoords.coordUnitsTime(),
98 m_modelMainWindow.locale());
99 m_validatorGraphY = dlgValidatorFactory.createCartesianOrPolarWithNonPolarPolar (m_modelCoords.coordScaleYRadius(),
100 isCartesian (),
101 m_modelCoords.coordUnitsY(),
102 m_modelCoords.coordUnitsRadius(),
103 m_modelCoords.coordUnitsDate(),
104 m_modelCoords.coordUnitsTime(),
105 m_modelMainWindow.locale());
106
107 // Label, with guidance in terms of legal ranges and units
108 QString description = QString ("%1 (%2, %3)%4%5%6%7%8%9 %10 (%11, %12):")
109 .arg (tr ("Graph Coordinates"))
110 .arg (nameXTheta ())
111 .arg (nameYRadius ())
112 .arg (isConstraintX || isConstraintY ? " with " : "")
113 .arg (isConstraintX ? QString (nameXTheta ()) : "")
114 .arg (isConstraintX ? " > 0" : "")
115 .arg (isConstraintX && isConstraintY ? " and " : "")
116 .arg ( isConstraintY ? QString (nameYRadius ()) : "")
117 .arg ( isConstraintY ? " > 0" : "")
118 .arg (tr ("as"))
119 .arg (unitsType (IS_X_THETA))
120 .arg (unitsType (IS_NOT_X_THETA));
121 QGroupBox *panel = new QGroupBox (description, this);
122 layoutOuter->addWidget (panel);
123
124 QHBoxLayout *layout = new QHBoxLayout (panel);
125 panel->setLayout (layout);
126
127 // Row
128 QLabel *labelGraphParLeft = new QLabel (tr ("("), this);
129 layout->addWidget(labelGraphParLeft, 0);
130
131 m_editGraphX = new QLineEdit;
132 m_editGraphX->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
133 m_editGraphX->setAlignment (ALIGNMENT);
134 m_editGraphX->setValidator (m_validatorGraphX);
135 // setStatusTip does not work for modal dialogs
136 m_editGraphX->setWhatsThis (tr ("Enter the first graph coordinate of the axis point.\n\n"
137 "For cartesian plots this is X. For polar plots this is the angle Theta.\n\n"
138 "The expected format of the coordinate value is determined by the locale setting. If "
139 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
140 layout->addWidget(m_editGraphX, 0);
141 connect (m_editGraphX, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
142
143 QLabel *labelGraphComma = new QLabel (tr (", "), this);
144 layout->addWidget(labelGraphComma, 0);
145
146 m_editGraphY = new QLineEdit;
147 m_editGraphY->setMinimumWidth(MIN_WIDTH_TO_FIT_STRANGE_UNITS);
148 m_editGraphY->setAlignment (ALIGNMENT);
149 m_editGraphY->setValidator (m_validatorGraphY);
150 // setStatusTip does not work for modal dialogs
151 m_editGraphY->setWhatsThis (tr ("Enter the second graph coordinate of the axis point.\n\n"
152 "For cartesian plots this is Y. For polar plots this is the radius R.\n\n"
153 "The expected format of the coordinate value is determined by the locale setting. If "
154 "typed values are not recognized as expected, check the locale setting in Settings / Main Window..."));
155 layout->addWidget(m_editGraphY, 0);
156 connect (m_editGraphY, SIGNAL (textChanged (const QString &)), this, SLOT (slotTextChanged (const QString &)));
157
158 QLabel *labelGraphParRight = new QLabel (tr (")"), this);
159 layout->addWidget(labelGraphParRight, 0);
160}
161
162void DlgEditPointAxis::createHints (QVBoxLayout *layoutOuter,
163 DocumentAxesPointsRequired documentAxesPointsRequired)
164{
165 // Insert:
166 // 1) a hint to advertise that axes with only one coordinate can be handled
167 // 2) a hint explaining why decimal points may not be accepted. Very confusing for user to figure out the problem at first, and
168 // then figure out which setting should change to fix it. The hint is centered so it is slightly less intrusive
169
170 const int MIN_EDIT_WIDTH = 180;
171
172 QWidget *widget = new QWidget;
173 layoutOuter->addWidget (widget, 0, Qt::AlignCenter);
174
175 QGridLayout *layout = new QGridLayout;
176 widget->setLayout (layout);
177 int row = 0;
178
179 // Hint 1
180 QLabel *labelNumberCoordinates = new QLabel (tr ("Number of coordinates per axis point:"));
181 layout->addWidget (labelNumberCoordinates, row, 0, 1, 1);
182 QLineEdit *editNumberCoordinates = new QLineEdit;
183 editNumberCoordinates->setWhatsThis (tr ("Three axis points with two coordinates each are normally used. "
184 "If each axis point has only one known coordinate, then start over "
185 "with File / Import (Advanced) / 4 Axis Points."));
186 editNumberCoordinates->setReadOnly (true);
187 editNumberCoordinates->setText (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3 ?
188 "2" :
189 "1");
190 editNumberCoordinates->setMinimumWidth (MIN_EDIT_WIDTH);
191 layout->addWidget (editNumberCoordinates, row++, 1, 1, 1);
192
193 // Hint 2
194 QLabel *labelLocale = new QLabel (tr ("Number format:"));
195 layout->addWidget (labelLocale, row, 0, 1, 1);
196 QLineEdit *editLocale = new QLineEdit;
197 editLocale->setWhatsThis (tr ("Locale which determines the allowed number formats. This is set by Settings / Main Window."));
198 editLocale->setReadOnly (true);
199 QString locale = QLocaleToString (m_modelMainWindow.locale ());
200 editLocale->setText (locale);
201 editLocale->setMinimumWidth (MIN_EDIT_WIDTH);
202 layout->addWidget (editLocale, row++, 1, 1, 1);
203}
204
205void DlgEditPointAxis::createOkCancel (QVBoxLayout *layoutOuter)
206{
207 QWidget *panel = new QWidget (this);
208 layoutOuter->addWidget (panel, 0, Qt::AlignCenter);
209
210 QHBoxLayout *layout = new QHBoxLayout (panel);
211 panel->setLayout (layout);
212
213 m_btnOk = new QPushButton (tr ("Ok"), this);
214 layout->addWidget(m_btnOk);
215 connect (m_btnOk, SIGNAL (released ()), this, SLOT (accept ()));
216
217 m_btnCancel = new QPushButton (tr ("Cancel"), this);
218 layout->addWidget(m_btnCancel);
219 connect (m_btnCancel, SIGNAL (released ()), this, SLOT (reject ()));
220}
221
222void DlgEditPointAxis::initializeGraphCoordinates (const double *xInitialValue,
223 const double *yInitialValue,
224 const Transformation &transformation,
225 bool isX,
226 bool isY)
227{
228 LOG4CPP_INFO_S ((*mainCat)) << "DlgEditPointAxis::initializeGraphCoordinates";
229
230 QString xTheta, yRadius;
231 if ((xInitialValue != nullptr) &&
232 (yInitialValue != nullptr)) {
233
234 FormatCoordsUnits format;
235 format.unformattedToFormatted (*xInitialValue,
236 *yInitialValue,
237 m_modelCoords,
238 m_modelGeneral,
239 m_modelMainWindow,
240 xTheta,
241 yRadius,
242 transformation);
243 }
244
245 if (isX) {
246 m_editGraphX->setText (xTheta);
247 } else {
248 m_editGraphX->setText ("");
249 }
250
251 if (isY) {
252 m_editGraphY->setText (yRadius);
253 } else {
254 m_editGraphY->setText ("");
255 }
256}
257
258bool DlgEditPointAxis::isCartesian () const
259{
260 return (m_modelCoords.coordsType() == COORDS_TYPE_CARTESIAN);
261}
262
263QChar DlgEditPointAxis::nameXTheta () const
264{
265 return (isCartesian () ? QChar ('X') : THETA);
266}
267
268QChar DlgEditPointAxis::nameYRadius () const
269{
270 return (isCartesian () ? QChar ('Y') : QChar ('R'));
271}
272
273QPointF DlgEditPointAxis::posGraph (bool &isXOnly) const
274{
275 double xTheta, yRadius;
276
277 FormatCoordsUnits format;
278
279 format.formattedToUnformatted (m_editGraphX->text(),
280 m_editGraphY->text(),
281 m_modelCoords,
282 m_modelMainWindow,
283 xTheta,
284 yRadius);
285
286 // If yRadius value is empty then this is the xTheta value only
287 isXOnly = m_editGraphY->text().isEmpty();
288
289 return QPointF (xTheta,
290 yRadius);
291}
292
293void DlgEditPointAxis::slotTextChanged (const QString &)
294{
295 updateControls ();
296}
297
298QString DlgEditPointAxis::unitsType (bool isXTheta) const
299{
300 if (isCartesian ()) {
301 if (isXTheta) {
302 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsX());
303 } else {
304 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsY());
305 }
306 } else {
307 if (isXTheta) {
308 return coordUnitsPolarThetaToBriefType (m_modelCoords.coordUnitsTheta());
309 } else {
310 return coordUnitsNonPolarThetaToBriefType (m_modelCoords.coordUnitsRadius());
311 }
312 }
313}
314
315void DlgEditPointAxis::updateControls ()
316{
317 QString textX = m_editGraphX->text();
318 QString textY = m_editGraphY->text();
319
320 int posX, posY;
321
322 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_4) {
323
324 bool gotX = (!textX.isEmpty() &&
325 (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable));
326 bool gotY = (!textY.isEmpty() &&
327 (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
328
329 // Check for not empty in one coordinate and for valid number in the other coordinate
330 m_btnOk->setEnabled ((textX.isEmpty() && gotY) ||
331 (textY.isEmpty() && gotX));
332
333 // Emphasize that only one coordinate is to be filled in at a time
334 m_editGraphX->setEnabled (!gotY);
335 m_editGraphY->setEnabled (!gotX);
336
337 } else {
338
339 // Check for not empty (which allows single minus sign) and for valid number (which prevents single minus sign)
340 m_btnOk->setEnabled (!textX.isEmpty () &&
341 !textY.isEmpty () &&
342 (m_validatorGraphX->validate(textX, posX) == QValidator::Acceptable) &&
343 (m_validatorGraphY->validate(textY, posY) == QValidator::Acceptable));
344
345 }
346}
@ COORD_SCALE_LOG
Definition CoordScale.h:14
const QChar THETA
QString coordUnitsNonPolarThetaToBriefType(CoordUnitsNonPolarTheta coordUnits)
QString coordUnitsPolarThetaToBriefType(CoordUnitsPolarTheta coordUnits)
@ COORDS_TYPE_CARTESIAN
Definition CoordsType.h:13
const bool IS_X_THETA
const Qt::Alignment ALIGNMENT
const int MIN_WIDTH_TO_FIT_STRANGE_UNITS
const bool IS_NOT_X_THETA
const int MIN_EDIT_WIDTH
@ DOCUMENT_AXES_POINTS_REQUIRED_3
@ DOCUMENT_AXES_POINTS_REQUIRED_4
log4cpp::Category * mainCat
Definition Logger.cpp:14
QString QLocaleToString(const QLocale &locale)
QPointF posGraph(bool &isXOnly) const
Return the graph coordinates position specified by the user. Only applies if dialog was accepted.
DlgEditPointAxis(MainWindow &mainWindow, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &modelMainWindow, const Transformation &transformation, DocumentAxesPointsRequired documentAxesPointsRequired, bool isXOnly=false, const double *xInitialValue=0, const double *yInitialValue=0)
Constructor for existing point which already has graph coordinates (which may be changed using this d...
Validator factory.
DlgValidatorAbstract * createCartesianOrPolarWithPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
DlgValidatorAbstract * createCartesianOrPolarWithNonPolarPolar(CoordScale coordScale, bool isCartesian, CoordUnitsNonPolarTheta coordUnitsCartesian, CoordUnitsNonPolarTheta coordUnitsPolar, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators for either cartesian or polar case, when polar format is spe...
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordUnitsNonPolarTheta coordUnitsRadius() const
Get method for radius units.
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
CoordUnitsNonPolarTheta coordUnitsY() const
Get method for x units.
CoordUnitsTime coordUnitsTime() const
Get method for time format when used.
CoordUnitsNonPolarTheta coordUnitsX() const
Get method for x units.
CoordUnitsDate coordUnitsDate() const
Get method for date format when used.
Model for DlgSettingsGeneral and CmdSettingsGeneral.
Highest-level wrapper around other Formats classes.
void formattedToUnformatted(const QString &xThetaFormatted, const QString &yRadiusFormatted, const DocumentModelCoords &modelCoords, const MainWindowModel &mainWindowModel, double &xThetaUnformatted, double &yRadiusUnformatted) const
Convert formatted string to unformatted numeric value.
void unformattedToFormatted(double xThetaUnformatted, double yRadiusUnformatted, const DocumentModelCoords &modelCoords, const DocumentModelGeneral &modelGeneral, const MainWindowModel &mainWindowModel, QString &xThetaFormatted, QString &yRadiusFormatted, const Transformation &transformation) const
Convert unformatted numeric value to formatted string. Transformation is used to determine best resol...
Model for DlgSettingsMainWindow.
QLocale locale() const
Get method for locale.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition MainWindow.h:95
Affine transformation between screen and graph coordinates, based on digitized axis points.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18