Engauge Digitizer  2
DlgSettingsDigitizeCurve.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 "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 
41  DlgSettingsAbstractBase (tr ("Digitize Curve"),
42  "DlgSettingsDigitizeCurve",
43  mainWindow),
44  m_scenePreview (0),
45  m_viewPreview (0),
46  m_modelDigitizeCurveBefore (0),
47  m_modelDigitizeCurveAfter (0)
48 {
49  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::DlgSettingsDigitizeCurve";
50 
51  QWidget *subPanel = createSubPanel ();
52  finishPanel (subPanel);
53 }
54 
55 DlgSettingsDigitizeCurve::~DlgSettingsDigitizeCurve()
56 {
57  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::~DlgSettingsDigitizeCurve";
58 }
59 
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(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(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(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(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 
119 {
120 }
121 
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 
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 
169 {
170  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::handleOk";
171 
173  cmdMediator ().document(),
174  *m_modelDigitizeCurveBefore,
175  *m_modelDigitizeCurveAfter);
176  cmdMediator ().push (cmd);
177 
178  hide ();
179 }
180 
182 {
183  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::load";
184 
185  setCmdMediator (cmdMediator);
186 
187  // Flush old data
188  if (m_modelDigitizeCurveBefore != 0) {
189  delete m_modelDigitizeCurveBefore;
190  }
191  if (m_modelDigitizeCurveAfter != 0) {
192  delete m_modelDigitizeCurveAfter;
193  }
194 
195  // Save new data
196  m_modelDigitizeCurveBefore = new DocumentModelDigitizeCurve (cmdMediator.document());
197  m_modelDigitizeCurveAfter = new DocumentModelDigitizeCurve (cmdMediator.document());
198 
199  // Sanity checks. Incoming defaults must be acceptable to the local limits
200  ENGAUGE_ASSERT (INNER_RADIUS_MIN <= m_modelDigitizeCurveAfter->cursorInnerRadius ());
201  ENGAUGE_ASSERT (INNER_RADIUS_MAX >= m_modelDigitizeCurveAfter->cursorInnerRadius ());
202  ENGAUGE_ASSERT (LINE_WIDTH_MIN <= m_modelDigitizeCurveAfter->cursorLineWidth ());
203  ENGAUGE_ASSERT (LINE_WIDTH_MAX >= m_modelDigitizeCurveAfter->cursorLineWidth ());
204 
205  // Populate controls
206  m_btnStandard->setChecked (m_modelDigitizeCurveAfter->cursorStandardCross());
207  m_btnCustom->setChecked (!m_modelDigitizeCurveAfter->cursorStandardCross());
208  m_spinInnerRadius->setValue (m_modelDigitizeCurveAfter->cursorInnerRadius());
209  int index = m_cmbSize->findData (QVariant (m_modelDigitizeCurveAfter->cursorSize()));
210  m_cmbSize->setCurrentIndex (index);
211  m_spinLineWidth->setValue (m_modelDigitizeCurveAfter->cursorLineWidth());
212 
213  updateControls();
214  enableOk (false); // Disable Ok button since there not yet any changes
215  updatePreview();
216 }
217 
219 {
220  if (!smallDialogs) {
221  setMinimumHeight (MINIMUM_HEIGHT);
222  }
223 }
224 
225 void DlgSettingsDigitizeCurve::slotCursorCustom (bool)
226 {
227  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorCustom";
228 
229  m_modelDigitizeCurveAfter->setCursorStandardCross(false);
230  updateControls();
231  updatePreview();
232 }
233 
234 void DlgSettingsDigitizeCurve::slotCursorInnerRadius (const QString &)
235 {
236  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorInnerRadius";
237 
238  m_modelDigitizeCurveAfter->setCursorInnerRadius (m_spinInnerRadius->value());
239  updateControls();
240  updatePreview();
241 }
242 
243 void DlgSettingsDigitizeCurve::slotCursorLineWidth (const QString &)
244 {
245  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorLineWidth";
246 
247  m_modelDigitizeCurveAfter->setCursorLineWidth (m_spinLineWidth->value());
248  updateControls();
249  updatePreview();
250 }
251 
252 void DlgSettingsDigitizeCurve::slotCursorSize (const QString &)
253 {
254  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorSize";
255 
256  m_modelDigitizeCurveAfter->setCursorSize ((CursorSize) m_cmbSize->currentData().toInt());
257  updateControls();
258  updatePreview();
259 }
260 
261 void DlgSettingsDigitizeCurve::slotCursorStandard (bool)
262 {
263  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorStandard";
264 
265  m_modelDigitizeCurveAfter->setCursorStandardCross(true);
266  updateControls();
267  updatePreview();
268 }
269 
270 void DlgSettingsDigitizeCurve::updateControls()
271 {
272  // Cursor has to fit into current extent
273  bool isGoodState = 2 * (m_modelDigitizeCurveAfter->cursorInnerRadius() + LINE_LENGTH_MIN) <=
274  CursorSizeToPixels (m_modelDigitizeCurveAfter->cursorSize());
275  enableOk (isGoodState);
276 
277  m_spinInnerRadius->setEnabled (m_btnCustom->isChecked());
278  m_cmbSize->setEnabled (m_btnCustom->isChecked());
279  m_spinLineWidth->setEnabled (m_btnCustom->isChecked());
280 }
281 
282 void DlgSettingsDigitizeCurve::updatePreview()
283 {
284  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::updatePreview";
285 
286  CursorFactory cursorFactory;
287  QCursor cursor = cursorFactory.generate (*m_modelDigitizeCurveAfter);
288  m_viewPreview->setCursor (cursor);
289 }
DlgSettingsDigitizeCurve(MainWindow &mainWindow)
Single constructor.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
CursorSize cursorSize() const
Get method for cursor size.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
Create standard cross cursor, or custom cursor, according to settings.
Definition: CursorFactory.h:15
void setCursorLineWidth(int lineWidth)
Set method for cursor line width.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
virtual void handleOk()
Process slotOk.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
void setCursorSize(CursorSize cursorSize)
Set method for cursor size.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
void setCursorInnerRadius(int innerRadius)
Set method for cursor inner radius.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
int cursorInnerRadius() const
Get method for cursor inner radius.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
bool cursorStandardCross() const
Get method for cursor type.
Command for DlgSettingsDigitizeCurve.
Command queue stack.
Definition: CmdMediator.h:23
int cursorLineWidth() const
Get method for cursor line width.
Abstract base class for all Settings dialogs.
MainWindow & mainWindow()
Get method for MainWindow.
QCursor generate(const DocumentModelDigitizeCurve &modelDigitizeCurve) const
Factory method to generate standard or custom cursor.
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 setCursorStandardCross(bool cursorStandardCross)
Set method for cursor type.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.