Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
DlgSettingsSegments.cpp
1 #include "CmdMediator.h"
2 #include "CmdSettingsSegments.h"
3 #include "DlgSettingsSegments.h"
4 #include "EngaugeAssert.h"
5 #include "Logger.h"
6 #include "MainWindow.h"
7 #include "PointStyle.h"
8 #include <QCheckBox>
9 #include <QComboBox>
10 #include <QGridLayout>
11 #include <QGraphicsScene>
12 #include <QLabel>
13 #include <qmath.h>
14 #include <QSpinBox>
15 #include "Segment.h"
16 #include "SegmentFactory.h"
17 #include "ViewPreview.h"
18 
19 const int MIN_LENGTH_MIN = 1;
20 const int MIN_LENGTH_MAX = 10000;
21 const int POINT_SEPARATION_MIN = 5;
22 const int POINT_SEPARATION_MAX = 10000;
23 
24 const int IMAGE_WIDTH = 400;
25 const int IMAGE_HEIGHT = 300;
26 
27 const double TWOPI = 2.0 * 3.1415926535;
28 
29 const double BRUSH_WIDTH = 2.0;
30 
32  DlgSettingsAbstractBase ("Segment Fill",
33  "DlgSettingsSegments",
34  mainWindow),
35  m_scenePreview (0),
36  m_viewPreview (0),
37  m_modelSegmentsBefore (0),
38  m_modelSegmentsAfter (0),
39  m_loading (false)
40 {
41  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::DlgSettingsSegments";
42 
43  QWidget *subPanel = createSubPanel ();
44  finishPanel (subPanel);
45 }
46 
47 DlgSettingsSegments::~DlgSettingsSegments()
48 {
49  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::~DlgSettingsSegments";
50 }
51 
52 void DlgSettingsSegments::clearPoints ()
53 {
54  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::clearPoints";
55 
56  QList<GraphicsPoint*>::iterator itrP;
57  for (itrP = m_points.begin(); itrP != m_points.end(); itrP++) {
58  GraphicsPoint *point = *itrP;
59  delete point;
60  }
61 
62  m_points.clear();
63 }
64 
65 void DlgSettingsSegments::createControls (QGridLayout *layout,
66  int &row)
67 {
68  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::createControls";
69 
70  QLabel *labelMinLength = new QLabel("Minimum length (points):");
71  layout->addWidget(labelMinLength, row, 1);
72 
73  m_spinMinLength = new QSpinBox;
74  m_spinMinLength->setRange (MIN_LENGTH_MIN, MIN_LENGTH_MAX);
75  m_spinMinLength->setWhatsThis (tr ("Select a minimum number of points in a segment.\n\n"
76  "Only segments with more points will be created.\n\n"
77  "This value should be as large as possible to reduce memory usage. This value has "
78  "a lower limit"));
79  connect (m_spinMinLength, SIGNAL (valueChanged (const QString &)), this, SLOT (slotMinLength (const QString &)));
80  layout->addWidget(m_spinMinLength, row++, 2);
81 
82  QLabel *labelPointSeparation = new QLabel("Point separation (pixels):");
83  layout->addWidget (labelPointSeparation, row, 1);
84 
85  m_spinPointSeparation = new QSpinBox;
86  m_spinPointSeparation->setRange (POINT_SEPARATION_MIN, POINT_SEPARATION_MAX);
87  m_spinPointSeparation->setWhatsThis (tr ("Select a point separation in pixels.\n\n"
88  "Successive points added to a segment will be separated by this number of pixels. "
89  "If Fill Corners is enabled, then additional points will be inserted at corners so some points "
90  "will be closer.\n\n"
91  "This value has a lower limit"));
92  connect (m_spinPointSeparation, SIGNAL (valueChanged (const QString &)), this, SLOT (slotPointSeparation (const QString &)));
93  layout->addWidget (m_spinPointSeparation, row++, 2);
94 
95  QLabel *labelFillCorners = new QLabel ("Fill corners:");
96  layout->addWidget (labelFillCorners, row, 1);
97 
98  m_chkFillCorners = new QCheckBox;
99  m_chkFillCorners->setWhatsThis (tr ("Fill corners.\n\n"
100  "In addition to the points placed at regular intervals, this option causes a point to be "
101  "placed at each corner. This option can capture important information in piecewise linear graphs, "
102  "but gradually curving graphs may not benefit from the additional points"));
103  connect (m_chkFillCorners, SIGNAL (stateChanged (int)), this, SLOT (slotFillCorners (int)));
104  layout->addWidget (m_chkFillCorners, row++, 2);
105 
106  QLabel *labelLineWidth = new QLabel("Line width:");
107  layout->addWidget (labelLineWidth, row, 1);
108 
109  m_spinLineWidth = new QSpinBox;
110  m_spinLineWidth->setWhatsThis (tr ("Select a size for the lines drawn along a segment"));
111  m_spinLineWidth->setMinimum(1);
112  connect (m_spinLineWidth, SIGNAL (valueChanged (int)), this, SLOT (slotLineWidth (int)));
113  layout->addWidget (m_spinLineWidth, row++, 2);
114 
115  QLabel *labelLineColor = new QLabel("Line color:");
116  layout->addWidget (labelLineColor, row, 1);
117 
118  m_cmbLineColor = new QComboBox;
119  m_cmbLineColor->setWhatsThis (tr ("Select a color for the lines drawn along a segment"));
120  populateColorComboWithTransparent (*m_cmbLineColor);
121  connect (m_cmbLineColor, SIGNAL (activated (const QString &)), this, SLOT (slotLineColor (const QString &))); // activated() ignores code changes
122  layout->addWidget (m_cmbLineColor, row++, 2);
123 }
124 
125 void DlgSettingsSegments::createOptionalSaveDefault (QHBoxLayout * /* layout */)
126 {
127 }
128 
129 void DlgSettingsSegments::createPreview (QGridLayout *layout,
130  int &row)
131 {
132  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::createPreview";
133 
134  QLabel *labelPreview = new QLabel ("Preview");
135  layout->addWidget (labelPreview, row++, 0, 1, 4);
136 
137  m_scenePreview = new QGraphicsScene (this);
138  m_viewPreview = new ViewPreview (m_scenePreview,
139  ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
140  this);
141  m_viewPreview->setWhatsThis (tr ("Preview window shows the shortest line that can be segment filled, "
142  "and the effects of current settings on segments and points generated by segment fill"));
143  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
144  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
145  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
146 
147  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
148 }
149 
150 QImage DlgSettingsSegments::createPreviewImage () const
151 {
152  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::createPreviewImage";
153 
154  QImage image (IMAGE_WIDTH,
155  IMAGE_HEIGHT,
156  QImage::Format_RGB32);
157  image.fill (Qt::white);
158  QPainter painter (&image);
159  painter.setRenderHint(QPainter::Antialiasing);
160  painter.setPen (QPen (QBrush (Qt::black), BRUSH_WIDTH));
161 
162  int margin = IMAGE_WIDTH / 15;
163  int yCenter = IMAGE_HEIGHT / 2;
164  int yHeight = IMAGE_HEIGHT / 4;
165  int x, y, xLast, yLast;
166  bool isFirst;
167 
168  // Draw sinusoid
169  isFirst = true;
170  int xStart = margin, xEnd = IMAGE_WIDTH / 2 - margin;
171  for (x = xStart; x < xEnd; x++) {
172  double s = (double) (x - xStart) / (double) (xEnd - xStart);
173  int y = yCenter - yHeight * qSin (TWOPI * s);
174 
175  if (!isFirst) {
176  painter.drawLine (xLast, yLast, x, y);
177  }
178  isFirst = false;
179  xLast = x;
180  yLast = y;
181  }
182 
183  // Draw triangular waveform that looks like sinusoid straightened up into line segments
184  isFirst = true;
185  xStart = IMAGE_WIDTH / 2 + margin, xEnd = IMAGE_WIDTH - margin;
186  for (x = xStart; x < xEnd; x++) {
187  double s = (double) (x - xStart) / (double) (xEnd - xStart);
188  if (s <= 0.25) {
189  y = yCenter - yHeight * (4.0 * s);
190  } else if (s < 0.75) {
191  y = yCenter - yHeight * (1.0 - 4.0 * (s - 0.25));
192  } else {
193  y = yCenter + yHeight * (1.0 - 4 * (s - 0.75));
194  }
195 
196  if (!isFirst) {
197  painter.drawLine (xLast, yLast, x, y);
198  }
199  isFirst = false;
200  xLast = x;
201  yLast = y;
202  }
203 
204  return image;
205 }
206 
208 {
209  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::createSubPanel";
210 
211  QWidget *subPanel = new QWidget ();
212  QGridLayout *layout = new QGridLayout (subPanel);
213  subPanel->setLayout (layout);
214 
215  layout->setColumnStretch (0, 1); // Empty first column
216  layout->setColumnStretch (1, 0); // Labels
217  layout->setColumnStretch (2, 0); // User controls
218  layout->setColumnStretch (3, 1); // Empty last column
219 
220  int row = 0;
221  createControls(layout, row);
222  createPreview (layout, row);
223  QPixmap pixmap = QPixmap::fromImage (createPreviewImage());
224  m_scenePreview->addPixmap (pixmap);
225 
226  return subPanel;
227 }
228 
230 {
231  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::handleOk";
232 
234  cmdMediator ().document(),
235  *m_modelSegmentsBefore,
236  *m_modelSegmentsAfter);
237  cmdMediator ().push (cmd);
238 
239  hide ();
240 }
241 
243 {
244  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::load";
245 
246  // Loading starts here
247  m_loading = true;
248 
249  setCmdMediator (cmdMediator);
250 
251  // Flush old data
252  if (m_modelSegmentsBefore != 0) {
253  delete m_modelSegmentsBefore;
254  }
255  if (m_modelSegmentsAfter != 0) {
256  delete m_modelSegmentsAfter;
257  }
258 
259  // Save new data
260  m_modelSegmentsBefore = new DocumentModelSegments (cmdMediator.document());
261  m_modelSegmentsAfter = new DocumentModelSegments (cmdMediator.document());
262 
263  // Sanity checks. Incoming defaults must be acceptable to the local limits
264  ENGAUGE_ASSERT (MIN_LENGTH_MIN <= m_modelSegmentsAfter->minLength ());
265  ENGAUGE_ASSERT (MIN_LENGTH_MAX >= m_modelSegmentsAfter->minLength ());
266  ENGAUGE_ASSERT (POINT_SEPARATION_MIN <= m_modelSegmentsAfter->pointSeparation());
267  ENGAUGE_ASSERT (POINT_SEPARATION_MAX >= m_modelSegmentsAfter->pointSeparation());
268 
269  // Populate controls
270  m_spinPointSeparation->setValue (m_modelSegmentsAfter->pointSeparation());
271  m_spinMinLength->setValue (m_modelSegmentsAfter->minLength());
272  m_chkFillCorners->setChecked (m_modelSegmentsAfter->fillCorners ());
273  m_spinLineWidth->setValue (m_modelSegmentsAfter->lineWidth());
274 
275  int indexLineColor = m_cmbLineColor->findData(QVariant (m_modelSegmentsAfter->lineColor()));
276  ENGAUGE_ASSERT (indexLineColor >= 0);
277  m_cmbLineColor->setCurrentIndex(indexLineColor);
278 
279  // Loading finishes here
280  m_loading = false;
281 
282  updateControls();
283  enableOk (false); // Disable Ok button since there not yet any changes
284  updatePreview();
285 }
286 
287 void DlgSettingsSegments::slotFillCorners (int state)
288 {
289  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::slotFillCorner";
290 
291  m_modelSegmentsAfter->setFillCorners(state == Qt::Checked);
292  updateControls();
293  updatePreview();
294 }
295 
296 void DlgSettingsSegments::slotLineColor (const QString &)
297 {
298  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::slotLineColor";
299 
300  m_modelSegmentsAfter->setLineColor((ColorPalette) m_cmbLineColor->currentData().toInt());
301  updateControls();
302  updatePreview();
303 }
304 
305 void DlgSettingsSegments::slotLineWidth (int lineWidth)
306 {
307  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::slotLineWidth";
308 
309  m_modelSegmentsAfter->setLineWidth(lineWidth);
310  updateControls();
311  updatePreview();
312 }
313 
314 void DlgSettingsSegments::slotMinLength (const QString &minLength)
315 {
316  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::slotMinLength";
317 
318  m_modelSegmentsAfter->setMinLength(minLength.toDouble());
319  updateControls();
320  updatePreview();
321 }
322 
323 void DlgSettingsSegments::slotPointSeparation (const QString &pointSeparation)
324 {
325  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::slotPointSeparation";
326 
327  m_modelSegmentsAfter->setPointSeparation(pointSeparation.toDouble());
328  updateControls();
329  updatePreview();
330 }
331 
332 void DlgSettingsSegments::updateControls()
333 {
334  enableOk (true);
335 }
336 
337 void DlgSettingsSegments::updatePreview()
338 {
339  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsSegments::updatePreview"
340  << " loading=" << (m_loading ? "true" : "false");
341 
342  const QString ARBITRARY_IDENTIFIER ("");
343  const QColor COLOR (Qt::blue);
344  const int RADIUS = 5;
345 
346  if (!m_loading) {
347 
348  SegmentFactory segmentFactory (*m_scenePreview,
349  mainWindow().isGnuplot());
350 
351  clearPoints();
352  segmentFactory.clearSegments (m_segments);
353 
354  // Create new segments
355  segmentFactory.makeSegments (createPreviewImage(),
356  *m_modelSegmentsAfter,
357  m_segments);
358 
359  // Make the segment visible
360  QList<Segment*>::iterator itrS;
361  for (itrS = m_segments.begin(); itrS != m_segments.end(); itrS++) {
362  Segment *segment = *itrS;
363  segment->slotHover (true);
364  }
365 
366  // Create some points
367  PointStyle pointStyle (POINT_SHAPE_CROSS,
368  RADIUS,
369  BRUSH_WIDTH,
370  COLOR_PALETTE_BLUE);
371  QPolygonF polygon = pointStyle.polygon();
372  QList<QPoint> points = segmentFactory.fillPoints (*m_modelSegmentsAfter,
373  m_segments);
374  QList<QPoint>::iterator itrP;
375  for (itrP = points.begin(); itrP != points.end(); itrP++) {
376  QPoint pos = *itrP;
377  GraphicsPoint *graphicsPoint = new GraphicsPoint (*m_scenePreview,
378  ARBITRARY_IDENTIFIER,
379  pos,
380  COLOR,
381  polygon,
382  BRUSH_WIDTH);
383  m_points.push_back (graphicsPoint);
384  }
385  }
386 }
ColorPalette lineColor() const
Get method for line color.
void setLineColor(ColorPalette lineColor)
Set method for line color.
void setMinLength(double minLength)
Set method for min length.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:61
double pointSeparation() const
Get method for point separation.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void setLineWidth(double lineWidth)
Set method for line width.
Factory class for Segment objects.
void slotHover(bool hover)
Slot for hover enter/leave events in the associated SegmentLines.
Definition: Segment.cpp:519
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:8
void setFillCorners(bool fillCorners)
Set method for fill corners.
Details for a specific Point.
Definition: PointStyle.h:14
Selectable piecewise-defined line that follows a filtered line in the image.
Definition: Segment.h:15
double lineWidth() const
Get method for line width.
Graphics item for drawing a circular or polygonal Point.
Definition: GraphicsPoint.h:33
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
Command for DlgSettingsSegments.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
Command queue stack.
Definition: CmdMediator.h:16
void populateColorComboWithTransparent(QComboBox &combo)
Add colors in color palette to combobox, with transparent entry at end.
DlgSettingsSegments(MainWindow &mainWindow)
Single constructor.
double minLength() const
Get method for min length.
Model for DlgSettingsSegments and CmdSettingsSegments.
Abstract base class for all Settings dialogs.
virtual void handleOk()
Process slotOk.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
void setPointSeparation(double pointSeparation)
Set method for point separation.
MainWindow & mainWindow()
Get method for MainWindow.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:66
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
bool fillCorners() const
Get method for fill corners.