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