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