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 
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"));
140  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
141  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
142  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
143 
144  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
145 }
146 
148 {
149  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::createSubPanel";
150 
151  QWidget *subPanel = new QWidget ();
152  QGridLayout *layout = new QGridLayout (subPanel);
153  subPanel->setLayout (layout);
154 
155  layout->setColumnStretch (0, 1); // Empty first column
156  layout->setColumnStretch (1, 0); // Labels
157  layout->setColumnStretch (2, 0); // User controls
158  layout->setColumnStretch (3, 1); // Empty last column
159 
160  int row = 0;
161  createControls(layout, row);
162  createPreview (layout, row);
163 
164  return subPanel;
165 }
166 
168 {
169  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::handleOk";
170 
172  cmdMediator ().document(),
173  *m_modelDigitizeCurveBefore,
174  *m_modelDigitizeCurveAfter);
175  cmdMediator ().push (cmd);
176 
177  hide ();
178 }
179 
181 {
182  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::load";
183 
184  setCmdMediator (cmdMediator);
185 
186  // Flush old data
187  if (m_modelDigitizeCurveBefore != 0) {
188  delete m_modelDigitizeCurveBefore;
189  }
190  if (m_modelDigitizeCurveAfter != 0) {
191  delete m_modelDigitizeCurveAfter;
192  }
193 
194  // Save new data
195  m_modelDigitizeCurveBefore = new DocumentModelDigitizeCurve (cmdMediator.document());
196  m_modelDigitizeCurveAfter = new DocumentModelDigitizeCurve (cmdMediator.document());
197 
198  // Sanity checks. Incoming defaults must be acceptable to the local limits
199  ENGAUGE_ASSERT (INNER_RADIUS_MIN <= m_modelDigitizeCurveAfter->cursorInnerRadius ());
200  ENGAUGE_ASSERT (INNER_RADIUS_MAX >= m_modelDigitizeCurveAfter->cursorInnerRadius ());
201  ENGAUGE_ASSERT (LINE_WIDTH_MIN <= m_modelDigitizeCurveAfter->cursorLineWidth ());
202  ENGAUGE_ASSERT (LINE_WIDTH_MAX >= m_modelDigitizeCurveAfter->cursorLineWidth ());
203 
204  // Populate controls
205  m_btnStandard->setChecked (m_modelDigitizeCurveAfter->cursorStandardCross());
206  m_btnCustom->setChecked (!m_modelDigitizeCurveAfter->cursorStandardCross());
207  m_spinInnerRadius->setValue (m_modelDigitizeCurveAfter->cursorInnerRadius());
208  int index = m_cmbSize->findData (QVariant (m_modelDigitizeCurveAfter->cursorSize()));
209  m_cmbSize->setCurrentIndex (index);
210  m_spinLineWidth->setValue (m_modelDigitizeCurveAfter->cursorLineWidth());
211 
212  updateControls();
213  enableOk (false); // Disable Ok button since there not yet any changes
214  updatePreview();
215 }
216 
217 void DlgSettingsDigitizeCurve::slotCursorCustom (bool)
218 {
219  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorCustom";
220 
221  m_modelDigitizeCurveAfter->setCursorStandardCross(false);
222  updateControls();
223  updatePreview();
224 }
225 
226 void DlgSettingsDigitizeCurve::slotCursorInnerRadius (const QString &)
227 {
228  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorInnerRadius";
229 
230  m_modelDigitizeCurveAfter->setCursorInnerRadius (m_spinInnerRadius->value());
231  updateControls();
232  updatePreview();
233 }
234 
235 void DlgSettingsDigitizeCurve::slotCursorLineWidth (const QString &)
236 {
237  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorLineWidth";
238 
239  m_modelDigitizeCurveAfter->setCursorLineWidth (m_spinLineWidth->value());
240  updateControls();
241  updatePreview();
242 }
243 
244 void DlgSettingsDigitizeCurve::slotCursorSize (const QString &)
245 {
246  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorSize";
247 
248  m_modelDigitizeCurveAfter->setCursorSize ((CursorSize) m_cmbSize->currentData().toInt());
249  updateControls();
250  updatePreview();
251 }
252 
253 void DlgSettingsDigitizeCurve::slotCursorStandard (bool)
254 {
255  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::slotCursorStandard";
256 
257  m_modelDigitizeCurveAfter->setCursorStandardCross(true);
258  updateControls();
259  updatePreview();
260 }
261 
262 void DlgSettingsDigitizeCurve::updateControls()
263 {
264  // Cursor has to fit into current extent
265  bool isGoodState = 2 * (m_modelDigitizeCurveAfter->cursorInnerRadius() + LINE_LENGTH_MIN) <=
266  CursorSizeToPixels (m_modelDigitizeCurveAfter->cursorSize());
267  enableOk (isGoodState);
268 
269  m_spinInnerRadius->setEnabled (m_btnCustom->isChecked());
270  m_cmbSize->setEnabled (m_btnCustom->isChecked());
271  m_spinLineWidth->setEnabled (m_btnCustom->isChecked());
272 }
273 
274 void DlgSettingsDigitizeCurve::updatePreview()
275 {
276  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsDigitizeCurve::updatePreview";
277 
278  CursorFactory cursorFactory;
279  QCursor cursor = cursorFactory.generate (*m_modelDigitizeCurveAfter);
280  m_viewPreview->setCursor (cursor);
281 }
DlgSettingsDigitizeCurve(MainWindow &mainWindow)
Single constructor.
int cursorLineWidth() const
Get method for cursor line width.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
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.
bool cursorStandardCross() const
Get method for cursor type.
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.
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
int cursorInnerRadius() const
Get method for cursor inner radius.
void setCursorInnerRadius(int innerRadius)
Set method for cursor inner radius.
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
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.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
CursorSize cursorSize() const
Get method for cursor size.
Command for DlgSettingsDigitizeCurve.
Command queue stack.
Definition: CmdMediator.h:23
Abstract base class for all Settings dialogs.
QCursor generate(const DocumentModelDigitizeCurve &modelDigitizeCurve) const
Factory method to generate standard or custom cursor.
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:77
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void setCursorStandardCross(bool cursorStandardCross)
Set method for cursor type.