Engauge Digitizer  2
DigitizeStateScale.cpp
1 /******************************************************************************************************
2  * (C) 2017 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 "CmdAddScale.h"
8 #include "CmdMediator.h"
9 #include "CursorFactory.h"
10 #include "DigitizeStateScale.h"
11 #include "DigitizeStateContext.h"
12 #include "DlgEditScale.h"
13 #include "Document.h"
14 #include "EngaugeAssert.h"
15 #include "GraphicsPoint.h"
16 #include "GraphicsScene.h"
17 #include "GraphicsView.h"
18 #include "Logger.h"
19 #include "MainWindow.h"
20 #include "PointStyle.h"
21 #include <QCursor>
22 #include <QGraphicsLineItem>
23 #include <QMessageBox>
24 #include "QtToString.h"
25 #include "ZValues.h"
26 
28  DigitizeStateAbstractBase (context),
29  m_temporaryPoint0 (0),
30  m_temporaryPoint1 (0),
31  m_line (0)
32 {
33 }
34 
35 DigitizeStateScale::~DigitizeStateScale ()
36 {
37 }
38 
40 {
41  return AXIS_CURVE_NAME;
42 }
43 
45  DigitizeState /* previousState */)
46 {
47  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::begin";
48 
49  setCursor(cmdMediator);
50  context().setDragMode(QGraphicsView::NoDrag);
52 }
53 
54 bool DigitizeStateScale::canPaste (const Transformation & /* transformation */,
55  const QSize & /* viewSize */) const
56 {
57  return false;
58 }
59 
60 QCursor DigitizeStateScale::cursor(CmdMediator *cmdMediator) const
61 {
62  LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateScale::cursor";
63 
64  CursorFactory cursorFactory;
65  QCursor cursor = cursorFactory.generate (cmdMediator->document().modelDigitizeCurve());
66 
67  return cursor;
68 }
69 
71 {
72  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::end";
73 }
74 
76  const QString &pointIdentifier)
77 {
78  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleContextMenuEventAxis "
79  << " point=" << pointIdentifier.toLatin1 ().data ();
80 }
81 
83  const QStringList &pointIdentifiers)
84 {
85  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleContextMenuEventGraph "
86  << "points=" << pointIdentifiers.join(",").toLatin1 ().data ();
87 }
88 
90 {
91  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleCurveChange";
92 }
93 
95  Qt::Key key,
96  bool /* atLeastOneSelectedItem */)
97 {
98  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleKeyPress"
99  << " key=" << QKeySequence (key).toString ().toLatin1 ().data ();
100 }
101 
103  QPointF posScreen)
104 {
105  if (m_temporaryPoint1 != 0) {
106 
107  LOG4CPP_DEBUG_S ((*mainCat)) << "DigitizeStateScale::handleMouseMove"
108  << " oldPos=" << QPointFToString (m_temporaryPoint1->pos ()).toLatin1().data()
109  << " newPos=" << QPointFToString (posScreen).toLatin1().data();
110 
111  m_temporaryPoint1->setPos (posScreen);
112 
113  updateLineGeometry();
114  }
115 }
116 
118  QPointF posScreen)
119 {
120  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleMousePress";
121 
122  GeometryWindow *NULL_GEOMETRY_WINDOW = 0;
123 
124  // Create the scale bar to give the user immediate feedback that something was created
125  const Curve &curveAxes = cmdMediator->curveAxes();
126  PointStyle pointStyleAxes = curveAxes.curveStyle().pointStyle();
127  m_pointIdentifier0 = Point::temporaryPointIdentifier();
128  m_pointIdentifier1 = m_pointIdentifier0 + "b";
129  m_temporaryPoint0 = context().mainWindow().scene().createPoint(m_pointIdentifier0,
130  pointStyleAxes,
131  posScreen,
132  NULL_GEOMETRY_WINDOW);
133  m_temporaryPoint1 = context().mainWindow().scene().createPoint(m_pointIdentifier1,
134  pointStyleAxes,
135  posScreen,
136  NULL_GEOMETRY_WINDOW);
137 
138  // Subtle stuff happening here. GraphicsPoints by default can receive focus for clicking/dragging,
139  // but for some reason that was causing the dragged second endpoint to jump to the origin the Nth
140  // time that a scale bar was created, for every N>1. So we make the endpoint passive and update
141  // its position manually in handleMouseMove
142  m_temporaryPoint0->setPassive ();
143  m_temporaryPoint1->setPassive ();
144 
145  context().mainWindow().scene().addTemporaryScaleBar (m_temporaryPoint0,
146  m_temporaryPoint1,
147  m_pointIdentifier0,
148  m_pointIdentifier1);
149 
150  m_line = new QGraphicsLineItem;
151  context().mainWindow().scene().addItem (m_line);
152  m_line->setPen (QColor (Qt::red));
153  m_line->setZValue (Z_VALUE_CURVE);
154  m_line->setVisible (true);
155 
156  updateLineGeometry ();
157 
158  // Attempts to select an endpoint right here, or after an super short timer interval
159  // failed. That would have been nice for having the click create the scale bar and, while
160  // the mouse was still pressed, selecting an endpoint thus allowing a single click-and-drag to
161  // create the scale bar. We fall back to the less elegant solution (which the user will never
162  // notice) of capturing mouse move events and using those to move an endpoint
163 }
164 
166  QPointF /* posScreen */)
167 {
168  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::handleMouseRelease";
169 
170  if (context().mainWindow().transformIsDefined()) {
171 
172  QMessageBox::warning (0,
173  QObject::tr ("Engauge Digitizer"),
174  QObject::tr ("The scale bar has been defined, and another is not needed or allowed."));
175 
176  removeTemporaryPointsAndLine ();
177 
178  } else {
179 
180  // Ask user for coordinates
181  DlgEditScale *dlg = new DlgEditScale (context ().mainWindow (),
182  cmdMediator->document().modelCoords(),
183  cmdMediator->document().modelGeneral(),
185  int rtn = dlg->exec ();
186 
187  double scaleLength = dlg->scaleLength ();
188  QPointF posScreen0 = m_temporaryPoint0->pos ();
189  QPointF posScreen1 = m_temporaryPoint1->pos ();
190  delete dlg;
191 
192  removeTemporaryPointsAndLine ();
193 
194  if (rtn == QDialog::Accepted) {
195 
196  // User wants to add this scale point. There are no additional sanity checks to run
197 
198  int nextOrdinal0 = cmdMediator->document().nextOrdinalForCurve(AXIS_CURVE_NAME);
199  int nextOrdinal1 = nextOrdinal0 + 1;
200 
201  // Create command to add point
202  Document &document = cmdMediator->document ();
203  QUndoCommand *cmd = new CmdAddScale (context ().mainWindow(),
204  document,
205  posScreen0,
206  posScreen1,
207  scaleLength,
208  nextOrdinal0,
209  nextOrdinal1);
210  context().appendNewCmd(cmdMediator,
211  cmd);
212  }
213  }
214 }
215 
216 void DigitizeStateScale::removeTemporaryPointsAndLine ()
217 {
218  context().mainWindow().scene().removePoint (m_pointIdentifier0); // Deallocates GraphicsPoint automatically
219  context().mainWindow().scene().removePoint (m_pointIdentifier1); // Deallocates GraphicsPoint automaticall
220  context().mainWindow().scene().removeItem (m_line);
221  delete m_line;
222  m_temporaryPoint0 = 0;
223  m_temporaryPoint1 = 0;
224  m_line = 0;
225 }
226 
228 {
229  return "DigitizeStateScale";
230 }
231 
233 {
234  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::updateAfterPointAddition";
235 }
236 
237 void DigitizeStateScale::updateLineGeometry ()
238 {
239  m_line->setLine (m_temporaryPoint0->pos ().x (),
240  m_temporaryPoint0->pos ().y (),
241  m_temporaryPoint1->pos ().x (),
242  m_temporaryPoint1->pos ().y ());
243 }
244 
246  const DocumentModelDigitizeCurve & /*modelDigitizeCurve */)
247 {
248  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::updateModelDigitizeCurve";
249 
250  setCursor(cmdMediator);
251 }
252 
254 {
255  LOG4CPP_INFO_S ((*mainCat)) << "DigitizeStateScale::updateModelSegments";
256 }
const Curve & curveAxes() const
See Document::curveAxes.
Definition: CmdMediator.cpp:57
void setPassive()
Prevent automatic focus on point (=make it passive) for scale bar so drags can be made to work proper...
virtual void handleMousePress(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse press 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.
void removePoint(const QString &identifier)
Remove specified point. This aborts if the point does not exist.
QPointF pos() const
Proxy method for QGraphicsItem::pos.
void setDragMode(QGraphicsView::DragMode dragMode)
Set QGraphicsView drag mode (in m_view). Called from DigitizeStateAbstractBase subclasses.
Create standard cross cursor, or custom cursor, according to settings.
Definition: CursorFactory.h:15
int nextOrdinalForCurve(const QString &curveName) const
Default next ordinal value for specified curve.
Definition: Document.cpp:759
Dialog box for editing the information of the map scale.
Definition: DlgEditScale.h:22
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
virtual void updateModelDigitizeCurve(CmdMediator *cmdMediator, const DocumentModelDigitizeCurve &modelDigitizeCurve)
Update the digitize curve settings.
void updateViewsOfSettings(const QString &activeCurve)
Update curve-specific view of settings. Private version gets active curve name from DigitizeStateCont...
DocumentModelGeneral modelGeneral() const
Get method for DocumentModelGeneral.
Definition: Document.cpp:717
void addTemporaryScaleBar(GraphicsPoint *point0, GraphicsPoint *point1, const QString &pointIdentifier0, const QString &pointIdentifier1)
Add temporary scale bar to scene.
Window that displays the geometry information, as a table, for the current curve. ...
void setPos(const QPointF pos)
Update the position.
virtual void handleMouseRelease(CmdMediator *cmdMediator, QPointF posScreen)
Handle a mouse release that was intercepted earlier.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
DigitizeStateContext & context()
Reference to the DigitizeStateContext that contains all the DigitizeStateAbstractBase subclasses...
virtual void handleCurveChange(CmdMediator *cmdMediator)
Handle the selection of a new curve. At a minimum, DigitizeStateSegment will generate a new set of Se...
MainWindow & mainWindow()
Reference to the MainWindow, without const.
static QString temporaryPointIdentifier()
Point identifier for temporary point that is used by DigitzeStateAxis.
Definition: Point.cpp:507
virtual void handleContextMenuEventGraph(CmdMediator *cmdMediator, const QStringList &pointIdentifiers)
Handle a right click, on a graph point, that was intercepted earlier.
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 QString state() const
State name for debugging.
GraphicsPoint * createPoint(const QString &identifier, const PointStyle &pointStyle, const QPointF &posScreen, GeometryWindow *geometryWindow)
Create one QGraphicsItem-based object that represents one Point. It is NOT added to m_graphicsLinesFo...
DocumentModelDigitizeCurve modelDigitizeCurve() const
Get method for DocumentModelDigitizeCurve.
Definition: Document.cpp:703
Model for DlgSettingsDigitizeCurve and CmdSettingsDigitizeCurve.
Affine transformation between screen and graph coordinates, based on digitized axis points...
Details for a specific Point.
Definition: PointStyle.h:20
virtual QString activeCurve() const
Name of the active Curve. This can include AXIS_CURVE_NAME.
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...
void appendNewCmd(CmdMediator *cmdMediator, QUndoCommand *cmd)
Append just-created QUndoCommand to command stack. This is called from DigitizeStateAbstractBase subc...
virtual void updateAfterPointAddition()
Update graphics attributes after possible new points. This is useful for highlight opacity...
Storage of one imported image and the data attached to that image.
Definition: Document.h:41
Container for one set of digitized Points.
Definition: Curve.h:33
virtual QCursor cursor(CmdMediator *cmdMediator) const
Returns the state-specific cursor shape.
MainWindowModel modelMainWindow() const
Get method for main window model.
Command for adding one scale point.
Definition: CmdAddScale.h:16
virtual void begin(CmdMediator *cmdMediator, DigitizeState previousState)
Method that is called at the exact moment a state is entered.
Command queue stack.
Definition: CmdMediator.h:23
Model for DlgSettingsSegments and CmdSettingsSegments.
CurveStyle curveStyle() const
Return the curve style.
Definition: Curve.cpp:148
Base class for all digitizing states. This serves as an interface to DigitizeStateContext.
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 end()
Method that is called at the exact moment a state is exited. Typically called just before begin for t...
DigitizeStateScale(DigitizeStateContext &context)
Single constructor.
virtual void updateModelSegments(const DocumentModelSegments &modelSegments)
Update the segments given the new settings.
double scaleLength() const
Return the scale bar length specified by the user. Only applies if dialog was accepted.
QCursor generate(const DocumentModelDigitizeCurve &modelDigitizeCurve) const
Factory method to generate standard or custom cursor.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:689