Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
DigitizeStateSelect.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 "CmdEditPointAxis.h"
8 #include "CmdEditPointGraph.h"
9 #include "CmdMediator.h"
10 #include "CmdMoveBy.h"
11 #include "DataKey.h"
12 #include "DigitizeStateContext.h"
13 #include "DigitizeStateSelect.h"
14 #include "DlgEditPointAxis.h"
15 #include "DlgEditPointGraph.h"
16 #include "EngaugeAssert.h"
17 #include "GraphicsItemsExtractor.h"
18 #include "GraphicsItemType.h"
19 #include "GraphicsScene.h"
20 #include "GraphicsView.h"
21 #include "Logger.h"
22 #include "MainWindow.h"
23 #include <QCursor>
24 #include <QGraphicsItem>
25 #include <QImage>
26 #include <QMessageBox>
27 #include <QObject>
28 #include <QtToString.h>
29 #include "Version.h"
30 
31 const QString MOVE_TEXT_DOWN (QObject::tr ("Move down"));
32 const QString MOVE_TEXT_LEFT (QObject::tr ("Move left"));
33 const QString MOVE_TEXT_RIGHT (QObject::tr ("Move right"));
34 const QString MOVE_TEXT_UP (QObject::tr ("Move up"));
35 
38 {
39 }
40 
41 DigitizeStateSelect::~DigitizeStateSelect ()
42 {
43 }
44 
46 {
48 }
49 
50 void DigitizeStateSelect::addHoverHighlighting()
51 {
52  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting";
53 
54  QList<QGraphicsItem*> items = context().mainWindow().scene().items();
55  QList<QGraphicsItem*>::iterator itr;
56  for (itr = items.begin (); itr != items.end (); itr++) {
57 
58  QGraphicsItem *item = *itr;
59  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) {
60  item->setAcceptHoverEvents(true);
61  }
62  }
63 }
64 
66  DigitizeState /* previousState */)
67 {
68  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::begin";
69 
70  setCursor(cmdMediator);
71  context().setDragMode(QGraphicsView::RubberBandDrag);
72 
73  addHoverHighlighting();
75 }
76 
77 QCursor DigitizeStateSelect::cursor(CmdMediator * /* cmdMediator */) const
78 {
79  LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::cursor";
80 
81  return QCursor (Qt::ArrowCursor);
82 }
83 
85 {
86  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::end";
87 
88  removeHoverHighlighting();
89 }
90 
92  const QString &pointIdentifier)
93 {
94  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventAxis "
95  << " point=" << pointIdentifier.toLatin1 ().data ();
96 
97  QPointF posScreen = cmdMediator->document().positionScreen (pointIdentifier);
98  QPointF posGraphBefore = cmdMediator->document().positionGraph (pointIdentifier);
99  bool isXOnly = cmdMediator->document().isXOnly (pointIdentifier);
100 
101  // Ask user for coordinates
102  double x = posGraphBefore.x();
103  double y = posGraphBefore.y();
104 
105  DlgEditPointAxis *dlg = new DlgEditPointAxis (context().mainWindow(),
106  cmdMediator->document().modelCoords(),
109  cmdMediator->document().documentAxesPointsRequired(),
110  isXOnly,
111  &x,
112  &y);
113  int rtn = dlg->exec ();
114 
115  QPointF posGraphAfter = dlg->posGraph (isXOnly); // This call returns new values for isXOnly and the graph position
116  delete dlg;
117 
118  if (rtn == QDialog::Accepted) {
119 
120  // User wants to edit this axis point, but let's perform sanity checks first
121 
122  bool isError;
123  QString errorMessage;
124 
125  context().mainWindow().cmdMediator()->document().checkEditPointAxis(pointIdentifier,
126  posScreen,
127  posGraphAfter,
128  isError,
129  errorMessage);
130 
131  if (isError) {
132 
133  QMessageBox::warning (0,
134  engaugeWindowTitle(),
135  errorMessage);
136 
137  } else {
138 
139  // Create a command to edit the point
140  CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(),
141  cmdMediator->document(),
142  pointIdentifier,
143  posGraphBefore,
144  posGraphAfter,
145  isXOnly);
146  context().appendNewCmd(cmdMediator,
147  cmd);
148  }
149  }
150 }
151 
153  const QStringList &pointIdentifiers)
154 {
155  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventGraph "
156  << "points=" << pointIdentifiers.join(",").toLatin1 ().data ();
157 
158  double *x = 0, *y = 0;
159 
160  if (pointIdentifiers.count() == 1) {
161 
162  // There is exactly one point so pass its coordinates to the dialog
163  x = new double;
164  y = new double;
165 
166  QPointF posScreenBefore = cmdMediator->document().positionScreen (pointIdentifiers.first());
167  QPointF posGraphBefore;
169  posGraphBefore);
170 
171  // Ask user for coordinates
172  *x = posGraphBefore.x();
173  *y = posGraphBefore.y();
174  }
175 
176  DlgEditPointGraph *dlg = new DlgEditPointGraph (context().mainWindow(),
177  cmdMediator->document().modelCoords(),
180  x,
181  y);
182  if (x != 0) {
183  delete x;
184  x = 0;
185  }
186 
187  if (y != 0) {
188  delete y;
189  y = 0;
190  }
191 
192  int rtn = dlg->exec ();
193 
194  bool isXGiven, isYGiven;
195  double xGiven, yGiven;
196  dlg->posGraph (isXGiven, xGiven, isYGiven, yGiven); // One or both coordinates are returned
197  delete dlg;
198 
199  if (rtn == QDialog::Accepted) {
200 
201  // Create a command to edit the point
202  CmdEditPointGraph *cmd = new CmdEditPointGraph (context().mainWindow(),
203  cmdMediator->document(),
204  pointIdentifiers,
205  isXGiven,
206  isYGiven,
207  xGiven,
208  yGiven);
209  context().appendNewCmd(cmdMediator,
210  cmd);
211  }
212 }
213 
215 {
216  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleCurveChange";
217 }
218 
220  Qt::Key key,
221  bool atLeastOneSelectedItem)
222 {
223  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleKeyPress"
224  << " key=" << QKeySequence (key).toString ().toLatin1 ().data ();
225 
226  if (atLeastOneSelectedItem) {
227 
228  if (key == Qt::Key_Down ||
229  key == Qt::Key_Up ||
230  key == Qt::Key_Left ||
231  key == Qt::Key_Right) {
232 
233  keyPressArrow (cmdMediator,
234  key);
235 
236  }
237  }
238 }
239 
241  QPointF /* posScreen */)
242 {
243 // LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::handleMouseMove";
244 }
245 
247  QPointF posScreen)
248 {
249  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMousePress"
250  << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
251 
252  // Note that GraphicsView has already called GraphicsPointAbstract::resetPositionHasChanged on all items
253 
254  m_movingStart = posScreen;
255 }
256 
258  QPointF posScreen)
259 {
260  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMouseRelease"
261  << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
262 
263  QPointF deltaScreen = posScreen - m_movingStart;
264  QStringList positionHasChangedIdentifers = context().mainWindow().scene().positionHasChangedPointIdentifiers();
265 
266  bool positionHasChanged = (positionHasChangedIdentifers.count () > 0);
267 
268  if (positionHasChanged && (
269  deltaScreen.x () != 0 ||
270  deltaScreen.y () != 0)) {
271 
272  QString moveText = moveTextFromDeltaScreen (deltaScreen);
273 
274  // Create command to move points
275  CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(),
276  cmdMediator->document(),
277  deltaScreen,
278  moveText,
279  positionHasChangedIdentifers);
280  context().appendNewCmd (cmdMediator,
281  cmd);
282 
283  } else {
284 
285  // Selection probably changed so update the MainWindow controls (especially Cut)
287 
288  }
289 }
290 
291 void DigitizeStateSelect::keyPressArrow (CmdMediator *cmdMediator,
292  Qt::Key key)
293 {
294  QPointF deltaScreen;
295  QString moveText;
296  switch (key) {
297  case Qt::Key_Down:
298  deltaScreen = QPointF (0, zoomedToUnzoomedScreenY ());
299  moveText = MOVE_TEXT_DOWN;
300  break;
301 
302  case Qt::Key_Left:
303  deltaScreen = QPointF (-1 * zoomedToUnzoomedScreenX (), 0);
304  moveText = MOVE_TEXT_LEFT;
305  break;
306 
307  case Qt::Key_Right:
308  deltaScreen = QPointF (zoomedToUnzoomedScreenX (), 0);
309  moveText = MOVE_TEXT_RIGHT;
310  break;
311 
312  case Qt::Key_Up:
313  deltaScreen = QPointF (0, -1 * zoomedToUnzoomedScreenY ());
314  moveText = MOVE_TEXT_UP;
315  break;
316 
317  default:
318  ENGAUGE_ASSERT (false);
319  }
320 
321  // Create command to move points
322  GraphicsItemsExtractor graphicsItemsExtractor;
323  const QList<QGraphicsItem*> &items = context().mainWindow().scene ().selectedItems();
324  CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(),
325  cmdMediator->document(),
326  deltaScreen,
327  moveText,
328  graphicsItemsExtractor.selectedPointIdentifiers (items));
329  context().appendNewCmd (cmdMediator,
330  cmd);
331 }
332 
333 QString DigitizeStateSelect::moveTextFromDeltaScreen (const QPointF &deltaScreen)
334 {
335  QString moveText;
336 
337  // x UP x -----> +x
338  // x x |
339  // LEFT x RIGHT |
340  // x x v
341  // x DOWN x +y
342  bool downOrRight = (deltaScreen.y () > -1.0 * deltaScreen.x ());
343  bool upOrRight = (deltaScreen.y () < deltaScreen.x ());
344  if (downOrRight && upOrRight) {
345  moveText = MOVE_TEXT_RIGHT;
346  } else if (downOrRight && !upOrRight) {
347  moveText = MOVE_TEXT_DOWN;
348  } else if (!downOrRight && upOrRight) {
349  moveText = MOVE_TEXT_UP;
350  } else {
351  moveText = MOVE_TEXT_LEFT;
352  }
353 
354  return moveText;
355 }
356 
357 void DigitizeStateSelect::removeHoverHighlighting()
358 {
359  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::removeHoverHighlighting";
360 
361  QList<QGraphicsItem*> items = context().mainWindow().scene().items();
362  QList<QGraphicsItem*>::iterator itr;
363  for (itr = items.begin (); itr != items.end (); itr++) {
364 
365  QGraphicsItem *item = *itr;
366  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) {
367  item->setAcceptHoverEvents(false);
368  }
369  }
370 }
371 
372 void DigitizeStateSelect::setHoverHighlighting(const MainWindowModel &modelMainWindow)
373 {
374  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting";
375 
376  // Set the opacity for all points. It should be already set for pre-existing points
377  QList<QGraphicsItem*> items = context().mainWindow().scene().items();
378  QList<QGraphicsItem*>::iterator itr;
379  for (itr = items.begin (); itr != items.end (); itr++) {
380 
381  QGraphicsItem *item = *itr;
382  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) {
383  item->setOpacity (modelMainWindow.highlightOpacity());
384  }
385  }
386 }
387 
389 {
390  return "DigitizeStateSelect";
391 }
392 
394 {
395  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateAfterPointAddition";
396 
397  addHoverHighlighting ();
398 }
399 
401  const DocumentModelDigitizeCurve & /*modelDigitizeCurve */)
402 {
403  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelDigitizeCurve";
404 }
405 
407 {
408  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelSegments";
409 }
410 
411 double DigitizeStateSelect::zoomedToUnzoomedScreenX () const
412 {
413  double m11 = context().mainWindow ().view ().transform().m11 ();
414  return 1.0 / m11;
415 }
416 
417 double DigitizeStateSelect::zoomedToUnzoomedScreenY () const
418 {
419  double m22 = context().mainWindow ().view ().transform().m22 ();
420  return 1.0 / m22;
421 }
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
Dialog box for editing the information of one axis point.
QPointF positionScreen(const QString &pointIdentifier) const
See Curve::positionScreen.
Definition: Document.cpp:752
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition: Document.cpp:333
bool isXOnly(const QString &pointIdentifier) const
See Curve::isXOnly.
Definition: Document.cpp:411
virtual void handleKeyPress(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
Handle a key press that was intercepted earlier.
virtual QCursor cursor(CmdMediator *cmdMediator) const
Returns the state-specific cursor shape.
Transformation transformation() const
Return read-only copy of transformation.
void setDragMode(QGraphicsView::DragMode dragMode)
Set QGraphicsView drag mode (in m_view). Called from DigitizeStateAbstractBase subclasses.
virtual void updateModelSegments(const DocumentModelSegments &modelSegments)
Update the segments given the new settings.
void updateAfterMouseRelease()
Call MainWindow::updateControls (which is private) after the very specific case - a mouse press/relea...
Command for editing the graph coordinates of one or more graph points.
virtual void handleContextMenuEventAxis(CmdMediator *cmdMediator, const QString &pointIdentifier)
Handle a right click, on an axis point, that was intercepted earlier.
virtual void handleCurveChange(CmdMediator *cmdMediator)
Handle the selection of a new curve. At a minimum, DigitizeStateSegment will generate a new set of Se...
virtual void handleMouseRelease(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse release that was intercepted earlier.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
QString selectedGraphCurve() const
Curve name that is currently selected in m_cmbCurve.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:665
Command for moving all selected Points by a specified translation.
Definition: CmdMoveBy.h:18
virtual void handleContextMenuEventGraph(CmdMediator *cmdMediator, const QStringList &pointIdentifiers)
Handle a right click, on a graph point, that was intercepted earlier.
virtual void handleMousePress(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse press that was intercepted earlier.
QPointF posGraph(bool &isXOnly) const
Return the graph coordinates position specified by the user. Only applies if dialog was accepted...
CmdMediator * cmdMediator()
Accessor for commands to process the Document.
Definition: MainWindow.cpp:310
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
virtual void updateAfterPointAddition()
Update graphics attributes after possible new points. This is useful for highlight opacity...
DigitizeStateContext & context()
Reference to the DigitizeStateContext that contains all the DigitizeStateAbstractBase subclasses...
MainWindow & mainWindow()
Reference to the MainWindow, without const.
QStringList selectedPointIdentifiers(const QList< QGraphicsItem * > &items) const
Return list of selected point identifiers.
void checkEditPointAxis(const QString &pointIdentifier, const QPointF &posScreen, const QPointF &posGraph, bool &isError, QString &errorMessage)
Check before calling editPointAxis.
Definition: Document.cpp:255
This class consolidates utility routines that deal with graphics items that are getting extracted fro...
void posGraph(bool &isX, double &x, bool &isY, double &y) const
Return one or both coordinates. Only applies if dialog was accepted.
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
virtual void begin(CmdMediator *cmdMediator, DigitizeState previousState)
Method that is called at the exact moment a state is entered.
GraphicsView & view()
View for the QImage and QGraphicsItems, without const.
QStringList positionHasChangedPointIdentifiers() const
Return a list of identifiers for the points that have moved since the last call to resetPositionHasCh...
GraphicsScene & scene()
Scene container for the QImage and QGraphicsItems.
void setCursor(CmdMediator *cmdMediator)
Update the cursor according to the current state.
Container for all DigitizeStateAbstractBase subclasses. This functions as the context class in a stan...
Model for DlgSettingsMainWindow.
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
virtual QString activeCurve() const
Name of the active Curve. This can include AXIS_CURVE_NAME.
virtual void end()
Method that is called at the exact moment a state is exited. Typically called just before begin for t...
virtual void handleMouseMove(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse move. This is part of an experiment to see if augmenting the cursor in Point Match mod...
QPointF positionGraph(const QString &pointIdentifier) const
See Curve::positionGraph.
Definition: Document.cpp:747
double highlightOpacity() const
Get method for highlight opacity.
DigitizeStateSelect(DigitizeStateContext &context)
Single constructor.
Command queue stack.
Definition: CmdMediator.h:23
Dialog box for editing the information of one or more points.
Model for DlgSettingsSegments and CmdSettingsSegments.
Base class for all digitizing states. This serves as an interface to DigitizeStateContext.
virtual QString state() const
State name for debugging.
Command for editing the graph coordinates one axis point.
virtual void updateModelDigitizeCurve(CmdMediator *cmdMediator, const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update the digitize curve settings.
MainWindowModel modelMainWindow() const
Get method for main window model.