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