Engauge Digitizer  2
DlgSettingsPointMatch.cpp
1 #include "CmdMediator.h"
2 #include "CmdSettingsPointMatch.h"
3 #include "DlgSettingsPointMatch.h"
4 #include "EngaugeAssert.h"
5 #include "Logger.h"
6 #include "MainWindow.h"
7 #include <QComboBox>
8 #include <QGraphicsEllipseItem>
9 #include <QGraphicsPixmapItem>
10 #include <QGraphicsRectItem>
11 #include <QGraphicsScene>
12 #include <QGridLayout>
13 #include <QLabel>
14 #include <qmath.h>
15 #include <QPen>
16 #include <QSpinBox>
17 #include "ViewPreview.h"
18 
19 const int POINT_SIZE_MAX = 1024;
20 const int POINT_SIZE_MIN = 5;
21 
23  DlgSettingsAbstractBase ("Point Match",
24  "DlgSettingsPointMatch",
25  mainWindow),
26  m_scenePreview (0),
27  m_viewPreview (0),
28  m_circle (0),
29  m_modelPointMatchBefore (0),
30  m_modelPointMatchAfter (0)
31 {
32  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::DlgSettingsPointMatch";
33 
34  QWidget *subPanel = createSubPanel ();
35  finishPanel (subPanel);
36 }
37 
38 DlgSettingsPointMatch::~DlgSettingsPointMatch()
39 {
40  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::~DlgSettingsPointMatch";
41 }
42 
43 QPointF DlgSettingsPointMatch::boxPositionConstraint(const QPointF &posIn)
44 {
45  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::boxPositionConstraint";
46 
47  double radius = radiusAlongDiagonal();
48  double diameter = 2.0 * radius;
49 
50  // Do not move any part outside the preview window or else ugly, and unwanted, shifting will occur
51  QPointF pos (posIn);
52  if (pos.x() - radius < 0) {
53  pos.setX (radius);
54  }
55 
56  if (pos.y() - radius < 0) {
57  pos.setY (radius);
58  }
59 
60  if (pos.x() + diameter > m_scenePreview->sceneRect().width ()) {
61  pos.setX (m_scenePreview->sceneRect().width() - diameter);
62  }
63 
64  if (pos.y() + diameter > m_scenePreview->sceneRect().height ()) {
65  pos.setY (m_scenePreview->sceneRect().height() - diameter);
66  }
67 
68  return pos;
69 }
70 
71 void DlgSettingsPointMatch::createControls (QGridLayout *layout,
72  int &row)
73 {
74  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createControls";
75 
76  QLabel *labelPointSize = new QLabel ("Maximum point size (pixels):");
77  layout->addWidget (labelPointSize, row, 1);
78 
79  m_spinPointSize = new QSpinBox;
80  m_spinPointSize->setWhatsThis (tr ("Select a maximum point size in pixels.\n\n"
81  "Sample match points must fit within a square box, around the cursor, having width and height "
82  "equal to this maximum.\n\n"
83  "This size is also used to determine if a region of pixels that are on, in the processed image, "
84  "should be ignored since that region is wider or taller than this limit.\n\n"
85  "This value has a lower limit"));
86  m_spinPointSize->setMinimum (POINT_SIZE_MIN);
87  m_spinPointSize->setMaximum (POINT_SIZE_MAX);
88  connect (m_spinPointSize, SIGNAL (valueChanged (int)), this, SLOT (slotMaxPointSize (int)));
89  layout->addWidget (m_spinPointSize, row++, 2);
90 
91  QLabel *labelAcceptedPointColor = new QLabel ("Accepted point color:");
92  layout->addWidget (labelAcceptedPointColor, row, 1);
93 
94  m_cmbAcceptedPointColor = new QComboBox;
95  m_cmbAcceptedPointColor->setWhatsThis (tr ("Select a color for matched points that are accepted"));
96  populateColorComboWithTransparent (*m_cmbAcceptedPointColor);
97  connect (m_cmbAcceptedPointColor, SIGNAL (activated (const QString &)), this, SLOT (slotAcceptedPointColor (const QString &))); // activated() ignores code changes
98  layout->addWidget (m_cmbAcceptedPointColor, row++, 2);
99 
100  QLabel *labelRejectedPointColor = new QLabel ("Rejected point color:");
101  layout->addWidget (labelRejectedPointColor, row, 1);
102 
103  m_cmbRejectedPointColor = new QComboBox;
104  m_cmbRejectedPointColor->setWhatsThis (tr ("Select a color for matched points that are rejected"));
105  populateColorComboWithTransparent (*m_cmbRejectedPointColor);
106  connect (m_cmbRejectedPointColor, SIGNAL (activated (const QString &)), this, SLOT (slotRejectedPointColor (const QString &))); // activated() ignores code changes
107  layout->addWidget (m_cmbRejectedPointColor, row++, 2);
108 
109  QLabel *labelCandidatePointColor = new QLabel ("Candidate point color:");
110  layout->addWidget (labelCandidatePointColor, row, 1);
111 
112  m_cmbCandidatePointColor = new QComboBox;
113  m_cmbCandidatePointColor->setWhatsThis (tr ("Select a color for the point being decided upon"));
114  populateColorComboWithTransparent (*m_cmbCandidatePointColor);
115  connect (m_cmbCandidatePointColor, SIGNAL (activated (const QString &)), this, SLOT (slotCandidatePointColor (const QString &))); // activated() ignores code changes
116  layout->addWidget (m_cmbCandidatePointColor, row++, 2);
117 }
118 
119 void DlgSettingsPointMatch::createPreview (QGridLayout *layout,
120  int &row)
121 {
122  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createPreview";
123 
124  QLabel *labelPreview = new QLabel ("Preview");
125  layout->addWidget (labelPreview, row++, 0, 1, 4);
126 
127  m_scenePreview = new QGraphicsScene (this);
128  m_viewPreview = new ViewPreview (m_scenePreview, this);
129  m_viewPreview->setWhatsThis (tr ("Preview window shows how current settings affect "
130  "point matching, and how the marked and candidate points are displayed.\n\nThe points are separated "
131  "by the point separation value, and the maximum point size is shown as a box in the center"));
132  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
133  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
134  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
135  connect (m_viewPreview, SIGNAL (signalMouseMove (QPointF)), this, SLOT (slotMouseMove (QPointF)));
136 
137  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
138 }
139 
141 {
142  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createSubPanel";
143 
144  QWidget *subPanel = new QWidget ();
145  QGridLayout *layout = new QGridLayout (subPanel);
146  subPanel->setLayout (layout);
147 
148  layout->setColumnStretch(0, 1); // Empty column
149  layout->setColumnStretch(1, 0); // Labels
150  layout->setColumnStretch(2, 0); // Controls
151  layout->setColumnStretch(3, 1); // Empty column
152 
153  int row = 0;
154  createControls (layout, row);
155  createPreview (layout, row);
156  createTemplate ();
157 
158  return subPanel;
159 }
160 
161 void DlgSettingsPointMatch::createTemplate ()
162 {
163  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createTemplate";
164 
165  QPen pen (QBrush (Qt::black), 0);
166 
167  m_circle = new QGraphicsEllipseItem;
168  m_circle->setPen (pen);
169  m_circle->setZValue (100);
170  m_scenePreview->addItem (m_circle);
171 }
172 
174 {
175  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::handleOk";
176 
178  cmdMediator ().document(),
179  *m_modelPointMatchBefore,
180  *m_modelPointMatchAfter);
181  cmdMediator ().push (cmd);
182 
183  hide ();
184 }
185 
186 void DlgSettingsPointMatch::initializeBox ()
187 {
188  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::initializeBox";
189 
190  m_circle->setPos (cmdMediator().document().pixmap().width () / 2.0,
191  cmdMediator().document().pixmap().height () / 2.0); // Initially box is in center of preview
192 }
193 
195 {
196  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::load";
197 
198  setCmdMediator (cmdMediator);
199 
200  // Flush old data
201  if (m_modelPointMatchBefore != 0) {
202  delete m_modelPointMatchBefore;
203  }
204  if (m_modelPointMatchAfter != 0) {
205  delete m_modelPointMatchAfter;
206  }
207 
208  // Save new data
209  m_modelPointMatchBefore = new DocumentModelPointMatch (cmdMediator.document());
210  m_modelPointMatchAfter = new DocumentModelPointMatch (cmdMediator.document());
211 
212  // Sanity checks. Incoming defaults must be acceptable to the local limits
213  ENGAUGE_ASSERT (POINT_SIZE_MIN <= m_modelPointMatchAfter->maxPointSize());
214  ENGAUGE_ASSERT (POINT_SIZE_MAX > m_modelPointMatchAfter->maxPointSize());
215 
216  // Populate controls
217  m_spinPointSize->setValue(m_modelPointMatchAfter->maxPointSize());
218 
219  int indexAccepted = m_cmbAcceptedPointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorAccepted()));
220  ENGAUGE_ASSERT (indexAccepted >= 0);
221  m_cmbAcceptedPointColor->setCurrentIndex(indexAccepted);
222 
223  int indexCandidate = m_cmbCandidatePointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorCandidate()));
224  ENGAUGE_ASSERT (indexCandidate >= 0);
225  m_cmbCandidatePointColor->setCurrentIndex(indexCandidate);
226 
227  int indexRejected = m_cmbRejectedPointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorRejected()));
228  ENGAUGE_ASSERT (indexRejected >= 0);
229  m_cmbRejectedPointColor->setCurrentIndex(indexRejected);
230 
231  initializeBox ();
232 
233  // Fix the preview size using an invisible boundary
234  QGraphicsRectItem *boundary = m_scenePreview->addRect (QRect (0,
235  0,
236  cmdMediator.document().pixmap().width (),
237  cmdMediator.document().pixmap().height ()));
238  boundary->setVisible (false);
239 
240  m_scenePreview->addPixmap (cmdMediator.document().pixmap());
241 
242  updateControls();
243  enableOk (false); // Disable Ok button since there not yet any changes
244  updatePreview();
245 }
246 
247 double DlgSettingsPointMatch::radiusAlongDiagonal () const
248 {
249  double maxPointSize = m_modelPointMatchAfter->maxPointSize();
250 
251  return qSqrt (2.0) * maxPointSize / 2.0;
252 }
253 
254 void DlgSettingsPointMatch::slotAcceptedPointColor (const QString &)
255 {
256  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotAcceptedPointColor";
257 
258  m_modelPointMatchAfter->setPaletteColorAccepted((ColorPalette) m_cmbAcceptedPointColor->currentData().toInt());
259 
260  updateControls();
261  updatePreview();
262 }
263 
264 void DlgSettingsPointMatch::slotCandidatePointColor (const QString &)
265 {
266  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotCandidatePointColor";
267 
268  m_modelPointMatchAfter->setPaletteColorCandidate((ColorPalette) m_cmbCandidatePointColor->currentData().toInt());
269  updateControls();
270  updatePreview();
271 }
272 
273 void DlgSettingsPointMatch::slotMaxPointSize (int maxPointSize)
274 {
275  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotMaxPointSize";
276 
277  m_modelPointMatchAfter->setMaxPointSize(maxPointSize);
278  updateControls();
279  updatePreview();
280 }
281 
282 void DlgSettingsPointMatch::slotMouseMove (QPointF pos)
283 {
284  // Move the box so it follows the mouse move, making sure to keep it entirely inside the view to
285  // prevent autoresizing by QGraphicsView
286  pos = boxPositionConstraint (pos);
287 
288  m_circle->setPos (pos);
289 }
290 
291 void DlgSettingsPointMatch::slotRejectedPointColor (const QString &)
292 {
293  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotRejectedPointColor";
294 
295  m_modelPointMatchAfter->setPaletteColorRejected((ColorPalette) m_cmbRejectedPointColor->currentData().toInt());
296  updateControls();
297  updatePreview();
298 }
299 
300 void DlgSettingsPointMatch::updateControls()
301 {
302  // All controls in this dialog are always fully validated so the ok button is always enabled (after the first change)
303  enableOk (true);
304 }
305 
306 void DlgSettingsPointMatch::updatePreview()
307 {
308  // Geometry parameters
309  double maxPointSize = m_modelPointMatchAfter->maxPointSize();
310 
311  double xLeft = -1.0 * maxPointSize / 2.0;
312  double yTop = -1.0 * maxPointSize / 2.0;
313 
314  // Update circle size
315  m_circle->setRect (xLeft,
316  yTop,
317  maxPointSize,
318  maxPointSize);
319 }
double maxPointSize() const
Get method for max point size.
Model for DlgSettingsPointMatch and CmdSettingsPointMatch.
void setPaletteColorCandidate(ColorPalette paletteColorCandidate)
Set method for candidate color.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
QPixmap pixmap() const
Return the image that is being digitized.
Definition: Document.cpp:695
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:61
Command for DlgSettingsPointMatch.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:8
void setMaxPointSize(double maxPointSize)
Set method for max point size.
void setPaletteColorRejected(ColorPalette paletteColorRejected)
Set method for rejected color.
void finishPanel(QWidget *subPanel)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
ColorPalette paletteColorCandidate() const
Get method for candidate color.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
virtual void handleOk()
Process slotOk.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
Command queue stack.
Definition: CmdMediator.h:16
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
void populateColorComboWithTransparent(QComboBox &combo)
Add colors in color palette to combobox, with transparent entry at end.
Abstract base class for all Settings dialogs.
ColorPalette paletteColorRejected() const
Get method for rejected color.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
DlgSettingsPointMatch(MainWindow &mainWindow)
Single constructor.
ColorPalette paletteColorAccepted() const
Get method for accepted color.
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:60
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void setPaletteColorAccepted(ColorPalette paletteColorAccepted)
Set method for accepted color.