Engauge Digitizer 2
Loading...
Searching...
No Matches
DigitizeStateSelect.cpp
Go to the documentation of this file.
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 "CallbackScaleBar.h"
8#include "CmdEditPointAxis.h"
9#include "CmdEditPointGraph.h"
10#include "CmdMediator.h"
11#include "CmdMoveBy.h"
12#include "DataKey.h"
14#include "DigitizeStateSelect.h"
15#include "DlgEditPointAxis.h"
16#include "DlgEditPointGraph.h"
17#include "DlgEditScale.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 <QSize>
29#include <QtToString.h>
30#include "Transformation.h"
31#include "Version.h"
32
37
41
46
47void DigitizeStateSelect::addHoverHighlighting()
48{
49 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting";
50
51 QList<QGraphicsItem*> items = context().mainWindow().scene().items();
52 QList<QGraphicsItem*>::iterator itr;
53 for (itr = items.begin (); itr != items.end (); itr++) {
54
55 QGraphicsItem *item = *itr;
58 item->setAcceptHoverEvents(true);
59 }
60 }
61}
62
64 DigitizeState /* previousState */)
65{
66 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::begin";
67
68 setCursor(cmdMediator);
69 context().setDragMode(QGraphicsView::RubberBandDrag);
70
71 addHoverHighlighting();
74}
75
76bool DigitizeStateSelect::canPaste (const Transformation & /* transformation */,
77 const QSize & /* viewSize */) const
78{
79 return false;
80}
81
82QCursor DigitizeStateSelect::cursor(CmdMediator * /* cmdMediator */) const
83{
84 LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::cursor";
85
86 return QCursor (Qt::ArrowCursor);
87}
88
90{
91 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::end";
92
93 removeHoverHighlighting();
94}
95
97{
98 return true;
99}
100
102 const QString &pointIdentifier)
103{
104 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventAxis "
105 << " point=" << pointIdentifier.toLatin1 ().data ();
106
108 handleContextMenuEventAxis2 (cmdMediator);
109 } else {
110 handleContextMenuEventAxis34 (cmdMediator,
111 pointIdentifier);
112 }
113}
114
115void DigitizeStateSelect::handleContextMenuEventAxis2 (CmdMediator *cmdMediator)
116{
117 LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventAxis2";
118
119 const bool IS_NOT_X_ONLY = false;
120
121 // The point identifier we want is not necessarily the one edited but is the one with the
122 // nonzero x or y (but not both) coordinate
123 QString pointIdentifier = scaleBarPointIdentifier (cmdMediator);
124
125 QPointF posScreen = cmdMediator->document().positionScreen (pointIdentifier);
126 QPointF posGraphBefore = cmdMediator->document().positionGraph (pointIdentifier);
127
128 // Ask user for scale length
129 double scaleLength = scaleBarLength (cmdMediator);
130 DlgEditScale *dlg = new DlgEditScale (context().mainWindow(),
131 cmdMediator->document().modelCoords(),
132 cmdMediator->document().modelGeneral(),
133 context().mainWindow().modelMainWindow(),
134 &scaleLength);
135 int rtn = dlg->exec ();
136
137 scaleLength = dlg->scaleLength (); // This call returns new value for scale length
138 delete dlg;
139
140 if (rtn == QDialog::Accepted) {
141
142 // User wants to edit the scale length, which is effectively editing this axis point, but let's perform sanity checks first
143
144 bool isError;
145 QString errorMessage;
146
147 bool isXNonzero = (qAbs (posGraphBefore.x()) > 0); // Identify which coordinate is to be edited
148 QPointF posGraphAfter (isXNonzero ? scaleLength : 0,
149 isXNonzero ? 0 : scaleLength);
151 posScreen,
152 posGraphAfter,
153 isError,
154 errorMessage);
155
156 if (isError) {
157
158 QMessageBox::warning (nullptr,
160 errorMessage);
161
162 } else {
163
164 // Create a command to change the scale length
165 CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(),
166 cmdMediator->document(),
167 pointIdentifier,
168 posGraphBefore,
169 posGraphAfter,
170 IS_NOT_X_ONLY);
171 context().appendNewCmd(cmdMediator,
172 cmd);
173 }
174 }
175}
176
177void DigitizeStateSelect::handleContextMenuEventAxis34 (CmdMediator *cmdMediator,
178 const QString &pointIdentifier)
179{
180 LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventAxis34";
181
182 QPointF posScreen = cmdMediator->document().positionScreen (pointIdentifier);
183 QPointF posGraphBefore = cmdMediator->document().positionGraph (pointIdentifier);
184 bool isXOnly = cmdMediator->document().isXOnly (pointIdentifier);
185
186 // Ask user for coordinates
187 double x = posGraphBefore.x();
188 double y = posGraphBefore.y();
189
190 DlgEditPointAxis *dlg = new DlgEditPointAxis (context().mainWindow(),
191 cmdMediator->document().modelCoords(),
192 cmdMediator->document().modelGeneral(),
193 context().mainWindow().modelMainWindow(),
194 context().mainWindow().transformation(),
195 cmdMediator->document().documentAxesPointsRequired(),
196 isXOnly,
197 &x,
198 &y);
199 int rtn = dlg->exec ();
200
201 QPointF posGraphAfter = dlg->posGraph (isXOnly); // This call returns new values for isXOnly and the graph position
202 delete dlg;
203
204 if (rtn == QDialog::Accepted) {
205
206 // User wants to edit this axis point, but let's perform sanity checks first
207
208 bool isError;
209 QString errorMessage;
210
212 posScreen,
213 posGraphAfter,
214 isError,
215 errorMessage);
216
217 if (isError) {
218
219 QMessageBox::warning (nullptr,
221 errorMessage);
222
223 } else {
224
225 // Create a command to edit the point
226 CmdEditPointAxis *cmd = new CmdEditPointAxis (context().mainWindow(),
227 cmdMediator->document(),
228 pointIdentifier,
229 posGraphBefore,
230 posGraphAfter,
231 isXOnly);
232 context().appendNewCmd(cmdMediator,
233 cmd);
234 }
235 }
236}
237
239 const QStringList &pointIdentifiers)
240{
241 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleContextMenuEventGraph "
242 << "points=" << pointIdentifiers.join(",").toLatin1 ().data ();
243
244 // Editing graph coordinates before the axes are defined is not useful because:
245 // 1) That functionality is for fine tuning point placement based on defined axes
246 // 2) The transformation from screen to graph coordinates below will crash
247 if (context().mainWindow().transformation().transformIsDefined()) {
248
249 double *x = nullptr, *y = nullptr;
250
251 if (pointIdentifiers.count() == 1) {
252
253 // There is exactly one point so pass its coordinates to the dialog
254 x = new double;
255 y = new double;
256
257 QPointF posScreenBefore = cmdMediator->document().positionScreen (pointIdentifiers.first());
258 QPointF posGraphBefore;
260 posGraphBefore);
261
262 // Ask user for coordinates
263 *x = posGraphBefore.x();
264 *y = posGraphBefore.y();
265 }
266
267 DlgEditPointGraph *dlg = new DlgEditPointGraph (context().mainWindow(),
268 cmdMediator->document().modelCoords(),
269 cmdMediator->document().modelGeneral(),
270 context().mainWindow().modelMainWindow(),
271 context().mainWindow().transformation(),
272 x,
273 y);
274 delete x;
275 delete y;
276
277 x = nullptr;
278 y = nullptr;
279
280 int rtn = dlg->exec ();
281
282 bool isXGiven, isYGiven;
283 double xGiven, yGiven;
284 dlg->posGraph (isXGiven, xGiven, isYGiven, yGiven); // One or both coordinates are returned
285 delete dlg;
286
287 if (rtn == QDialog::Accepted) {
288
289 // Create a command to edit the point
290 CmdEditPointGraph *cmd = new CmdEditPointGraph (context().mainWindow(),
291 cmdMediator->document(),
292 pointIdentifiers,
293 isXGiven,
294 isYGiven,
295 xGiven,
296 yGiven);
297 context().appendNewCmd(cmdMediator,
298 cmd);
299 }
300 }
301}
302
304{
305 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleCurveChange";
306}
307
309 Qt::Key key,
310 bool atLeastOneSelectedItem)
311{
312 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleKeyPress"
313 << " key=" << QKeySequence (key).toString ().toLatin1 ().data ();
314
315 handleKeyPressArrow (cmdMediator,
316 key,
317 atLeastOneSelectedItem);
318}
319
321 QPointF /* posScreen */)
322{
323// LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateSelect::handleMouseMove";
324}
325
327 QPointF posScreen)
328{
329 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMousePress"
330 << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
331
332 // Note that GraphicsView has already called GraphicsPointAbstract::resetPositionHasChanged on all items
333
334 m_movingStart = posScreen;
335}
336
338 QPointF posScreen)
339{
340 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::handleMouseRelease"
341 << " posScreen=" << QPointFToString (posScreen).toLatin1 ().data ();
342
343 QPointF deltaScreen = posScreen - m_movingStart;
344 QStringList positionHasChangedIdentifers = context().mainWindow().scene().positionHasChangedPointIdentifiers();
345
346 bool positionHasChanged = (positionHasChangedIdentifers.count () > 0);
347
348 if (positionHasChanged && (
349 qAbs (deltaScreen.x ()) > 0 ||
350 qAbs (deltaScreen.y ()) > 0)) {
351
352 QString moveText = moveTextFromDeltaScreen (deltaScreen);
353
354 // Create command to move points
355 CmdMoveBy *cmd = new CmdMoveBy (context().mainWindow(),
356 cmdMediator->document(),
357 deltaScreen,
358 moveText,
359 positionHasChangedIdentifers);
360 context().appendNewCmd (cmdMediator,
361 cmd);
362
363 } else {
364
365 // Selection probably changed so update the MainWindow controls (especially Cut)
367
368 showCoordinatesIfSinglePointIsSelected ();
369 }
370}
371
372QString DigitizeStateSelect::moveTextFromDeltaScreen (const QPointF &deltaScreen)
373{
374 QString moveText;
375
376 // x UP x -----> +x
377 // x x |
378 // LEFT x RIGHT |
379 // x x v
380 // x DOWN x +y
381 bool downOrRight = (deltaScreen.y () > -1.0 * deltaScreen.x ());
382 bool upOrRight = (deltaScreen.y () < deltaScreen.x ());
383 if (downOrRight && upOrRight) {
384 moveText = moveTextRight();
385 } else if (downOrRight && !upOrRight) {
386 moveText = moveTextDown();
387 } else if (!downOrRight && upOrRight) {
388 moveText = moveTextUp();
389 } else {
390 moveText = moveTextLeft();
391 }
392
393 return moveText;
394}
395
396void DigitizeStateSelect::removeHoverHighlighting()
397{
398 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::removeHoverHighlighting";
399
400 QList<QGraphicsItem*> items = context().mainWindow().scene().items();
401 QList<QGraphicsItem*>::iterator itr;
402 for (itr = items.begin (); itr != items.end (); itr++) {
403
404 QGraphicsItem *item = *itr;
407 item->setAcceptHoverEvents(false);
408 }
409 }
410}
411
412double DigitizeStateSelect::scaleBarLength (CmdMediator *cmdMediator) const
413{
414 CallbackScaleBar ftor;
415
416 Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
418 cmdMediator->iterateThroughCurvePointsAxes (ftorWithCallback);
419
420 return ftor.scaleBarLength ();
421}
422
423QString DigitizeStateSelect::scaleBarPointIdentifier (CmdMediator *cmdMediator) const
424{
425 CallbackScaleBar ftor;
426
427 Functor2wRet<const QString &, const Point&, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
429 cmdMediator->iterateThroughCurvePointsAxes (ftorWithCallback);
430
431 return ftor.scaleBarPointIdentifier();
432}
433
434void DigitizeStateSelect::setHoverHighlighting(const MainWindowModel &modelMainWindow)
435{
436 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::addHoverHighlighting";
437
438 // Set the opacity for all points. It should be already set for pre-existing points
439 QList<QGraphicsItem*> items = context().mainWindow().scene().items();
440 QList<QGraphicsItem*>::iterator itr;
441 for (itr = items.begin (); itr != items.end (); itr++) {
442
443 QGraphicsItem *item = *itr;
445 item->setOpacity (modelMainWindow.highlightOpacity());
446 }
447 }
448}
449
450void DigitizeStateSelect::showCoordinatesIfSinglePointIsSelected ()
451{
452 // See if there is a single point selected
453 QList<QGraphicsItem*> items = context().mainWindow().scene().selectedItems();
454 if (items.size () == 1) {
455
456 // There is a single item selected but we must see if it is a point
457 QGraphicsItem *item = * (items.begin ());
458
460
461 // Show the coordinates of the point in the status bar
462 QString coordsScreen, coordsGraph, resolutionGraph;
464 coordsScreen,
465 coordsGraph,
466 resolutionGraph,
467 context().mainWindow().modeMap());
468
469 context().mainWindow().showTemporaryMessage(coordsGraph);
470 }
471 }
472}
473
475{
476 return "DigitizeStateSelect";
477}
478
480{
481 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateAfterPointAddition";
482
483 addHoverHighlighting ();
484}
485
487 const DocumentModelDigitizeCurve & /*modelDigitizeCurve */)
488{
489 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelDigitizeCurve";
490}
491
493{
494 LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateSelect::updateModelSegments";
495}
@ DATA_KEY_GRAPHICS_ITEM_TYPE
Definition DataKey.h:15
DigitizeState
Set of possible states of Digitize toolbar.
@ DOCUMENT_AXES_POINTS_REQUIRED_2
@ GRAPHICS_ITEM_TYPE_GUIDELINE
@ GRAPHICS_ITEM_TYPE_POINT
log4cpp::Category * mainCat
Definition Logger.cpp:14
QString QPointFToString(const QPointF &pos)
QString engaugeWindowTitle()
Text for title bars of dialogs.
Definition Version.cpp:15
QString scaleBarPointIdentifier() const
Identified axis point.
double scaleBarLength() const
Length of scale bar.
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
Command for editing the graph coordinates of one or more graph points.
Command queue stack.
Definition CmdMediator.h:24
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Command for moving all selected Points by a specified translation.
Definition CmdMoveBy.h:19
QString moveTextUp() const
Display text for up arrow.
QString moveTextDown() const
Display text for down arrow.
QString moveTextLeft() const
Display text for left arrow.
virtual void handleKeyPressArrow(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
If the key is an arrow (left, right, up, down) then move currently selected items.
DigitizeStateAbstractBase(DigitizeStateContext &context)
Single constructor.
QString moveTextRight() const
Display text for right arrow.
DigitizeStateContext & context()
Reference to the DigitizeStateContext that contains all the DigitizeStateAbstractBase subclasses,...
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...
void setDragMode(QGraphicsView::DragMode dragMode)
Set QGraphicsView drag mode (in m_view). Called from DigitizeStateAbstractBase subclasses.
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
MainWindow & mainWindow()
Reference to the MainWindow, without const.
virtual void begin(CmdMediator *cmdMediator, DigitizeState previousState)
Method that is called at the exact moment a state is entered.
virtual QCursor cursor(CmdMediator *cmdMediator) const
Returns the state-specific cursor shape.
virtual bool canPaste(const Transformation &transformation, const QSize &viewSize) const
Return true if there is good data in the clipboard for pasting, and that is compatible with the curre...
virtual void updateAfterPointAddition()
Update graphics attributes after possible new points. This is useful for highlight opacity.
virtual void updateModelDigitizeCurve(CmdMediator *cmdMediator, const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update the digitize curve settings.
virtual void updateModelSegments(const DocumentModelSegments &modelSegments)
Update the segments given the new settings.
virtual void end()
Method that is called at the exact moment a state is exited. Typically called just before begin for t...
virtual QString activeCurve() const
Name of the active Curve. This can include AXIS_CURVE_NAME.
virtual void handleContextMenuEventGraph(CmdMediator *cmdMediator, const QStringList &pointIdentifiers)
Handle a right click, on a graph point, that was intercepted earlier.
virtual bool guidelinesAreSelectable() const
Enable/disable guidelines according to state.
virtual void handleMouseRelease(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse release that was intercepted earlier.
virtual void handleKeyPress(CmdMediator *cmdMediator, Qt::Key key, bool atLeastOneSelectedItem)
Handle a key press that was intercepted earlier.
virtual void handleContextMenuEventAxis(CmdMediator *cmdMediator, const QString &pointIdentifier)
Handle a right click, on an axis point, that was intercepted earlier.
virtual void handleMousePress(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse press that was intercepted earlier.
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...
virtual void handleCurveChange(CmdMediator *cmdMediator)
Handle the selection of a new curve. At a minimum, DigitizeStateSegment will generate a new set of Se...
DigitizeStateSelect(DigitizeStateContext &context)
Single constructor.
virtual QString state() const
State name for debugging.
QPointF posGraph(bool &isXOnly) const
Return the graph coordinates position specified by the user. Only applies if dialog was accepted.
Dialog box for editing the information of one or more points.
void posGraph(bool &isX, double &x, bool &isY, double &y) const
Return one or both coordinates. Only applies if dialog was accepted.
Dialog box for editing the information of the map scale.
double scaleLength() const
Return the scale bar length specified by the user. Only applies if dialog was accepted.
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
Model for DlgSettingsSegments and CmdSettingsSegments.
QPointF positionScreen(const QString &pointIdentifier) const
See Curve::positionScreen.
Definition Document.cpp:853
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition Document.cpp:735
QPointF positionGraph(const QString &pointIdentifier) const
See Curve::positionGraph.
Definition Document.cpp:848
bool isXOnly(const QString &pointIdentifier) const
See Curve::isXOnly.
Definition Document.cpp:450
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition Document.cpp:707
void checkEditPointAxis(const QString &pointIdentifier, const QPointF &posScreen, const QPointF &posGraph, bool &isError, QString &errorMessage)
Check before calling editPointAxis.
Definition Document.cpp:290
DocumentAxesPointsRequired documentAxesPointsRequired() const
Get method for DocumentAxesPointsRequired.
Definition Document.cpp:369
QStringList positionHasChangedPointIdentifiers() const
Return a list of identifiers for the points that have moved since the last call to resetPositionHasCh...
Model for DlgSettingsMainWindow.
double highlightOpacity() const
Get method for highlight opacity.
void showTemporaryMessage(const QString &temporaryMessage)
Show temporary message in status bar.
CmdMediator * cmdMediator()
Accessor for commands to process the Document.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
void handleGuidelinesActiveChange(bool active)
Handle Guidelines active status toggle.
QString selectedGraphCurve() const
Curve name that is currently selected in m_cmbCurve.
GraphicsScene & scene()
Scene container for the QImage and QGraphicsItems.
void updateAfterMouseRelease()
Call MainWindow::updateControls (which is private) after the very specific case - a mouse press/relea...
Transformation transformation() const
Return read-only copy of transformation.
Affine transformation between screen and graph coordinates, based on digitized axis points.
void coordTextForStatusBar(QPointF cursorScreen, QString &coordsScreen, QString &coordsGraph, QString &resolutionGraph, bool usingScaleBar)
Return string descriptions of cursor coordinates for status bar.
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18
#define LOG4CPP_DEBUG_S(logger)
Definition convenience.h:20