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::createOptionalSaveDefault (QHBoxLayout * /* layout */)
120 {
121 }
122 
123 void DlgSettingsPointMatch::createPreview (QGridLayout *layout,
124  int &row)
125 {
126  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createPreview";
127 
128  QLabel *labelPreview = new QLabel ("Preview");
129  layout->addWidget (labelPreview, row++, 0, 1, 4);
130 
131  m_scenePreview = new QGraphicsScene (this);
132  m_viewPreview = new ViewPreview (m_scenePreview,
133  ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
134  this);
135  m_viewPreview->setWhatsThis (tr ("Preview window shows how current settings affect "
136  "point matching, and how the marked and candidate points are displayed.\n\nThe points are separated "
137  "by the point separation value, and the maximum point size is shown as a box in the center"));
138  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
139  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
140  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
141  connect (m_viewPreview, SIGNAL (signalMouseMove (QPointF)), this, SLOT (slotMouseMove (QPointF)));
142 
143  layout->addWidget (m_viewPreview, row++, 0, 1, 4);
144 }
145 
147 {
148  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createSubPanel";
149 
150  QWidget *subPanel = new QWidget ();
151  QGridLayout *layout = new QGridLayout (subPanel);
152  subPanel->setLayout (layout);
153 
154  layout->setColumnStretch(0, 1); // Empty column
155  layout->setColumnStretch(1, 0); // Labels
156  layout->setColumnStretch(2, 0); // Controls
157  layout->setColumnStretch(3, 1); // Empty column
158 
159  int row = 0;
160  createControls (layout, row);
161  createPreview (layout, row);
162  createTemplate ();
163 
164  return subPanel;
165 }
166 
167 void DlgSettingsPointMatch::createTemplate ()
168 {
169  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::createTemplate";
170 
171  QPen pen (QBrush (Qt::black), 0);
172 
173  m_circle = new QGraphicsEllipseItem;
174  m_circle->setPen (pen);
175  m_circle->setZValue (100);
176  m_scenePreview->addItem (m_circle);
177 }
178 
180 {
181  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::handleOk";
182 
184  cmdMediator ().document(),
185  *m_modelPointMatchBefore,
186  *m_modelPointMatchAfter);
187  cmdMediator ().push (cmd);
188 
189  hide ();
190 }
191 
192 void DlgSettingsPointMatch::initializeBox ()
193 {
194  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::initializeBox";
195 
196  m_circle->setPos (cmdMediator().document().pixmap().width () / 2.0,
197  cmdMediator().document().pixmap().height () / 2.0); // Initially box is in center of preview
198 }
199 
201 {
202  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::load";
203 
204  setCmdMediator (cmdMediator);
205 
206  // Flush old data
207  if (m_modelPointMatchBefore != 0) {
208  delete m_modelPointMatchBefore;
209  }
210  if (m_modelPointMatchAfter != 0) {
211  delete m_modelPointMatchAfter;
212  }
213 
214  // Save new data
215  m_modelPointMatchBefore = new DocumentModelPointMatch (cmdMediator.document());
216  m_modelPointMatchAfter = new DocumentModelPointMatch (cmdMediator.document());
217 
218  // Sanity checks. Incoming defaults must be acceptable to the local limits
219  ENGAUGE_ASSERT (POINT_SIZE_MIN <= m_modelPointMatchAfter->maxPointSize());
220  ENGAUGE_ASSERT (POINT_SIZE_MAX > m_modelPointMatchAfter->maxPointSize());
221 
222  // Populate controls
223  m_spinPointSize->setValue(m_modelPointMatchAfter->maxPointSize());
224 
225  int indexAccepted = m_cmbAcceptedPointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorAccepted()));
226  ENGAUGE_ASSERT (indexAccepted >= 0);
227  m_cmbAcceptedPointColor->setCurrentIndex(indexAccepted);
228 
229  int indexCandidate = m_cmbCandidatePointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorCandidate()));
230  ENGAUGE_ASSERT (indexCandidate >= 0);
231  m_cmbCandidatePointColor->setCurrentIndex(indexCandidate);
232 
233  int indexRejected = m_cmbRejectedPointColor->findData(QVariant(m_modelPointMatchAfter->paletteColorRejected()));
234  ENGAUGE_ASSERT (indexRejected >= 0);
235  m_cmbRejectedPointColor->setCurrentIndex(indexRejected);
236 
237  initializeBox ();
238 
239  // Fix the preview size using an invisible boundary
240  QGraphicsRectItem *boundary = m_scenePreview->addRect (QRect (0,
241  0,
242  cmdMediator.document().pixmap().width (),
243  cmdMediator.document().pixmap().height ()));
244  boundary->setVisible (false);
245 
246  m_scenePreview->addPixmap (cmdMediator.document().pixmap());
247 
248  updateControls();
249  enableOk (false); // Disable Ok button since there not yet any changes
250  updatePreview();
251 }
252 
253 double DlgSettingsPointMatch::radiusAlongDiagonal () const
254 {
255  double maxPointSize = m_modelPointMatchAfter->maxPointSize();
256 
257  return qSqrt (2.0) * maxPointSize / 2.0;
258 }
259 
260 void DlgSettingsPointMatch::slotAcceptedPointColor (const QString &)
261 {
262  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotAcceptedPointColor";
263 
264  m_modelPointMatchAfter->setPaletteColorAccepted((ColorPalette) m_cmbAcceptedPointColor->currentData().toInt());
265 
266  updateControls();
267  updatePreview();
268 }
269 
270 void DlgSettingsPointMatch::slotCandidatePointColor (const QString &)
271 {
272  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotCandidatePointColor";
273 
274  m_modelPointMatchAfter->setPaletteColorCandidate((ColorPalette) m_cmbCandidatePointColor->currentData().toInt());
275  updateControls();
276  updatePreview();
277 }
278 
279 void DlgSettingsPointMatch::slotMaxPointSize (int maxPointSize)
280 {
281  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotMaxPointSize";
282 
283  m_modelPointMatchAfter->setMaxPointSize(maxPointSize);
284  updateControls();
285  updatePreview();
286 }
287 
288 void DlgSettingsPointMatch::slotMouseMove (QPointF pos)
289 {
290  // Move the box so it follows the mouse move, making sure to keep it entirely inside the view to
291  // prevent autoresizing by QGraphicsView
292  pos = boxPositionConstraint (pos);
293 
294  m_circle->setPos (pos);
295 }
296 
297 void DlgSettingsPointMatch::slotRejectedPointColor (const QString &)
298 {
299  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsPointMatch::slotRejectedPointColor";
300 
301  m_modelPointMatchAfter->setPaletteColorRejected((ColorPalette) m_cmbRejectedPointColor->currentData().toInt());
302  updateControls();
303  updatePreview();
304 }
305 
306 void DlgSettingsPointMatch::updateControls()
307 {
308  // All controls in this dialog are always fully validated so the ok button is always enabled (after the first change)
309  enableOk (true);
310 }
311 
312 void DlgSettingsPointMatch::updatePreview()
313 {
314  // Geometry parameters
315  double maxPointSize = m_modelPointMatchAfter->maxPointSize();
316 
317  double xLeft = -1.0 * maxPointSize / 2.0;
318  double yTop = -1.0 * maxPointSize / 2.0;
319 
320  // Update circle size
321  m_circle->setRect (xLeft,
322  yTop,
323  maxPointSize,
324  maxPointSize);
325 }
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:721
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.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:66
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.
void setPaletteColorAccepted(ColorPalette paletteColorAccepted)
Set method for accepted color.