Engauge Digitizer  2
 All Classes Functions Variables Typedefs Enumerations Friends Pages
DlgSettingsCoords.cpp
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 "CallbackBoundingRects.h"
8 #include "CmdMediator.h"
9 #include "CmdSettingsCoords.h"
10 #include "CoordUnitsDate.h"
11 #include "CoordUnitsTime.h"
12 #include "DlgSettingsCoords.h"
13 #include "DlgValidatorAbstract.h"
14 #include "DlgValidatorFactory.h"
15 #include "DocumentModelCoords.h"
16 #include "EngaugeAssert.h"
17 #include "Logger.h"
18 #include "MainWindow.h"
19 #include <math.h>
20 #include <QComboBox>
21 #include <QDebug>
22 #include <QDoubleValidator>
23 #include <QGraphicsRectItem>
24 #include <QGridLayout>
25 #include <QGroupBox>
26 #include <QGraphicsScene>
27 #include <QLabel>
28 #include <QLineEdit>
29 #include <qmath.h>
30 #include <QPalette>
31 #include <QRadioButton>
32 #include <QStackedWidget>
33 #include <QVBoxLayout>
34 #include "Transformation.h"
35 #include "ViewPreview.h"
36 
37 const QString OVERRIDDEN_VALUE(""); // Values are overridden in updateControls
38 
39 const int COLUMN_0 = 0;
40 const int COLUMN_1 = 1;
41 
42 const int STEPS_PER_CYCLE = 4; // Repeat STEPS_PER_CYLE-1 unhighlighted steps plus 1 highlighted step in each cycle
43 const int STEPS_CYCLE_COUNT = 4; // Repeat one highlighted step + STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED steps this many times
44 const int NUM_COORD_STEPS = 1 + STEPS_PER_CYCLE * STEPS_CYCLE_COUNT;
45 
46 const int MAX_WIDTH_EDIT_ORIGIN_RADIUS = 140;
47 
48 const int CARTESIAN_COORD_MAX = 100;
49 const int CARTESIAN_COORD_MIN = -100;
50 const double CARTESIAN_COORD_STEP = (CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN) / (NUM_COORD_STEPS - 1.0);
51 
52 const int POLAR_RADIUS = CARTESIAN_COORD_MAX;
53 const double POLAR_STEP = POLAR_RADIUS / (NUM_COORD_STEPS - 1.0);
54 
55 const int POLAR_THETA_MAX = 360;
56 const int POLAR_THETA_MIN = 0;
57 const double POLAR_THETA_STEP = (POLAR_THETA_MAX - POLAR_THETA_MIN) / (NUM_COORD_STEPS - 1.0);
58 
59 const double XCENTER = (CARTESIAN_COORD_MIN + CARTESIAN_COORD_MAX) / 2.0;
60 const double YCENTER = (CARTESIAN_COORD_MIN + CARTESIAN_COORD_MAX) / 2.0;
61 
62 const double LINE_WIDTH_THIN = 0.0;
63 const double LINE_WIDTH_THICK = 2.0;
64 
65 const double PI = 3.1415926535;
66 const double DEG_2_RAD = PI / 180.0;
67 
68 const int FONT_SIZE = 6;
69 
70 const double POWER_FOR_LOG = 10.0; // Need a larger power (certainly more than e) to make log gradient obvious
71 
72 const int MINIMUM_DIALOG_WIDTH_COORDS = 800;
73 const int MINIMUM_HEIGHT = 540;
74 
76  DlgSettingsAbstractBase (tr ("Coordinates"),
77  "DlgSettingsCoords",
78  mainWindow),
79  m_btnCartesian (nullptr),
80  m_btnPolar (nullptr),
81  m_validatorOriginRadius (nullptr),
82  m_cmbDate (nullptr),
83  m_cmbTime (nullptr),
84  m_scenePreview (nullptr),
85  m_viewPreview (nullptr),
86  m_modelCoordsBefore (nullptr),
87  m_modelCoordsAfter (nullptr)
88 {
89  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::DlgSettingsCoords";
90 
91  QWidget *subPanel = createSubPanel ();
92  finishPanel (subPanel,
93  MINIMUM_DIALOG_WIDTH_COORDS);
94 }
95 
96 DlgSettingsCoords::~DlgSettingsCoords()
97 {
98  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::~DlgSettingsCoords";
99 }
100 
101 void DlgSettingsCoords::annotateAngles (const QFont &defaultFont) {
102 
103  // 0=+x, 1=+y, 2=-x, 3=-y
104  for (int direction = 0; direction < 4; direction++) {
105 
106  QString angle;
107  CoordUnitsPolarTheta thetaUnits = static_cast<CoordUnitsPolarTheta> (m_cmbXThetaUnits->currentData().toInt());
108 
109  switch (thetaUnits) {
110  case COORD_UNITS_POLAR_THETA_DEGREES:
111  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
112  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
113  angle = QString::number (90.0 * direction);
114  break;
115 
116  case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
117  angle = QString::number (90.0 * direction);
118  if (direction == 1) {
119  angle = "90E";
120  } else if (direction == 3) {
121  angle = "90W";
122  }
123  break;
124 
125  case COORD_UNITS_POLAR_THETA_GRADIANS:
126  angle = QString::number (100.0 * direction);
127  break;
128 
129  case COORD_UNITS_POLAR_THETA_RADIANS:
130  {
131  static QString radiansUnits [] = {"0", "PI / 2", "PI", "3 * PI / 2"};
132  ENGAUGE_ASSERT (direction < 4);
133  angle = radiansUnits [direction];
134  }
135  break;
136 
137  case COORD_UNITS_POLAR_THETA_TURNS:
138  {
139  static QString turnsUnits [] = {"0", "1 / 4", "1 / 2", "3 / 4"};
140  ENGAUGE_ASSERT (direction < 4);
141  angle = turnsUnits [direction];
142  }
143  break;
144 
145  default:
146  break;
147  }
148 
149  QGraphicsTextItem *textAngle = m_scenePreview->addText (angle);
150  textAngle->setFont (QFont (defaultFont.defaultFamily(), FONT_SIZE));
151  double x = 0, y = 0; // Initialized to prevent compiler warning
152  switch (direction) {
153  case 0:
154  x = CARTESIAN_COORD_MAX - textAngle->boundingRect().width ();
155  break;
156  case 1:
157  case 3:
158  x = XCENTER - textAngle->boundingRect().width () / 2.0;
159  break;
160  case 2:
161  x = CARTESIAN_COORD_MIN;
162  break;
163  }
164  switch (direction) {
165  case 0:
166  case 2:
167  y = YCENTER;
168  break;
169  case 1:
170  y = CARTESIAN_COORD_MIN;
171  break;
172  case 3:
173  y = CARTESIAN_COORD_MAX - textAngle->boundingRect().height ();
174  break;
175  }
176 
177  textAngle->setPos (x, y);
178  }
179 }
180 
181 void DlgSettingsCoords::annotateRadiusAtOrigin(const QFont &defaultFont) {
182 
183  QGraphicsTextItem *textRadius = m_scenePreview->addText (m_editOriginRadius->text());
184  textRadius->setFont (QFont (defaultFont.defaultFamily(), FONT_SIZE));
185  textRadius->setPos (XCENTER - textRadius->boundingRect().width () / 2.0,
186  YCENTER);
187 }
188 
189 void DlgSettingsCoords::boundingRectGraph (CmdMediator &cmdMediator,
190  bool &isEmpty,
191  QPointF &boundingRectGraphMin,
192  QPointF &boundingRectGraphMax) const
193 {
196 
197  Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
199 
200  // There may or may one, two or three axis points. Even if all three are not defined (so
201  // transformation is not defined), we can still get coordinates if there are one or two
202  cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
203 
204  // If the transformation is not defined, then there are no graph coordinates to extract
205  // from the graph curves (and probably trigger an assert)
206  if (mainWindow().transformIsDefined()) {
207  cmdMediator.iterateThroughCurvesPointsGraphs (ftorWithCallback);
208  }
209 
210  boundingRectGraphMin = ftor.boundingRectGraphMin (isEmpty);
211  boundingRectGraphMax = ftor.boundingRectGraphMax (isEmpty);
212 }
213 
214 void DlgSettingsCoords::createDateTime (QGridLayout *layout,
215  int &row)
216 {
217  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createDateTime";
218 
219  QLabel *label = new QLabel(QString ("%1:").arg (tr ("Date/Time")));
220  layout->addWidget (label, row, 1);
221 
222  QWidget *widgetCombos = new QWidget;
223  layout->addWidget (widgetCombos, row++, 2);
224  QHBoxLayout *layoutCombos = new QHBoxLayout;
225  widgetCombos->setLayout (layoutCombos);
226 
227  // Put date and time comboboxes into same widget
228  m_cmbDate = new QComboBox;
229  m_cmbDate->setWhatsThis (tr ("Date format to be used for date values, and date portion of mixed date/time values, "
230  "during input and output.\n\n"
231  "Setting the format to an empty value results in just the time portion appearing in output."));
232  connect (m_cmbDate, SIGNAL (activated (const QString &)), this, SLOT (slotDate (const QString &)));
233  layoutCombos->addWidget (m_cmbDate);
234 
235  m_cmbTime = new QComboBox;
236  m_cmbTime->setWhatsThis (tr ("Time format to be used for time values, and time portion of mixed date/time values, "
237  "during input and output.\n\n"
238  "Setting the format to an empty value results in just the date portion appearing in output."));
239  connect (m_cmbTime, SIGNAL (activated (const QString &)), this, SLOT (slotTime (const QString &)));
240  layoutCombos->addWidget (m_cmbTime);
241 }
242 
243 void DlgSettingsCoords::createGroupCoordsType (QGridLayout *layout,
244  int &row)
245 {
246  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupCoordsType";
247 
248  m_boxCoordsType = new QGroupBox(tr ("Coordinates Types"));
249  layout->addWidget (m_boxCoordsType, row++, 1, 1, 2);
250 
251  QVBoxLayout *layoutGroup = new QVBoxLayout (m_boxCoordsType);
252 
253  QString polarButtonText = QString(tr ("Polar") + " (") + THETA + QString(", " + tr ("R") + ")");
254 
255  m_btnCartesian = new QRadioButton (tr ("Cartesian (X, Y)"), m_boxCoordsType);
256  m_btnCartesian->setWhatsThis (QString(tr("Select cartesian coordinates.\n\n"
257  "The X and Y coordinates will be used")));
258  connect (m_btnCartesian, SIGNAL (toggled(bool)), this, SLOT (slotCartesianPolar (bool)));
259  layoutGroup->addWidget (m_btnCartesian);
260 
261  m_btnPolar = new QRadioButton (polarButtonText, m_boxCoordsType);
262  m_btnPolar->setWhatsThis (QString(tr("Select polar coordinates.\n\n"
263  "The Theta and R coordinates will be used.\n\n"
264  "Polar coordinates are not allowed with log scale for Theta")));
265  connect (m_btnPolar, SIGNAL (toggled(bool)), this, SLOT (slotCartesianPolar (bool)));
266  layoutGroup->addWidget (m_btnPolar);
267 }
268 
269 void DlgSettingsCoords::createGroupXTheta (QGridLayout *layout,
270  int &row)
271 {
272  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupXTheta";
273 
274  m_boxXTheta = new QGroupBox(OVERRIDDEN_VALUE);
275  layout->addWidget (m_boxXTheta, row, 1, 1, 1);
276 
277  QGridLayout *layoutXTheta = new QGridLayout (m_boxXTheta);
278  m_boxXTheta->setLayout (layoutXTheta);
279  int rowGroup = 0;
280 
281  QLabel *labelScale = new QLabel (QString ("%1:").arg (tr ("Scale")));
282  layoutXTheta->addWidget (labelScale, rowGroup++, COLUMN_0);
283 
284  m_xThetaLinear = new QRadioButton (tr ("Linear"), m_boxXTheta);
285  m_xThetaLinear->setWhatsThis (QString(tr("Specifies linear scale for the X or Theta coordinate")));
286  connect (m_xThetaLinear, SIGNAL (released ()), this, SLOT (slotXThetaLinear()));
287  layoutXTheta->addWidget (m_xThetaLinear, rowGroup++, COLUMN_0);
288 
289  m_xThetaLog = new QRadioButton (tr ("Log"), m_boxXTheta);
290  m_xThetaLog->setWhatsThis (QString(tr("Specifies logarithmic scale for the X or Theta coordinate.\n\n"
291  "Log scale is not allowed if there are negative coordinates.\n\n"
292  "Log scale is not allowed for the Theta coordinate.")));
293  connect (m_xThetaLog, SIGNAL (released ()), this, SLOT (slotXThetaLog()));
294  layoutXTheta->addWidget (m_xThetaLog, rowGroup++, COLUMN_0);
295 
296  QLabel *labelThetaUnits = new QLabel(QString ("%1:").arg (tr ("Units")));
297  layoutXTheta->addWidget (labelThetaUnits, rowGroup++, COLUMN_0);
298 
299  m_cmbXThetaUnits = new QComboBox;
300  connect (m_cmbXThetaUnits, SIGNAL (activated (const QString &)), this, SLOT (slotUnitsXTheta(const QString &))); // activated() ignores code changes
301  layoutXTheta->addWidget (m_cmbXThetaUnits, rowGroup++, COLUMN_0, 1, 2);
302 }
303 
304 void DlgSettingsCoords::createGroupYRadius (QGridLayout *layout,
305  int &row)
306 {
307  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createGroupYRadius";
308 
309  m_boxYRadius = new QGroupBox (OVERRIDDEN_VALUE);
310  layout->addWidget (m_boxYRadius, row++, 2, 1, 1);
311 
312  QGridLayout *layoutYRadius = new QGridLayout (m_boxYRadius);
313  m_boxYRadius->setLayout (layoutYRadius);
314  int rowGroup = 0;
315 
316  QLabel *labelScale = new QLabel (QString ("%1:").arg (tr ("Scale")));
317  layoutYRadius->addWidget (labelScale, rowGroup++, COLUMN_0);
318 
319  m_yRadiusLinear = new QRadioButton (tr ("Linear"), m_boxYRadius);
320  m_yRadiusLinear->setWhatsThis (QString(tr("Specifies linear scale for the Y or R coordinate")));
321  connect (m_yRadiusLinear, SIGNAL(released()), this, SLOT (slotYRadiusLinear()));
322  layoutYRadius->addWidget (m_yRadiusLinear, rowGroup, COLUMN_0);
323 
324  QLabel *labelOriginRadius = new QLabel(QString ("%1:").arg (tr ("Origin radius value")));
325  layoutYRadius->addWidget (labelOriginRadius, rowGroup++, COLUMN_1);
326 
327  m_yRadiusLog = new QRadioButton (tr ("Log"), m_boxYRadius);
328  m_yRadiusLog->setWhatsThis (QString(tr("Specifies logarithmic scale for the Y or R coordinate\n\n"
329  "Log scale is not allowed if there are negative coordinates.")));
330  connect (m_yRadiusLog, SIGNAL(released ()), this, SLOT (slotYRadiusLog ()));
331  layoutYRadius->addWidget (m_yRadiusLog, rowGroup, COLUMN_0);
332 
333  m_editOriginRadius = new QLineEdit (m_boxYRadius);
334  m_editOriginRadius->setMaximumWidth (MAX_WIDTH_EDIT_ORIGIN_RADIUS);
335  m_editOriginRadius->setWhatsThis (QString(tr("Specify radius value at origin.\n\n"
336  "Normally the radius at the origin is 0, but a nonzero value may be applied in other cases "
337  "(like when the radial units are decibels).")));
338  connect (m_editOriginRadius, SIGNAL (textChanged (const QString &)), this, SLOT (slotPolarOriginRadius(const QString &)));
339  layoutYRadius->addWidget (m_editOriginRadius, rowGroup++, COLUMN_1);
340 
341  QLabel *labelUnits = new QLabel(QString ("%1:").arg (tr ("Units")));
342  layoutYRadius->addWidget (labelUnits, rowGroup++, COLUMN_0);
343 
344  m_cmbYRadiusUnits = new QComboBox;
345  connect (m_cmbYRadiusUnits, SIGNAL (activated (const QString &)), this, SLOT (slotUnitsYRadius(const QString &))); // activated() ignores code changes
346  layoutYRadius->addWidget (m_cmbYRadiusUnits, rowGroup++, COLUMN_0, 1, 2);
347 }
348 
349 void DlgSettingsCoords::createOptionalSaveDefault (QHBoxLayout * /* layout */)
350 {
351 }
352 
353 void DlgSettingsCoords::createPreview (QGridLayout *layout,
354  int &row)
355 {
356  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createPreview";
357 
358  QLabel *labelPreview = new QLabel (tr ("Preview"));
359  layout->addWidget (labelPreview, row++, 0, 1, 4);
360 
361  m_scenePreview = new QGraphicsScene (this);
362  m_viewPreview = new ViewPreview (m_scenePreview,
363  ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
364  this);
365  m_viewPreview->setWhatsThis (tr ("Preview window that shows how current settings affect the coordinate system."));
366  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
367  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
368  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
369 
370  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
371 }
372 
374 {
375  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::createSubPanel";
376 
377  QWidget *subPanel = new QWidget ();
378 
379  QGridLayout *layout = new QGridLayout (subPanel);
380  subPanel->setLayout (layout);
381 
382  layout->setColumnStretch(0, 1); // Empty first column
383  layout->setColumnStretch(1, 0); // Labels
384  layout->setColumnStretch(2, 0); // User controls
385  layout->setColumnStretch(3, 1); // Empty last column
386 
387  int row = 0;
388  createGroupCoordsType(layout, row);
389  createGroupXTheta (layout, row);
390  createGroupYRadius (layout, row);
391  createDateTime (layout, row);
392  createPreview (layout, row);
393 
394  return subPanel;
395 }
396 
397 void DlgSettingsCoords::drawCartesianLinearX ()
398 {
399  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLinearX";
400 
401  bool isAxis = true;
402  for (int step = 0; step < NUM_COORD_STEPS; step++) {
403  double x = CARTESIAN_COORD_MIN + step * CARTESIAN_COORD_STEP;
404  QGraphicsLineItem *line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
405  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
406  line->setPen(QPen (QBrush ((isHighlighted ? Qt::gray : Qt::lightGray)),
407  LINE_WIDTH_THIN,
408  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
409  if (isAxis) {
410  line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
411  line->setPen(QPen (QBrush (Qt::black),
412  LINE_WIDTH_THICK));
413  }
414  isAxis = false;
415  }
416 }
417 
418 void DlgSettingsCoords::drawCartesianLinearY ()
419 {
420  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLinearY";
421 
422  bool isAxis = true;
423  for (int step = NUM_COORD_STEPS - 1; step >= 0; step--) {
424  double y = CARTESIAN_COORD_MIN + step * CARTESIAN_COORD_STEP;
425  QGraphicsLineItem *line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
426  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
427  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
428  LINE_WIDTH_THIN,
429  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
430  if (isAxis) {
431  line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
432  line->setPen(QPen (QBrush (Qt::black),
433  LINE_WIDTH_THICK));
434  }
435  isAxis = false;
436  }
437 }
438 
439 void DlgSettingsCoords::drawCartesianLogX ()
440 {
441  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLogX";
442 
443  bool isAxis = true;
444  for (int step = 0; step < NUM_COORD_STEPS; step++) {
445  double s = (exp (step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
446  (exp (1.0) - 1.0);
447  double x = (1.0 - s) * CARTESIAN_COORD_MIN + s * CARTESIAN_COORD_MAX;
448  QGraphicsLineItem *line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
449  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
450  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
451  LINE_WIDTH_THIN,
452  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
453  if (isAxis) {
454  line = m_scenePreview->addLine (x, CARTESIAN_COORD_MIN, x, CARTESIAN_COORD_MAX);
455  line->setPen(QPen (QBrush (Qt::black),
456  LINE_WIDTH_THICK));
457  }
458  isAxis = false;
459  }
460 }
461 
462 void DlgSettingsCoords::drawCartesianLogY ()
463 {
464  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawCartesianLogY";
465 
466  bool isAxis = true;
467  for (int step = 0; step < NUM_COORD_STEPS; step++) {
468  double s = (pow (POWER_FOR_LOG, step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
469  (pow (POWER_FOR_LOG, 1.0) - 1.0);
470  double y = (1.0 - s) * CARTESIAN_COORD_MAX + s * CARTESIAN_COORD_MIN; // Invert y coordinate (min<->max)
471  QGraphicsLineItem *line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
472  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
473  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
474  LINE_WIDTH_THIN,
475  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
476  if (isAxis) {
477  line = m_scenePreview->addLine (CARTESIAN_COORD_MIN, y, CARTESIAN_COORD_MAX, y);
478  line->setPen(QPen (QBrush (Qt::black),
479  LINE_WIDTH_THICK));
480  }
481  isAxis = false;
482  }
483 }
484 
485 void DlgSettingsCoords::drawPolarLinearRadius ()
486 {
487  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarLinearRadius";
488 
489  for (int step = 0; step < NUM_COORD_STEPS; step++) {
490  double radius = step * POLAR_STEP;
491  QGraphicsEllipseItem *line = m_scenePreview->addEllipse (XCENTER - radius,
492  YCENTER - radius,
493  2.0 * radius,
494  2.0 * radius);
495  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
496  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
497  LINE_WIDTH_THIN,
498  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
499  }
500 }
501 
502 void DlgSettingsCoords::drawPolarLogRadius ()
503 {
504  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarLogRadius";
505 
506  for (int step = 0; step < NUM_COORD_STEPS; step++) {
507  double s = (pow (POWER_FOR_LOG, step / (NUM_COORD_STEPS - 1.0)) - 1.0) /
508  (pow (POWER_FOR_LOG, 1.0) - 1.0);
509  double radius = (s * (NUM_COORD_STEPS - 1.0)) * POLAR_STEP;
510  QGraphicsEllipseItem *line = m_scenePreview->addEllipse (XCENTER - radius,
511  YCENTER - radius,
512  2.0 * radius,
513  2.0 * radius);
514  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
515  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
516  LINE_WIDTH_THIN,
517  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
518  }
519 }
520 
521 void DlgSettingsCoords::drawPolarTheta ()
522 {
523  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::drawPolarTheta";
524 
525  bool isAxis = true;
526  for (int step = 0; step < NUM_COORD_STEPS; step++) {
527  double theta = POLAR_THETA_MIN + step * POLAR_THETA_STEP;
528  double x = POLAR_RADIUS * cos (theta * DEG_2_RAD);
529  double y = POLAR_RADIUS * sin (theta * DEG_2_RAD);
530  QGraphicsLineItem *line = m_scenePreview->addLine (XCENTER, YCENTER, XCENTER + x, YCENTER + y);
531  bool isHighlighted = (step % STEPS_PER_CYCLE == 0);
532  line->setPen(QPen (QBrush (isHighlighted ? Qt::gray : Qt::lightGray),
533  LINE_WIDTH_THIN,
534  (isHighlighted ? Qt::SolidLine : Qt::DashLine)));
535  if (isAxis) {
536  line = m_scenePreview->addLine (XCENTER, YCENTER, XCENTER + x, YCENTER + y);
537  line->setPen(QPen (QBrush (Qt::black),
538  LINE_WIDTH_THICK));
539  }
540  isAxis = false;
541  }
542 }
543 
545 {
546  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::handleOk";
547 
549  cmdMediator ().document(),
550  *m_modelCoordsBefore,
551  *m_modelCoordsAfter);
552  cmdMediator ().push (cmd);
553 
554  hide ();
555 }
556 
558 {
559  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::load";
560 
561  setCmdMediator (cmdMediator);
562 
563  // Remove if coordinates are log so later constraints can be applied
564  bool isEmpty;
565  QPointF boundingRectGraphMin, boundingRectGraphMax;
566  boundingRectGraph (cmdMediator,
567  isEmpty,
568  boundingRectGraphMin,
569  boundingRectGraphMax);
570  bool xThetaGoesNegative = !isEmpty && (boundingRectGraphMin.x() <= 0);
571  bool yRGoesNegative = !isEmpty && (boundingRectGraphMin.y() <= 0);
572  m_xThetaLinear->setEnabled (!xThetaGoesNegative);
573  m_xThetaLog->setEnabled (!xThetaGoesNegative);
574  m_yRadiusLinear->setEnabled (!yRGoesNegative);
575  m_yRadiusLog->setEnabled (!yRGoesNegative);
576 
577  // Flush old data
578  delete m_modelCoordsBefore;
579  delete m_modelCoordsAfter;
580 
581  // Save new data
582  m_modelCoordsBefore = new DocumentModelCoords (cmdMediator.document().modelCoords());
583  m_modelCoordsAfter = new DocumentModelCoords (cmdMediator.document().modelCoords());
584 
585  // Populate controls
586  DlgValidatorFactory dlgValidatorFactory;
587  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (m_modelCoordsAfter->coordScaleYRadius(),
588  m_modelCoordsAfter->coordUnitsRadius(),
589  m_modelCoordsAfter->coordUnitsDate(),
590  m_modelCoordsAfter->coordUnitsTime(),
592  m_editOriginRadius->setValidator (m_validatorOriginRadius); // Set before call to setText so validator is defined in updateControls
593  m_editOriginRadius->setText (QString::number (m_modelCoordsAfter->originRadius ()));
594 
595  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
596  m_btnCartesian->setChecked (true);
597  } else {
598  m_btnPolar->setChecked (true);
599  }
600 
601  updateCoordUnits(); // Call after checking m_btnCartesian or m_btnPolar
602  loadComboBoxDate();
603  loadComboBoxTime ();
604 
605  m_xThetaLinear->setChecked (m_modelCoordsAfter->coordScaleXTheta() == COORD_SCALE_LINEAR);
606  m_xThetaLog->setChecked (m_modelCoordsAfter->coordScaleXTheta() == COORD_SCALE_LOG);
607  m_yRadiusLinear->setChecked (m_modelCoordsAfter->coordScaleYRadius() == COORD_SCALE_LINEAR);
608  m_yRadiusLog->setChecked (m_modelCoordsAfter->coordScaleYRadius() == COORD_SCALE_LOG);
609 
610  updateControls (); // Probably redundant due to the setChecked just above
611  enableOk (false); // Disable Ok button since there not yet any changes
612  updatePreview();
613 }
614 
615 void DlgSettingsCoords::loadComboBoxDate()
616 {
617  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxDate";
618 
619  m_cmbDate->clear ();
620 
621  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_SKIP),
622  QVariant (COORD_UNITS_DATE_SKIP));
623  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_MONTH_DAY_YEAR),
624  QVariant (COORD_UNITS_DATE_MONTH_DAY_YEAR));
625  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_DAY_MONTH_YEAR),
626  QVariant (COORD_UNITS_DATE_DAY_MONTH_YEAR));
627  m_cmbDate->addItem (coordUnitsDateToString (COORD_UNITS_DATE_YEAR_MONTH_DAY),
628  QVariant (COORD_UNITS_DATE_YEAR_MONTH_DAY));
629 
630  ENGAUGE_ASSERT (m_cmbDate->count() == NUM_COORD_UNITS_DATE);
631 
632  int index = m_cmbDate->findData (QVariant (m_modelCoordsAfter->coordUnitsDate()));
633  m_cmbDate->setCurrentIndex (index);
634 }
635 
636 void DlgSettingsCoords::loadComboBoxTime()
637 {
638  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxTime";
639 
640  m_cmbTime->clear ();
641 
642  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_SKIP),
643  QVariant (COORD_UNITS_TIME_SKIP));
644  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_HOUR_MINUTE),
645  QVariant (COORD_UNITS_TIME_HOUR_MINUTE));
646  m_cmbTime->addItem (coordUnitsTimeToString (COORD_UNITS_TIME_HOUR_MINUTE_SECOND),
647  QVariant (COORD_UNITS_TIME_HOUR_MINUTE_SECOND));
648 
649  ENGAUGE_ASSERT (m_cmbTime->count() == NUM_COORD_UNITS_TIME);
650 
651  int index = m_cmbTime->findData (QVariant (m_modelCoordsAfter->coordUnitsTime()));
652  m_cmbTime->setCurrentIndex (index);
653 }
654 
655 void DlgSettingsCoords::loadComboBoxUnitsNonPolar (QComboBox &cmb,
656  CoordUnitsNonPolarTheta coordUnits)
657 {
658  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxUnitsNonPolar";
659 
660  cmb.clear();
661 
662  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_NUMBER),
663  QVariant (COORD_UNITS_NON_POLAR_THETA_NUMBER));
664  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DATE_TIME),
665  QVariant (COORD_UNITS_NON_POLAR_THETA_DATE_TIME));
666  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS),
667  QVariant (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS));
668  cmb.addItem (coordUnitsNonPolarThetaToString (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW),
669  QVariant (COORD_UNITS_NON_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW));
670 
671  ENGAUGE_ASSERT (cmb.count() == NUM_COORD_UNITS_NON_POLAR_THETA);
672 
673  cmb.setWhatsThis (QString (tr ("Numbers have the simplest and most general format.\n\n"
674  "Date and time values have date and/or time components.\n\n"
675  "Degrees Minutes Seconds (DDD MM SS.S) format uses two integer number for degrees and minutes, and a real number for "
676  "seconds. There are 60 seconds per minute. During input, spaces must be inserted between the three numbers.")));
677 
678  int index = cmb.findData (coordUnits);
679  cmb.setCurrentIndex (index);
680 }
681 
682 void DlgSettingsCoords::loadComboBoxUnitsPolar (QComboBox &cmb,
683  CoordUnitsPolarTheta coordUnits)
684 {
685  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::loadComboBoxUnitsPolar";
686 
687  cmb.clear();
688 
689  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES),
690  QVariant (COORD_UNITS_POLAR_THETA_DEGREES));
691  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES),
692  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES));
693  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS),
694  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS));
695  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW),
696  QVariant (COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW));
697  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_GRADIANS),
698  QVariant (COORD_UNITS_POLAR_THETA_GRADIANS));
699  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_RADIANS),
700  QVariant (COORD_UNITS_POLAR_THETA_RADIANS));
701  cmb.addItem (coordUnitsPolarThetaToString (COORD_UNITS_POLAR_THETA_TURNS),
702  QVariant (COORD_UNITS_POLAR_THETA_TURNS));
703 
704  ENGAUGE_ASSERT (cmb.count() == NUM_COORD_UNITS_POLAR_THETA);
705 
706  cmb.setWhatsThis (QString (tr ("Degrees (DDD.DDDDD) format uses a single real number. One complete revolution is 360 degrees.\n\n"
707  "Degrees Minutes (DDD MM.MMM) format uses one integer number for degrees, and a real number for minutes. There are "
708  "60 minutes per degree. During input, a space must be inserted between the two numbers.\n\n"
709  "Degrees Minutes Seconds (DDD MM SS.S) format uses two integer number for degrees and minutes, and a real number for "
710  "seconds. There are 60 seconds per minute. During input, spaces must be inserted between the three numbers.\n\n"
711  "Gradians format uses a single real number. One complete revolution is 400 gradians.\n\n"
712  "Radians format uses a single real number. One complete revolution is 2*pi radians.\n\n"
713  "Turns format uses a single real number. One complete revolution is one turn.")));
714 
715  int index = cmb.findData (coordUnits);
716  cmb.setCurrentIndex (index);
717 }
718 
719 void DlgSettingsCoords::resetSceneRectangle ()
720 {
721  QRect rect (qFloor (CARTESIAN_COORD_MIN - CARTESIAN_COORD_STEP / 2.0),
722  qFloor (CARTESIAN_COORD_MIN - CARTESIAN_COORD_STEP / 2.0),
723  qFloor (CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN + CARTESIAN_COORD_STEP),
724  qFloor (CARTESIAN_COORD_MAX - CARTESIAN_COORD_MIN + CARTESIAN_COORD_STEP));
725 
726  QGraphicsRectItem *itemPerimeter = new QGraphicsRectItem(rect);
727  itemPerimeter->setVisible(false);
728  m_scenePreview->addItem (itemPerimeter);
729  m_viewPreview->centerOn (QPointF (0.0, 0.0));
730 }
731 
732 void DlgSettingsCoords::setSmallDialogs(bool smallDialogs)
733 {
734  if (!smallDialogs) {
735  setMinimumHeight (MINIMUM_HEIGHT);
736  }
737 }
738 
739 void DlgSettingsCoords::slotCartesianPolar (bool)
740 {
741  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotCartesian";
742 
743  if (m_btnCartesian->isChecked ()) {
744  m_modelCoordsAfter->setCoordsType (COORDS_TYPE_CARTESIAN);
745  } else {
746  m_modelCoordsAfter->setCoordsType(COORDS_TYPE_POLAR);
747  }
748  updateCoordUnits();
749  updateControls();
750  updatePreview();
751 }
752 
753 void DlgSettingsCoords::slotDate(const QString &)
754 {
755  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotDate";
756 
757  CoordUnitsDate coordUnits = static_cast<CoordUnitsDate> (m_cmbDate->currentData ().toInt());
758  m_modelCoordsAfter->setCoordUnitsDate(coordUnits);
759  updateControls();
760  updatePreview();
761 }
762 
763 void DlgSettingsCoords::slotPolarOriginRadius(const QString &)
764 {
765  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotPolarOriginRadius";
766 
767  QString numberText = m_editOriginRadius->text();
768 
769  m_modelCoordsAfter->setOriginRadius(numberText.toDouble ());
770  updateControls();
771  updatePreview();
772 }
773 
774 void DlgSettingsCoords::slotTime(const QString &)
775 {
776  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotTime";
777 
778  CoordUnitsTime coordUnits = static_cast<CoordUnitsTime> (m_cmbTime->currentData ().toInt());
779  m_modelCoordsAfter->setCoordUnitsTime(coordUnits);
780  updateControls();
781  updatePreview();
782 }
783 
784 void DlgSettingsCoords::slotUnitsXTheta(const QString &)
785 {
786  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotUnitsXTheta";
787 
788  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
789  CoordUnitsNonPolarTheta coordUnits = static_cast<CoordUnitsNonPolarTheta> (m_cmbXThetaUnits->currentData ().toInt ());
790  m_modelCoordsAfter->setCoordUnitsX(coordUnits);
791  } else {
792  CoordUnitsPolarTheta coordUnits = static_cast<CoordUnitsPolarTheta> (m_cmbXThetaUnits->currentData ().toInt ());
793  m_modelCoordsAfter->setCoordUnitsTheta(coordUnits);
794  }
795  updateControls ();
796  updatePreview();
797 }
798 
799 void DlgSettingsCoords::slotUnitsYRadius(const QString &)
800 {
801  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotUnitsYRadius";
802 
803  CoordUnitsNonPolarTheta coordUnits = static_cast<CoordUnitsNonPolarTheta> (m_cmbYRadiusUnits->currentData ().toInt ());
804  if (m_modelCoordsAfter->coordsType() == COORDS_TYPE_CARTESIAN) {
805  m_modelCoordsAfter->setCoordUnitsY(coordUnits);
806  } else {
807  m_modelCoordsAfter->setCoordUnitsRadius(coordUnits);
808  }
809  updateControls ();
810  updatePreview();
811 }
812 
813 void DlgSettingsCoords::slotXThetaLinear()
814 {
815  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotXThetaLinear";
816 
817  m_modelCoordsAfter->setCoordScaleXTheta(COORD_SCALE_LINEAR);
818  updateControls ();
819  updatePreview();
820 }
821 
822 void DlgSettingsCoords::slotXThetaLog()
823 {
824  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotXThetaLog";
825 
826  m_modelCoordsAfter->setCoordScaleXTheta(COORD_SCALE_LOG);
827  updateControls ();
828  updatePreview();
829 }
830 
831 void DlgSettingsCoords::slotYRadiusLinear()
832 {
833  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotYRadiusLinear";
834 
835  delete m_validatorOriginRadius;
836 
837  DlgValidatorFactory dlgValidatorFactory;
838  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (COORD_SCALE_LINEAR,
839  m_modelCoordsAfter->coordUnitsRadius(),
840  m_modelCoordsAfter->coordUnitsDate(),
841  m_modelCoordsAfter->coordUnitsTime(),
843  m_editOriginRadius->setValidator (m_validatorOriginRadius);
844 
845  m_modelCoordsAfter->setCoordScaleYRadius((COORD_SCALE_LINEAR));
846  updateControls ();
847  updatePreview();
848 }
849 
850 void DlgSettingsCoords::slotYRadiusLog()
851 {
852  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::slotYRadiusLog";
853 
854  delete m_validatorOriginRadius;
855 
856  DlgValidatorFactory dlgValidatorFactory;
857  m_validatorOriginRadius = dlgValidatorFactory.createWithNonPolar (COORD_SCALE_LOG,
858  m_modelCoordsAfter->coordUnitsRadius(),
859  m_modelCoordsAfter->coordUnitsDate(),
860  m_modelCoordsAfter->coordUnitsTime(),
862  m_editOriginRadius->setValidator (m_validatorOriginRadius);
863 
864  m_modelCoordsAfter->setCoordScaleYRadius(COORD_SCALE_LOG);
865  updateControls ();
866  updatePreview();
867 }
868 
869 void DlgSettingsCoords::updateControls ()
870 {
871  // LOG4CPP_INFO_S is below
872 
873  QString textOriginRadius = m_editOriginRadius->text();
874  int posOriginRadius = 0;
875 
876  bool goodOriginRadius = true; // Cartesian coordinates do not use origin radius
877  if (m_editOriginRadius->isEnabled ()) {
878 
879  // Origin radius must be greater than zero
880  goodOriginRadius = (m_validatorOriginRadius->validate (textOriginRadius,
881  posOriginRadius) == QValidator::Acceptable);
882  }
883 
884  enableOk (goodOriginRadius);
885 
886  m_boxCoordsType->setEnabled (!m_xThetaLog->isChecked ());
887 
888  m_xThetaLinear->setEnabled (!m_btnPolar->isChecked ());
889  m_xThetaLog->setEnabled (!m_btnPolar->isChecked ());
890  if (m_btnCartesian->isChecked()) {
891  m_yRadiusLinear->setEnabled (true);
892  m_yRadiusLog->setEnabled (true);
893  } else {
894 
895  // Use temporary validator to see if current origin radius would be correct in OTHER linear/log mode
896  DlgValidatorFactory dlgValidatorFactory;
897  DlgValidatorAbstract *dlg = dlgValidatorFactory.createWithNonPolar (m_yRadiusLinear->isChecked () ? COORD_SCALE_LOG : COORD_SCALE_LINEAR,
898  m_modelCoordsAfter->coordUnitsRadius(),
899  m_modelCoordsAfter->coordUnitsDate(),
900  m_modelCoordsAfter->coordUnitsTime(),
902  int posOriginRadiusOther;
903  bool goodOriginRadiusOther = (dlg->validate (textOriginRadius, posOriginRadiusOther) == QValidator::Acceptable);
904 
905  delete dlg; // Deallocate
906 
907  m_yRadiusLinear->setEnabled (goodOriginRadius && goodOriginRadiusOther);
908  m_yRadiusLog->setEnabled (goodOriginRadius && goodOriginRadiusOther);
909  }
910  m_editOriginRadius->setEnabled (m_btnPolar->isChecked ());
911 
912  QString captionXTheta = (m_btnCartesian->isChecked () ?
913  QString (tr ("X")) :
914  THETA) + QString (" %1")
915  .arg (tr ("Coordinates"));
916  QString captionYRadius = (m_btnCartesian->isChecked () ?
917  QString (tr ("Y")) :
918  QString (tr ("R"))) + QString (" %1")
919  .arg (tr ("Coordinates"));
920 
921  if (m_boxXTheta->title() != captionXTheta) {
922  m_boxXTheta->setTitle (captionXTheta);
923  }
924 
925  if (m_boxYRadius->title () != captionYRadius) {
926  m_boxYRadius->setTitle (captionYRadius);
927  }
928 
929  bool enableDateTime;
930  if (m_btnCartesian->isChecked()) {
931  enableDateTime = ((static_cast<CoordUnitsNonPolarTheta> (m_cmbXThetaUnits->currentData ().toInt()) == COORD_UNITS_NON_POLAR_THETA_DATE_TIME) ||
932  (static_cast<CoordUnitsNonPolarTheta> (m_cmbYRadiusUnits->currentData ().toInt()) == COORD_UNITS_NON_POLAR_THETA_DATE_TIME));
933  } else {
934  enableDateTime = (static_cast<CoordUnitsNonPolarTheta> (m_cmbYRadiusUnits->currentData ().toInt()) == COORD_UNITS_NON_POLAR_THETA_DATE_TIME);
935  }
936  m_cmbDate->setEnabled (enableDateTime);
937  m_cmbTime->setEnabled (enableDateTime);
938 
939  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsCoords::updateControls"
940  << " textOriginRadius=" << textOriginRadius.toLatin1().data()
941  << " goodOriginRadius=" << (goodOriginRadius ? "true" : "false")
942  << " originRadius=" << posOriginRadius
943  << " btnPolarChecked=" << (m_btnPolar->isChecked() ? "true" : "false")
944  << " enableDateTime=" << (enableDateTime ? "true" : "false");
945 }
946 
947 void DlgSettingsCoords::updateCoordUnits()
948 {
949  // X and Y units
950  if (m_btnCartesian->isChecked()) {
951  loadComboBoxUnitsNonPolar (*m_cmbXThetaUnits,
952  m_modelCoordsAfter->coordUnitsX());
953  loadComboBoxUnitsNonPolar (*m_cmbYRadiusUnits,
954  m_modelCoordsAfter->coordUnitsY());
955  } else {
956  loadComboBoxUnitsPolar (*m_cmbXThetaUnits,
957  m_modelCoordsAfter->coordUnitsTheta());
958  loadComboBoxUnitsNonPolar (*m_cmbYRadiusUnits,
959  m_modelCoordsAfter->coordUnitsRadius());
960  }
961 }
962 
963 void DlgSettingsCoords::updatePreview()
964 {
965  m_scenePreview->clear();
966 
967  // General approach
968  // 1) Axis lines are extra thick, but since they sometimes disappear as the preview window is rescaled, we keep the
969  // constant-pixel line under each axis line
970  // 2) Every STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED out of STEPS_UNHIGHLIGHTED_PER_HIGHLIGHTED+1 lines are dashed to make
971  // them more subtle
972 
973  if (m_btnCartesian->isChecked()) {
974 
975  // Cartesian
976  if (m_xThetaLinear->isChecked()) {
977  drawCartesianLinearX ();
978  } else {
979  drawCartesianLogX ();
980  }
981 
982  if (m_yRadiusLinear->isChecked()) {
983  drawCartesianLinearY ();
984  } else {
985  drawCartesianLogY ();
986  }
987 
988  } else {
989 
990  // Polar
991  drawPolarTheta ();
992  if (m_yRadiusLinear->isChecked()) {
993  drawPolarLinearRadius ();
994  } else {
995  drawPolarLogRadius ();
996  }
997 
998  QFont defaultFont;
999  annotateRadiusAtOrigin (defaultFont);
1000  annotateAngles (defaultFont);
1001  }
1002 
1003  resetSceneRectangle();
1004 }
void setCoordUnitsTime(CoordUnitsTime coordUnits)
Set method for time units.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
void setCoordUnitsDate(CoordUnitsDate coordUnits)
Set method for date units.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition: Document.cpp:361
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
Transformation transformation() const
Return read-only copy of transformation.
void setCoordUnitsY(CoordUnitsNonPolarTheta coordUnits)
Set method for y units.
void setCoordUnitsX(CoordUnitsNonPolarTheta coordUnits)
Set method for x units.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
void setCoordScaleYRadius(CoordScale coordScale)
Set method for linear/log scale on y/radius.
virtual QValidator::State validate(QString &input, int &pos) const =0
Validate according to the numeric format specific to the leaf class.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:693
CoordUnitsNonPolarTheta coordUnitsRadius() const
Get method for radius units.
Abstract validator for all numeric formats.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
CoordUnitsTime coordUnitsTime() const
Get method for time format when used.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
Command for DlgSettingsCoords.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
CoordUnitsNonPolarTheta coordUnitsY() const
Get method for x units.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
void setCoordUnitsTheta(CoordUnitsPolarTheta coordUnits)
Set method for theta units.
CoordsType coordsType() const
Get method for coordinates type.
CoordUnitsNonPolarTheta coordUnitsX() const
Get method for x units.
Model for DlgSettingsCoords and CmdSettingsCoords.
void setOriginRadius(double originRadius)
Set method for origin radius in polar mode.
CoordUnitsDate coordUnitsDate() const
Get method for date format when used.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
void setCoordUnitsRadius(CoordUnitsNonPolarTheta coordUnits)
Set method for radius units.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
DlgValidatorAbstract * createWithNonPolar(CoordScale coordScale, CoordUnitsNonPolarTheta coordUnits, CoordUnitsDate coordUnitsDate, CoordUnitsTime coordUnitsTime, const QLocale &locale) const
Factory method for generating validators when cartesian/polar case handling is handled externally...
Command queue stack.
Definition: CmdMediator.h:23
Abstract base class for all Settings dialogs.
Validator factory.
void iterateThroughCurvesPointsGraphs(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for all the graphs curves.
Definition: CmdMediator.cpp:97
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Definition: CmdMediator.cpp:87
QLocale locale() const
Get method for locale.
Callback for computing the bounding rectangles of the screen and graph coordinates of the points in t...
MainWindow & mainWindow()
Get method for MainWindow.
virtual void handleOk()
Process slotOk.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:91
MainWindowModel modelMainWindow() const
Get method for main window model.
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void setCoordScaleXTheta(CoordScale coordScale)
Set method for linear/log scale on x/theta.
DlgSettingsCoords(MainWindow &mainWindow)
Single constructor.
CoordUnitsPolarTheta coordUnitsTheta() const
Get method for theta unit.
void setCoordsType(CoordsType coordsType)
Set method for coordinates type.