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