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"
8 #include "CmdSettingsDigitizeCurve.h"
9 #include "CursorFactory.h"
10 #include "CursorSize.h"
11 #include "DlgSettingsDigitizeCurve.h"
12 #include "DocumentModelDigitizeCurve.h"
13 #include "EngaugeAssert.h"
14 #include "Logger.h"
15 #include "MainWindow.h"
16 #include "PointStyle.h"
17 #include <QCheckBox>
18 #include <QComboBox>
19 #include <QGraphicsPixmapItem>
20 #include <QGridLayout>
21 #include <QGraphicsScene>
22 #include <QGroupBox>
23 #include <QLabel>
24 #include <qmath.h>
25 #include <QRadioButton>
26 #include <QSpinBox>
27 #include "Segment.h"
28 #include "SegmentFactory.h"
29 #include "ViewPreview.h"
30
31 const int IMAGE_WIDTH = 100;
32 const int IMAGE_HEIGHT = 100;
33 const int MINIMUM_HEIGHT = 450;
34 const int INNER_RADIUS_MAX = 64;
35 const int INNER_RADIUS_MIN = 0;
36 const int LINE_LENGTH_MIN = 2; // Min length of one line in the cursor, in pixels
37 const int LINE_WIDTH_MAX = 32;
38 const int LINE_WIDTH_MIN = 1;
39
DlgSettingsDigitizeCurve(MainWindow & mainWindow)40 DlgSettingsDigitizeCurve::DlgSettingsDigitizeCurve(MainWindow &mainWindow) :
41 DlgSettingsAbstractBase (tr ("Digitize Curve"),
42 "DlgSettingsDigitizeCurve",
43 mainWindow),
44 m_scenePreview (nullptr),
45 m_viewPreview (nullptr),
46 m_modelDigitizeCurveBefore (nullptr),
47 m_modelDigitizeCurveAfter (nullptr)
48 {
49 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::DlgSettingsDigitizeCurve";
50
51 QWidget *subPanel = createSubPanel ();
52 finishPanel (subPanel);
53 }
54
~DlgSettingsDigitizeCurve()55 DlgSettingsDigitizeCurve::~DlgSettingsDigitizeCurve()
56 {
57 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::~DlgSettingsDigitizeCurve";
58 }
59
createControls(QGridLayout * layout,int & row)60 void DlgSettingsDigitizeCurve::createControls (QGridLayout *layout,
61 int &row)
62 {
63 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::createControls";
64
65 m_boxCursor = new QGroupBox (tr ("Cursor"));
66 layout->addWidget (m_boxCursor, row++, 1, 1, 2);
67
68 // Layout inside cursor group box
69 QGridLayout *layoutCursor = new QGridLayout;
70 m_boxCursor->setLayout (layoutCursor);
71 int rowCursor = 0;
72
73 QLabel *labelCursorType = new QLabel(QString ("%1:").arg (tr ("Type")));
74 layoutCursor->addWidget (labelCursorType, rowCursor, 0);
75
76 m_btnStandard = new QRadioButton (tr ("Standard cross"));
77 m_btnStandard->setWhatsThis (tr ("Selects the standard cross cursor"));
78 layoutCursor->addWidget (m_btnStandard, rowCursor++, 1);
79 connect (m_btnStandard, SIGNAL (toggled (bool)), this, SLOT (slotCursorStandard(bool)));
80
81 m_btnCustom = new QRadioButton (tr ("Custom cross"));
82 m_btnCustom->setWhatsThis (tr ("Selects a custom cursor based on the settings selected below"));
83 layoutCursor->addWidget (m_btnCustom, rowCursor++, 1);
84 connect (m_btnCustom, SIGNAL (toggled (bool)), this, SLOT (slotCursorCustom(bool)));
85
86 QLabel *labelSize = new QLabel(QString ("%1:").arg (tr ("Size (pixels)")));
87 layoutCursor->addWidget (labelSize, rowCursor, 0);
88
89 m_cmbSize = new QComboBox;
90 m_cmbSize->addItem (QString::number (CursorSizeToPixels (CURSOR_SIZE_16)), QVariant (CURSOR_SIZE_16));
91 m_cmbSize->addItem (QString::number (CursorSizeToPixels (CURSOR_SIZE_32)), QVariant (CURSOR_SIZE_32));
92 m_cmbSize->addItem (QString::number (CursorSizeToPixels (CURSOR_SIZE_48)), QVariant (CURSOR_SIZE_48));
93 m_cmbSize->addItem (QString::number (CursorSizeToPixels (CURSOR_SIZE_64)), QVariant (CURSOR_SIZE_64));
94 ENGAUGE_ASSERT (m_cmbSize->count() == NUM_CURSOR_SIZES);
95 m_cmbSize->setWhatsThis (tr ("Horizontal and vertical size of the cursor in pixels"));
96 layoutCursor->addWidget (m_cmbSize, rowCursor++, 1);
97 connect (m_cmbSize, SIGNAL (currentIndexChanged (const QString &)), this, SLOT (slotCursorSize (const QString &)));
98
99 QLabel *labelInnerRadius = new QLabel(QString ("%1:").arg (tr ("Inner radius (pixels)")));
100 layoutCursor->addWidget (labelInnerRadius, rowCursor, 0);
101
102 m_spinInnerRadius = new QSpinBox;
103 m_spinInnerRadius->setRange (INNER_RADIUS_MIN, INNER_RADIUS_MAX);
104 m_spinInnerRadius->setWhatsThis (tr ("Radius of circle at the center of the cursor that will remain empty"));
105 layoutCursor->addWidget (m_spinInnerRadius, rowCursor++, 1);
106 connect (m_spinInnerRadius, SIGNAL (valueChanged(const QString &)), this, SLOT (slotCursorInnerRadius (const QString &)));
107
108 QLabel *labelLineWidth = new QLabel(QString ("%1:").arg (tr ("Line width (pixels)")));
109 layoutCursor->addWidget (labelLineWidth, rowCursor, 0);
110
111 m_spinLineWidth = new QSpinBox;
112 m_spinLineWidth->setRange (LINE_WIDTH_MIN, LINE_WIDTH_MAX);
113 m_spinLineWidth->setWhatsThis (tr ("Width of each arm of the cross of the cursor"));
114 layoutCursor->addWidget (m_spinLineWidth, rowCursor++, 1);
115 connect (m_spinLineWidth, SIGNAL (valueChanged(const QString &)), this, SLOT (slotCursorLineWidth (const QString &)));
116 }
117
createOptionalSaveDefault(QHBoxLayout *)118 void DlgSettingsDigitizeCurve::createOptionalSaveDefault (QHBoxLayout * /* layout */)
119 {
120 }
121
createPreview(QGridLayout * layout,int & row)122 void DlgSettingsDigitizeCurve::createPreview (QGridLayout *layout,
123 int &row)
124 {
125 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::createPreview";
126
127 QLabel *labelPreview = new QLabel (tr ("Preview"));
128 layout->addWidget (labelPreview, row++, 0, 1, 4);
129
130 m_scenePreview = new QGraphicsScene (this);
131 m_scenePreview->setSceneRect(0,
132 0,
133 IMAGE_WIDTH,
134 IMAGE_HEIGHT);
135
136 m_viewPreview = new ViewPreview (m_scenePreview,
137 ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
138 this);
139 m_viewPreview->setWhatsThis (tr ("Preview window showing the currently selected cursor.\n\n"
140 "Drag the cursor over this area to see the effects of the current settings on the cursor shape."));
141 m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
142 m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
143 m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
144
145 layout->addWidget (m_viewPreview, row++, 0, 1, 4);
146 }
147
createSubPanel()148 QWidget *DlgSettingsDigitizeCurve::createSubPanel ()
149 {
150 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::createSubPanel";
151
152 QWidget *subPanel = new QWidget ();
153 QGridLayout *layout = new QGridLayout (subPanel);
154 subPanel->setLayout (layout);
155
156 layout->setColumnStretch (0, 1); // Empty first column
157 layout->setColumnStretch (1, 0); // Labels
158 layout->setColumnStretch (2, 0); // User controls
159 layout->setColumnStretch (3, 1); // Empty last column
160
161 int row = 0;
162 createControls(layout, row);
163 createPreview (layout, row);
164
165 return subPanel;
166 }
167
handleOk()168 void DlgSettingsDigitizeCurve::handleOk ()
169 {
170 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::handleOk";
171
172 CmdSettingsDigitizeCurve *cmd = new CmdSettingsDigitizeCurve (mainWindow (),
173 cmdMediator ().document(),
174 *m_modelDigitizeCurveBefore,
175 *m_modelDigitizeCurveAfter);
176 cmdMediator ().push (cmd);
177
178 hide ();
179 }
180
load(CmdMediator & cmdMediator)181 void DlgSettingsDigitizeCurve::load (CmdMediator &cmdMediator)
182 {
183 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::load";
184
185 setCmdMediator (cmdMediator);
186
187 // Flush old data
188 delete m_modelDigitizeCurveBefore;
189 delete m_modelDigitizeCurveAfter;
190
191 // Save new data
192 m_modelDigitizeCurveBefore = new DocumentModelDigitizeCurve (cmdMediator.document());
193 m_modelDigitizeCurveAfter = new DocumentModelDigitizeCurve (cmdMediator.document());
194
195 // Sanity checks. Incoming defaults must be acceptable to the local limits
196 ENGAUGE_ASSERT (INNER_RADIUS_MIN <= m_modelDigitizeCurveAfter->cursorInnerRadius ());
197 ENGAUGE_ASSERT (INNER_RADIUS_MAX >= m_modelDigitizeCurveAfter->cursorInnerRadius ());
198 ENGAUGE_ASSERT (LINE_WIDTH_MIN <= m_modelDigitizeCurveAfter->cursorLineWidth ());
199 ENGAUGE_ASSERT (LINE_WIDTH_MAX >= m_modelDigitizeCurveAfter->cursorLineWidth ());
200
201 // Populate controls
202 m_btnStandard->setChecked (m_modelDigitizeCurveAfter->cursorStandardCross());
203 m_btnCustom->setChecked (!m_modelDigitizeCurveAfter->cursorStandardCross());
204 m_spinInnerRadius->setValue (m_modelDigitizeCurveAfter->cursorInnerRadius());
205 int index = m_cmbSize->findData (QVariant (m_modelDigitizeCurveAfter->cursorSize()));
206 m_cmbSize->setCurrentIndex (index);
207 m_spinLineWidth->setValue (m_modelDigitizeCurveAfter->cursorLineWidth());
208
209 updateControls();
210 enableOk (false); // Disable Ok button since there not yet any changes
211 updatePreview();
212 }
213
setSmallDialogs(bool smallDialogs)214 void DlgSettingsDigitizeCurve::setSmallDialogs(bool smallDialogs)
215 {
216 if (!smallDialogs) {
217 setMinimumHeight (MINIMUM_HEIGHT);
218 }
219 }
220
slotCursorCustom(bool)221 void DlgSettingsDigitizeCurve::slotCursorCustom (bool)
222 {
223 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorCustom";
224
225 m_modelDigitizeCurveAfter->setCursorStandardCross(false);
226 updateControls();
227 updatePreview();
228 }
229
slotCursorInnerRadius(const QString &)230 void DlgSettingsDigitizeCurve::slotCursorInnerRadius (const QString &)
231 {
232 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorInnerRadius";
233
234 m_modelDigitizeCurveAfter->setCursorInnerRadius (m_spinInnerRadius->value());
235 updateControls();
236 updatePreview();
237 }
238
slotCursorLineWidth(const QString &)239 void DlgSettingsDigitizeCurve::slotCursorLineWidth (const QString &)
240 {
241 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorLineWidth";
242
243 m_modelDigitizeCurveAfter->setCursorLineWidth (m_spinLineWidth->value());
244 updateControls();
245 updatePreview();
246 }
247
slotCursorSize(const QString &)248 void DlgSettingsDigitizeCurve::slotCursorSize (const QString &)
249 {
250 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorSize";
251
252 m_modelDigitizeCurveAfter->setCursorSize (static_cast<CursorSize> (m_cmbSize->currentData().toInt()));
253 updateControls();
254 updatePreview();
255 }
256
slotCursorStandard(bool)257 void DlgSettingsDigitizeCurve::slotCursorStandard (bool)
258 {
259 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorStandard";
260
261 m_modelDigitizeCurveAfter->setCursorStandardCross(true);
262 updateControls();
263 updatePreview();
264 }
265
updateControls()266 void DlgSettingsDigitizeCurve::updateControls()
267 {
268 // Cursor has to fit into current extent
269 bool isGoodState = 2 * (m_modelDigitizeCurveAfter->cursorInnerRadius() + LINE_LENGTH_MIN) <=
270 CursorSizeToPixels (m_modelDigitizeCurveAfter->cursorSize());
271 enableOk (isGoodState);
272
273 m_spinInnerRadius->setEnabled (m_btnCustom->isChecked());
274 m_cmbSize->setEnabled (m_btnCustom->isChecked());
275 m_spinLineWidth->setEnabled (m_btnCustom->isChecked());
276 }
277
updatePreview()278 void DlgSettingsDigitizeCurve::updatePreview()
279 {
280 LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::updatePreview";
281
282 CursorFactory cursorFactory;
283 QCursor cursor = cursorFactory.generate (*m_modelDigitizeCurveAfter);
284 m_viewPreview->setCursor (cursor);
285 }
286