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(),
107  cmdMediator->document().modelGeneral(),
110  cmdMediator->document().documentAxesPointsRequired(),
111  isXOnly,
112  &x,
113  &y);
114  int rtn = dlg->exec ();
115 
116  QPointF posGraphAfter = dlg->posGraph (isXOnly); // This call returns new values for isXOnly and the graph position
117  delete dlg;
118 
119  if (rtn == QDialog::Accepted) {
120 
121  // User wants to edit this axis point, but let's perform sanity checks first
122 
123  bool isError;
124  QString errorMessage;
125 
126  context().mainWindow().cmdMediator()->document().checkEditPointAxis(pointIdentifier,
127  posScreen,
128  posGraphAfter,
129  isError,
130  errorMessage);
131 
132  if (isError) {
133 
134  QMessageBox::warning (0,
135  engaugeWindowTitle(),
136  errorMessage);
137 
138  } else {
139 
140  // Create a command to edit the point
141  CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(),
142  cmdMediator->document(),
143  pointIdentifier,
144  posGraphBefore,
145  posGraphAfter,
146  isXOnly);
147  context().appendNewCmd(cmdMediator,
148  cmd);
149  }
150  }
151 }
152 
154  const QStringList &pointIdentifiers)
155 {
156  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventGraph "
157  << "points=" << pointIdentifiers.join(",").toLatin1 ().data ();
158 
159  double *x = 0, *y = 0;
160 
161  if (pointIdentifiers.count() == 1) {
162 
163  // There is exactly one point so pass its coordinates to the dialog
164  x = new double;
165  y = new double;
166 
167  QPointF posScreenBefore = cmdMediator->document().positionScreen (pointIdentifiers.first());
168  QPointF posGraphBefore;
170  posGraphBefore);
171 
172  // Ask user for coordinates
173  *x = posGraphBefore.x();
174  *y = posGraphBefore.y();
175  }
176 
177  DlgEditPointGraph *dlg = new DlgEditPointGraph (context().mainWindow(),
178  cmdMediator->document().modelCoords(),
179  cmdMediator->document().modelGeneral(),
182  x,
183  y);
184  if (x != 0) {
185  delete x;
186  x = 0;
187  }
188 
189  if (y != 0) {
190  delete y;
191  y = 0;
192  }
193 
194  int rtn = dlg->exec ();
195 
196  bool isXGiven, isYGiven;
197  double xGiven, yGiven;
198  dlg->posGraph (isXGiven, xGiven, isYGiven, yGiven); // One or both coordinates are returned
199  delete dlg;
200 
201  if (rtn == QDialog::Accepted) {
202 
203  // Create a command to edit the point
204  CmdEditPointGraph *cmd = new CmdEditPointGraph (context().mainWindow(),
205  cmdMediator->document(),
206  pointIdentifiers,
207  isXGiven,
208  isYGiven,
209  xGiven,
210  yGiven);
211  context().appendNewCmd(cmdMediator,
212  cmd);
213  }
214 }
215 
217 {
218  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleCurveChange";
219 }
220 
222  Qt::Key key,
223  bool atLeastOneSelectedItem)
224 {
225  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleKeyPress"
226  << " key=" << QKeySequence (key).toString ().toLatin1 ().data ();
227 
228  if (atLeastOneSelectedItem) {
229 
230  if (key == Qt::Key_Down ||
231  key == Qt::Key_Up ||
232  key == Qt::Key_Left ||
233  key == Qt::Key_Right) {
234 
235  keyPressArrow (cmdMediator,
236  key);
237 
238  }
239  }
240 }
241 
243  QPointF /* posScreen */)
244 {
245 // LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::handleMouseMove";
246 }
247 
249  QPointF posScreen)
250 {
251  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMousePress"
252  << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
253 
254  // Note that GraphicsView has already called GraphicsPointAbstract::resetPositionHasChanged on all items
255 
256  m_movingStart = posScreen;
257 }
258 
260  QPointF posScreen)
261 {
262  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMouseRelease"
263  << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
264 
265  QPointF deltaScreen = posScreen - m_movingStart;
266  QStringList positionHasChangedIdentifers = context().mainWindow().scene().positionHasChangedPointIdentifiers();
267 
268  bool positionHasChanged = (positionHasChangedIdentifers.count () > 0);
269 
270  if (positionHasChanged && (
271  deltaScreen.x () != 0 ||
272  deltaScreen.y () != 0)) {
273 
274  QString moveText = moveTextFromDeltaScreen (deltaScreen);
275 
276  // Create command to move points
277  CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(),
278  cmdMediator->document(),
279  deltaScreen,
280  moveText,
281  positionHasChangedIdentifers);
282  context().appendNewCmd (cmdMediator,
283  cmd);
284 
285  } else {
286 
287  // Selection probably changed so update the MainWindow controls (especially Cut)
289 
290  }
291 }
292 
293 void DigitizeStateSelect::keyPressArrow (CmdMediator *cmdMediator,
294  Qt::Key key)
295 {
296  QPointF deltaScreen;
297  QString moveText;
298  switch (key) {
299  case Qt::Key_Down:
300  deltaScreen = QPointF (0, zoomedToUnzoomedScreenY ());
301  moveText = MOVE_TEXT_DOWN;
302  break;
303 
304  case Qt::Key_Left:
305  deltaScreen = QPointF (-1 * zoomedToUnzoomedScreenX (), 0);
306  moveText = MOVE_TEXT_LEFT;
307  break;
308 
309  case Qt::Key_Right:
310  deltaScreen = QPointF (zoomedToUnzoomedScreenX (), 0);
311  moveText = MOVE_TEXT_RIGHT;
312  break;
313 
314  case Qt::Key_Up:
315  deltaScreen = QPointF (0, -1 * zoomedToUnzoomedScreenY ());
316  moveText = MOVE_TEXT_UP;
317  break;
318 
319  default:
320  ENGAUGE_ASSERT (false);
321  }
322 
323  // Create command to move points
324  GraphicsItemsExtractor graphicsItemsExtractor;
325  const QList<QGraphicsItem*> &items = context().mainWindow().scene ().selectedItems();
326  CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(),
327  cmdMediator->document(),
328  deltaScreen,
329  moveText,
330  graphicsItemsExtractor.selectedPointIdentifiers (items));
331  context().appendNewCmd (cmdMediator,
332  cmd);
333 }
334 
335 QString DigitizeStateSelect::moveTextFromDeltaScreen (const QPointF &deltaScreen)
336 {
337  QString moveText;
338 
339  // x UP x -----> +x
340  // x x |
341  // LEFT x RIGHT |
342  // x x v
343  // x DOWN x +y
344  bool downOrRight = (deltaScreen.y () > -1.0 * deltaScreen.x ());
345  bool upOrRight = (deltaScreen.y () < deltaScreen.x ());
346  if (downOrRight && upOrRight) {
347  moveText = MOVE_TEXT_RIGHT;
348  } else if (downOrRight && !upOrRight) {
349  moveText = MOVE_TEXT_DOWN;
350  } else if (!downOrRight && upOrRight) {
351  moveText = MOVE_TEXT_UP;
352  } else {
353  moveText = MOVE_TEXT_LEFT;
354  }
355 
356  return moveText;
357 }
358 
359 void DigitizeStateSelect::removeHoverHighlighting()
360 {
361  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::removeHoverHighlighting";
362 
363  QList<QGraphicsItem*> items = context().mainWindow().scene().items();
364  QList<QGraphicsItem*>::iterator itr;
365  for (itr = items.begin (); itr != items.end (); itr++) {
366 
367  QGraphicsItem *item = *itr;
368  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) {
369  item->setAcceptHoverEvents(false);
370  }
371  }
372 }
373 
374 void DigitizeStateSelect::setHoverHighlighting(const MainWindowModel &modelMainWindow)
375 {
376  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting";
377 
378  // Set the opacity for all points. It should be already set for pre-existing points
379  QList<QGraphicsItem*> items = context().mainWindow().scene().items();
380  QList<QGraphicsItem*>::iterator itr;
381  for (itr = items.begin (); itr != items.end (); itr++) {
382 
383  QGraphicsItem *item = *itr;
384  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE) == GRAPHICS_ITEM_TYPE_POINT) {
385  item->setOpacity (modelMainWindow.highlightOpacity());
386  }
387  }
388 }
389 
391 {
392  return "DigitizeStateSelect";
393 }
394 
396 {
397  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateAfterPointAddition";
398 
399  addHoverHighlighting ();
400 }
401 
403  const DocumentModelDigitizeCurve & /*modelDigitizeCurve */)
404 {
405  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelDigitizeCurve";
406 }
407 
409 {
410  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelSegments";
411 }
412 
413 double DigitizeStateSelect::zoomedToUnzoomedScreenX () const
414 {
415  double m11 = context().mainWindow ().view ().transform().m11 ();
416  return 1.0 / m11;
417 }
418 
419 double DigitizeStateSelect::zoomedToUnzoomedScreenY () const
420 {
421  double m22 = context().mainWindow ().view ().transform().m22 ();
422  return 1.0 / m22;
423 }
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.
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:693