pappsomspp
Library for mass spectrometry
baseplotwidget.cpp
Go to the documentation of this file.
1 /* This code comes right from the msXpertSuite software project.
2  *
3  * msXpertSuite - mass spectrometry software suite
4  * -----------------------------------------------
5  * Copyright(C) 2009,...,2018 Filippo Rusconi
6  *
7  * http://www.msxpertsuite.org
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  *
22  * END software license
23  */
24 
25 
26 /////////////////////// StdLib includes
27 #include <vector>
28 
29 
30 /////////////////////// Qt includes
31 #include <QVector>
32 
33 
34 /////////////////////// Local includes
35 #include "baseplotwidget.h"
36 #include "../../pappsoexception.h"
37 
38 
39 int basePlotContextMetaTypeId = qRegisterMetaType<pappso::BasePlotContext>("pappso::BasePlotContext");
40 int basePlotContextPtrMetaTypeId = qRegisterMetaType<pappso::BasePlotContext *>("pappso::BasePlotContext *");
41 
42 
43 namespace pappso
44 {
45 
46 QString
48 {
49  QString text("Context:");
50 
51  text += QString("data kind: %1").arg(static_cast<int>(dataKind));
52 
53  text += QString(" isMouseDragging: %1 -- wasMouseDragging: %2")
54  .arg(isMouseDragging ? "true" : "false")
55  .arg(wasMouseDragging ? "true" : "false");
56 
57  text += QString(" -- startDragPoint : (%1, %2)")
58  .arg(startDragPoint.x())
59  .arg(startDragPoint.y());
60 
61  text += QString(" -- currentDragPoint : (%1, %2)")
62  .arg(currentDragPoint.x())
63  .arg(currentDragPoint.y());
64 
65  text += QString(" -- lastCursorHoveredPoint : (%1, %2)")
66  .arg(lastCursorHoveredPoint.x())
67  .arg(lastCursorHoveredPoint.y());
68 
69  text += QString(" -- xRange: (%1, %2)").arg(xRange.lower).arg(xRange.upper);
70 
71  text += QString(" -- yRange: (%1, %2)").arg(yRange.lower).arg(yRange.upper);
72 
73  text +=
74  QString(" -- wasClickOnXAxis: %1").arg(wasClickOnXAxis ? "true" : "false");
75  text +=
76  QString(" -- wasClickOnYAxis: %1").arg(wasClickOnYAxis ? "true" : "false");
77  text += QString(" -- isMeasuringDistance: %1")
78  .arg(isMeasuringDistance ? "true" : "false");
79 
80  text += QString(" -- xRegionRangeStart: %1 -- xRegionRangeEnd: %2")
81  .arg(xRegionRangeStart)
82  .arg(xRegionRangeEnd);
83 
84  text += QString(" -- yRegionRangeStart: %1 -- yRegionRangeEnd: %2")
85  .arg(yRegionRangeStart)
86  .arg(yRegionRangeEnd);
87 
88  text += QString(" -- xDelta: %1 -- yDelta: %2").arg(xDelta).arg(yDelta);
89 
90  text += QString(" -- pressedKeyCode: %1").arg(pressedKeyCode);
91 
92  text += QString(" -- keyboardModifiers: %1").arg(keyboardModifiers);
93 
94  text += QString(" -- lastPressedMouseButton: %1").arg(lastPressedMouseButton);
95 
96  text +=
97  QString(" -- lastReleasedMouseButton: %1").arg(lastReleasedMouseButton);
98 
99  text += QString(" -- pressedMouseButtons: %1").arg(pressedMouseButtons);
100 
101  text +=
102  QString(" -- mouseButtonsAtMousePress: %1").arg(mouseButtonsAtMousePress);
103 
104  text += QString(" -- mouseButtonsAtMouseRelease: %1")
106 
107  return text;
108 }
109 
110 
111 BasePlotWidget::BasePlotWidget(QWidget *parent) : QCustomPlot(parent)
112 {
113  // qDebug();
114 
115  if(parent == nullptr)
116  qFatal("Programming error.");
117 
118  // Default settings for the pen used to graph the data.
119  m_pen.setStyle(Qt::SolidLine);
120  m_pen.setBrush(Qt::black);
121  m_pen.setWidth(1);
122 
123  if(!setupWidget())
124  qFatal("Programming error.");
125 
126  show();
127 }
128 
129 
131  const QString &x_axis_label,
132  const QString &y_axis_label)
133  : QCustomPlot(parent), m_axisLabelX(x_axis_label), m_axisLabelY(y_axis_label)
134 {
135  // qDebug();
136 
137  if(parent == nullptr)
138  qFatal("Programming error.");
139 
140  // Default settings for the pen used to graph the data.
141  m_pen.setStyle(Qt::SolidLine);
142  m_pen.setBrush(Qt::black);
143  m_pen.setWidth(1);
144 
145  xAxis->setLabel(x_axis_label);
146  yAxis->setLabel(y_axis_label);
147 
148  if(!setupWidget())
149  qFatal("Programming error.");
150 
151  show();
152 }
153 
154 
155 //! Destruct \c this BasePlotWidget instance.
156 /*!
157 
158  The destruction involves clearing the history, deleting all the axis range
159  history items for x and y axes.
160 
161 */
163 {
164  // qDebug() << "In the destructor of plot widget:" << this;
165 
166  m_xAxisRangeHistory.clear();
167  m_yAxisRangeHistory.clear();
168 }
169 
170 
171 bool
173 {
174  // qDebug();
175 
176  // By default the widget comes with a graph. Remove it.
177 
178  if(graphCount())
179  removeGraph(0);
180 
181  // This is required so that we get the keyboard events.
182  setFocusPolicy(Qt::StrongFocus);
183  setInteractions(QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iMultiSelect);
184 
185  // Make a copy of the pen to just change its color and set that color to
186  // the tracer line.
187  QPen pen = m_pen;
188 
189  // Create the lines that will act as tracers for position and selection of
190  // regions.
191  //
192  // We have the cross hair that serves as the cursor. That crosshair cursor is
193  // made of a vertical line (green, because when click-dragging the mouse it
194  // becomes the tracer that is being anchored at the region start. The second
195  // line i horizontal and is always black.
196 
197  pen.setColor(QColor("black"));
198 
199  // The set of tracers (horizontal and vertical) that track the position of the
200  // mouse cursor.
201  mp_vPosTracerItem = new QCPItemLine(this);
202  mp_vPosTracerItem->setPen(m_pen);
203  mp_vPosTracerItem->start->setType(QCPItemPosition::ptPlotCoords);
204  mp_vPosTracerItem->end->setType(QCPItemPosition::ptPlotCoords);
205  mp_vPosTracerItem->start->setCoords(0, 0);
206  mp_vPosTracerItem->end->setCoords(0, 0);
207 
208  mp_hPosTracerItem = new QCPItemLine(this);
209  mp_hPosTracerItem->setPen(m_pen);
210  mp_hPosTracerItem->start->setType(QCPItemPosition::ptPlotCoords);
211  mp_hPosTracerItem->end->setType(QCPItemPosition::ptPlotCoords);
212  mp_hPosTracerItem->start->setCoords(0, 0);
213  mp_hPosTracerItem->end->setCoords(0, 0);
214 
215  // The set of tracers (horizontal only) that track the region
216  // spanning/selection regions.
217  //
218  // The start vertical tracer is colored in greeen.
219  pen.setColor(QColor("green"));
220 
221  mp_vStartTracerItem = new QCPItemLine(this);
222  mp_vStartTracerItem->setPen(pen);
223  mp_vStartTracerItem->start->setType(QCPItemPosition::ptPlotCoords);
224  mp_vStartTracerItem->end->setType(QCPItemPosition::ptPlotCoords);
225  mp_vStartTracerItem->start->setCoords(0, 0);
226  mp_vStartTracerItem->end->setCoords(0, 0);
227 
228  // The end vertical tracer is colored in red.
229  pen.setColor(QColor("red"));
230 
231  mp_vEndTracerItem = new QCPItemLine(this);
232  mp_vEndTracerItem->setPen(pen);
233  mp_vEndTracerItem->start->setType(QCPItemPosition::ptPlotCoords);
234  mp_vEndTracerItem->end->setType(QCPItemPosition::ptPlotCoords);
235  mp_vEndTracerItem->start->setCoords(0, 0);
236  mp_vEndTracerItem->end->setCoords(0, 0);
237 
238  mp_zoomRectItem = new QCPItemRect(this);
239  mp_zoomRectItem->setPen(m_pen);
240  mp_zoomRectItem->topLeft->setType(QCPItemPosition::ptPlotCoords);
241  mp_zoomRectItem->bottomRight->setType(QCPItemPosition::ptPlotCoords);
242  mp_zoomRectItem->setVisible(false);
243 
244  mp_selectLineItem = new QCPItemLine(this);
245  mp_selectLineItem->setPen(m_pen);
246  mp_selectLineItem->start->setType(QCPItemPosition::ptPlotCoords);
247  mp_selectLineItem->end->setType(QCPItemPosition::ptPlotCoords);
248  mp_selectLineItem->setVisible(false);
249 
250  // When the user click-drags the mouse, the X distance between the drag start
251  // point and the drag end point (current point) is the xDelta.
252  mp_xDeltaTextItem = new QCPItemText(this);
253  mp_xDeltaTextItem->setPositionAlignment(Qt::AlignBottom | Qt::AlignCenter);
254  mp_xDeltaTextItem->position->setType(QCPItemPosition::ptPlotCoords);
255  mp_xDeltaTextItem->setVisible(false);
256 
257  // We want to capture the signals emitted by the QCustomPlot base class.
258  connect(
259  this, &QCustomPlot::mouseMove, this, &BasePlotWidget::mouseMoveHandler);
260 
261  connect(this,
262  &QCustomPlot::mousePress,
263  this,
265 
266  connect(this,
267  &QCustomPlot::mouseRelease,
268  this,
270 
271  connect(this,
272  &QCustomPlot::axisDoubleClick,
273  this,
275 
276  return true;
277 }
278 
279 
280 void
281 BasePlotWidget::setPen(const QPen &pen)
282 {
283  m_pen = pen;
284 }
285 
286 
287 const QPen &
289 {
290  return m_pen;
291 }
292 
293 
294 void
295 BasePlotWidget::setPlottingColor(QCPAbstractPlottable *plottable_p,
296  const QColor &new_color)
297 {
298  if(plottable_p == nullptr)
299  qFatal("Pointer cannot be nullptr.");
300 
301  // First this single-graph widget
302  QPen pen;
303 
304  pen = plottable_p->pen();
305  pen.setColor(new_color);
306  plottable_p->setPen(pen);
307 
308  replot();
309 }
310 
311 
312 void
313 BasePlotWidget::setPlottingColor(int index, const QColor &new_color)
314 {
315  if(!new_color.isValid())
316  return;
317 
318  QCPGraph *graph_p = graph(index);
319 
320  if(graph_p == nullptr)
321  qFatal("Programming error.");
322 
323  return setPlottingColor(graph_p, new_color);
324 }
325 
326 
327 QColor
328 BasePlotWidget::getPlottingColor(QCPAbstractPlottable *plottable_p) const
329 {
330  if(plottable_p == nullptr)
331  qFatal("Programming error.");
332 
333  return plottable_p->pen().color();
334 }
335 
336 
337 QColor
339 {
340  QCPGraph *graph_p = graph(index);
341 
342  if(graph_p == nullptr)
343  qFatal("Programming error.");
344 
345  return getPlottingColor(graph_p);
346 }
347 
348 
349 void
350 BasePlotWidget::setAxisLabelX(const QString &label)
351 {
352  xAxis->setLabel(label);
353 }
354 
355 
356 void
357 BasePlotWidget::setAxisLabelY(const QString &label)
358 {
359  yAxis->setLabel(label);
360 }
361 
362 
363 // AXES RANGE HISTORY-related functions
364 void
366 {
367  m_xAxisRangeHistory.clear();
368  m_yAxisRangeHistory.clear();
369 
370  m_xAxisRangeHistory.push_back(new QCPRange(xAxis->range()));
371  m_yAxisRangeHistory.push_back(new QCPRange(yAxis->range()));
372 
373  // qDebug() << "size of history:" << m_xAxisRangeHistory.size()
374  //<< "setting index to 0";
375 
376  // qDebug() << "resetting axes history to values:" << xAxis->range().lower
377  //<< "--" << xAxis->range().upper << "and" << yAxis->range().lower
378  //<< "--" << yAxis->range().upper;
379 
381 }
382 
383 
384 //! Create new axis range history items and append them to the history.
385 /*!
386 
387  The plot widget is queried to get the current x/y-axis ranges and the
388  current ranges are appended to the history for x-axis and for y-axis.
389 
390 */
391 void
393 {
394  m_xAxisRangeHistory.push_back(new QCPRange(xAxis->range()));
395  m_yAxisRangeHistory.push_back(new QCPRange(yAxis->range()));
396 
398 
399  // qDebug() << "axes history size:" << m_xAxisRangeHistory.size()
400  //<< "current index:" << m_lastAxisRangeHistoryIndex
401  //<< xAxis->range().lower << "--" << xAxis->range().upper
402  //<< "and"
403  //<< yAxis->range().lower << "--" << yAxis->range().upper;
404 }
405 
406 
407 //! Go up one history element in the axis history.
408 /*!
409 
410  If possible, back up one history item in the axis histories and update the
411  plot's x/y-axis ranges to match that history item.
412 
413 */
414 void
416 {
417  // qDebug() << "axes history size:" << m_xAxisRangeHistory.size()
418  //<< "current index:" << m_lastAxisRangeHistoryIndex;
419 
421  {
422  // qDebug() << "current index is 0 returning doing nothing";
423 
424  return;
425  }
426 
427  // qDebug() << "setting index to:" << m_lastAxisRangeHistoryIndex - 1
428  //<< "and restoring axes history to that index";
429 
431 }
432 
433 
434 //! Get the axis histories at index \p index and update the plot ranges.
435 /*!
436 
437  \param index index at which to select the axis history item.
438 
439  \sa updateAxesRangeHistory().
440 
441 */
442 void
444 {
445  // qDebug() << "axes history size:" << m_xAxisRangeHistory.size()
446  //<< "current index:" << m_lastAxisRangeHistoryIndex
447  //<< "asking to restore index:" << index;
448 
449  if(index >= m_xAxisRangeHistory.size())
450  {
451  // qDebug() << "index >= history size. Returning.";
452  return;
453  }
454 
455  xAxis->setRange(*(m_xAxisRangeHistory.at(index)));
456  yAxis->setRange(*(m_yAxisRangeHistory.at(index)));
457 
459 
460  mp_vPosTracerItem->setVisible(false);
461  mp_hPosTracerItem->setVisible(false);
462 
463  mp_vStartTracerItem->setVisible(false);
464  mp_vEndTracerItem->setVisible(false);
465 
466 
467  // The start trace will keep beeing represented at the last position and last
468  // size even if we call this function repetitively. So actually do not show,
469  // it will reappare as soon as the mouse is moved.
470  // if(m_shouldTracersBeVisible)
471  //{
472  // mp_vStartTracerItem->setVisible(true);
473  //}
474 
475  replot();
476 
478 
479  // qDebug() << "restored axes history to index:" << index
480  //<< "with values:" << xAxis->range().lower << "--"
481  //<< xAxis->range().upper << "and" << yAxis->range().lower << "--"
482  //<< yAxis->range().upper;
483 
485 }
486 // AXES RANGE HISTORY-related functions
487 
488 
489 /// KEYBOARD-related EVENTS
490 void
492 {
493  // qDebug() << "ENTER";
494 
495  // We need this because some keys modify our behaviour.
496  m_context.pressedKeyCode = event->key();
497  m_context.keyboardModifiers = QGuiApplication::queryKeyboardModifiers();
498 
499  if(event->key() == Qt::Key_Left || event->key() == Qt::Key_Right ||
500  event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)
501  {
502  return directionKeyPressEvent(event);
503  }
504  else if(event->key() == m_leftMousePseudoButtonKey ||
505  event->key() == m_rightMousePseudoButtonKey)
506  {
507  return mousePseudoButtonKeyPressEvent(event);
508  }
509 
510  // Do not do anything here, because this function is used by derived classes
511  // that will emit the signal below. Otherwise there are going to be multiple
512  // signals sent.
513  // qDebug() << "Going to emit keyPressEventSignal(m_context);";
514  // emit keyPressEventSignal(m_context);
515 }
516 
517 
518 //! Handle specific key codes and trigger respective actions.
519 void
521 {
522  m_context.releasedKeyCode = event->key();
523 
524  // The keyboard key is being released, set the key code to 0.
526  m_context.keyboardModifiers = QGuiApplication::queryKeyboardModifiers();
527 
528  // Now test if the key that was released is one of the housekeeping keys.
529  if(event->key() == Qt::Key_Backspace)
530  {
531  // The user wants to iterate back in the x/y axis range history.
533 
534  event->accept();
535  }
536  else if(event->key() == Qt::Key_Space)
537  {
538  return spaceKeyReleaseEvent(event);
539  }
540  else if(event->key() == Qt::Key_Delete)
541  {
542  // The user wants to delete a graph. What graph is to be determined
543  // programmatically:
544 
545  // If there is a single graph, then that is the graph to be removed.
546  // If there are more than one graph, then only the ones that are selected
547  // are to be removed.
548 
549  // Note that the user of this widget might want to provide the user with
550  // the ability to specify if all the children graph needs to be removed
551  // also. This can be coded in key modifiers. So provide the context.
552 
553  int graph_count = plottableCount();
554 
555  if(!graph_count)
556  {
557  // qDebug() << "Not a single graph in the plot widget. Doing
558  // nothing.";
559 
560  event->accept();
561  return;
562  }
563 
564  if(graph_count == 1)
565  {
566  // qDebug() << "A single graph is in the plot widget. Emitting a graph
567  // " "destruction requested signal for it:"
568  //<< graph();
569 
570  emit plottableDestructionRequestedSignal(this, graph(), m_context);
571  }
572  else
573  {
574  // At this point we know there are more than one graph in the plot
575  // widget. We need to get the selected one (if any).
576  QList<QCPGraph *> selected_graph_list;
577 
578  selected_graph_list = selectedGraphs();
579 
580  if(!selected_graph_list.size())
581  {
582  event->accept();
583  return;
584  }
585 
586  // qDebug() << "Number of selected graphs to be destrobyed:"
587  //<< selected_graph_list.size();
588 
589  for(int iter = 0; iter < selected_graph_list.size(); ++iter)
590  {
591  // qDebug()
592  //<< "Emitting a graph destruction requested signal for graph:"
593  //<< selected_graph_list.at(iter);
594 
596  this, selected_graph_list.at(iter), m_context);
597 
598  // We do not do this, because we want the slot called by the
599  // signal above to handle that removal. Remember that it is not
600  // possible to delete graphs manually.
601  //
602  // removeGraph(selected_graph_list.at(iter));
603  }
604  event->accept();
605  }
606  }
607  // End of
608  // else if(event->key() == Qt::Key_Delete)
609  else if(event->key() == Qt::Key_T)
610  {
611  // The user wants to toggle the visibiity of the tracers.
613 
615  hideTracers();
616  else
617  showTracers();
618 
619  event->accept();
620  }
621  else if(event->key() == Qt::Key_Left || event->key() == Qt::Key_Right ||
622  event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)
623  {
624  return directionKeyReleaseEvent(event);
625  }
626  else if(event->key() == m_leftMousePseudoButtonKey ||
627  event->key() == m_rightMousePseudoButtonKey)
628  {
629  return mousePseudoButtonKeyReleaseEvent(event);
630  }
631 
632  // At this point emit the signal, since we did not treat it. Maybe the
633  // consumer widget wants to know that the keyboard key was released.
634 
636 }
637 
638 
639 void
641 {
642  // qDebug();
643 }
644 
645 
646 void
648 {
649  // qDebug() << "event key:" << event->key();
650 
651  // The user is trying to move the positional cursor/markers. There are
652  // multiple way they can do that:
653  //
654  // 1.a. Hitting the arrow left/right keys alone will search for next pixel.
655  // 1.b. Hitting the arrow left/right keys with Alt modifier will search for a
656  // multiple of pixels that might be equivalent to one 20th of the pixel width
657  // of the plot widget.
658  // 1.c Hitting the left/right keys with Alt and Shift modifiers will search
659  // for a multiple of pixels that might be the equivalent to half of the pixel
660  // width.
661  //
662  // 2. Hitting the Control modifier will move the cursor to the next data point
663  // of the graph.
664 
665  int pixel_increment = 0;
666 
667  if(m_context.keyboardModifiers == Qt::NoModifier)
668  pixel_increment = 1;
669  else if(m_context.keyboardModifiers == Qt::AltModifier)
670  pixel_increment = 50;
671 
672  // The user is moving the positional markers. This is equivalent to a
673  // non-dragging cursor movement to the next pixel. Note that the origin is
674  // located at the top left, so key down increments and key up decrements.
675 
676  if(event->key() == Qt::Key_Left)
677  horizontalMoveMouseCursorCountPixels(-pixel_increment);
678  else if(event->key() == Qt::Key_Right)
679  horizontalMoveMouseCursorCountPixels(pixel_increment);
680  else if(event->key() == Qt::Key_Up)
681  verticalMoveMouseCursorCountPixels(-pixel_increment);
682  else if(event->key() == Qt::Key_Down)
683  verticalMoveMouseCursorCountPixels(pixel_increment);
684 
685  event->accept();
686 }
687 
688 
689 void
691 {
692  // qDebug() << "event key:" << event->key();
693  event->accept();
694 }
695 
696 
697 void
699 {
700  // qDebug();
701 }
702 
703 
704 void
706 {
707 
708  QPointF pixel_coordinates(
709  xAxis->coordToPixel(m_context.lastCursorHoveredPoint.x()),
710  yAxis->coordToPixel(m_context.lastCursorHoveredPoint.y()));
711 
712  Qt::MouseButton button = Qt::NoButton;
713  QEvent::Type q_event_type = QEvent::MouseButtonPress;
714 
715  if(event->key() == m_leftMousePseudoButtonKey)
716  {
717  // Toggles the left mouse button on/off
718 
719  button = Qt::LeftButton;
720 
723 
725  q_event_type = QEvent::MouseButtonPress;
726  else
727  q_event_type = QEvent::MouseButtonRelease;
728  }
729  else if(event->key() == m_rightMousePseudoButtonKey)
730  {
731  // Toggles the right mouse button.
732 
733  button = Qt::RightButton;
734 
737 
739  q_event_type = QEvent::MouseButtonPress;
740  else
741  q_event_type = QEvent::MouseButtonRelease;
742  }
743 
744  // qDebug() << "pressed/released pseudo button:" << button
745  //<< "q_event_type:" << q_event_type;
746 
747  // Synthesize a QMouseEvent and use it.
748 
749  QMouseEvent *mouse_event_p =
750  new QMouseEvent(q_event_type,
751  pixel_coordinates,
752  mapToGlobal(pixel_coordinates.toPoint()),
753  mapToGlobal(pixel_coordinates.toPoint()),
754  button,
755  button,
757  Qt::MouseEventSynthesizedByApplication);
758 
759  if(q_event_type == QEvent::MouseButtonPress)
760  mousePressHandler(mouse_event_p);
761  else
762  mouseReleaseHandler(mouse_event_p);
763 
764  // event->accept();
765 }
766 /// KEYBOARD-related EVENTS
767 
768 
769 /// MOUSE-related EVENTS
770 
771 void
773 {
774  // When the user clicks this widget it has to take focus.
775  setFocus();
776 
777  QPointF mousePoint = event->localPos();
778 
779  m_context.lastPressedMouseButton = event->button();
780  m_context.mouseButtonsAtMousePress = event->buttons();
781 
782  // The pressedMouseButtons must continually inform on the status of pressed
783  // buttons so add the pressed button.
784  m_context.pressedMouseButtons |= event->button();
785 
786  // qDebug().noquote() << m_context.toString();
787 
788  // In all the processing of the events, we need to know if the user is
789  // clicking somewhere with the intent to change the plot ranges (reframing
790  // or rescaling the plot).
791  //
792  // Reframing the plot means that the new x and y axes ranges are modified so
793  // that they match the region that the user has encompassed by left clicking
794  // the mouse and dragging it over the plot. That is we reframe the plot so
795  // that it contains only the "selected" region.
796  //
797  // Rescaling the plot means the the new x|y axis range is modified such that
798  // the lower axis range is constant and the upper axis range is moved either
799  // left or right by the same amont as the x|y delta encompassed by the user
800  // moving the mouse. The axis is thus either compressed (mouse movement is
801  // leftwards) or un-compressed (mouse movement is rightwards).
802 
803  // There are two ways to perform axis range modifications:
804  //
805  // 1. By clicking on any of the axes
806  // 2. By clicking on the plot region but using keyboard key modifiers, like
807  // Alt and Ctrl.
808  //
809  // We need to know both cases separately which is why we need to perform a
810  // number of tests below.
811 
812  // Let's check if the click is on the axes, either X or Y, because that
813  // will allow us to take proper actions.
814 
815  if(isClickOntoXAxis(mousePoint))
816  {
817  // The X axis was clicked upon, we need to document that:
818  // qDebug() << __FILE__ << __LINE__
819  //<< "Layout element is axisRect and actually on an X axis part.";
820 
821  m_context.wasClickOnXAxis = true;
822 
823  // int currentInteractions = interactions();
824  // currentInteractions |= QCP::iRangeDrag;
825  // setInteractions((QCP::Interaction)currentInteractions);
826  // axisRect()->setRangeDrag(xAxis->orientation());
827  }
828  else
829  m_context.wasClickOnXAxis = false;
830 
831  if(isClickOntoYAxis(mousePoint))
832  {
833  // The Y axis was clicked upon, we need to document that:
834  // qDebug() << __FILE__ << __LINE__
835  //<< "Layout element is axisRect and actually on an Y axis part.";
836 
837  m_context.wasClickOnYAxis = true;
838 
839  // int currentInteractions = interactions();
840  // currentInteractions |= QCP::iRangeDrag;
841  // setInteractions((QCP::Interaction)currentInteractions);
842  // axisRect()->setRangeDrag(yAxis->orientation());
843  }
844  else
845  m_context.wasClickOnYAxis = false;
846 
847  // At this point, let's see if we need to remove the QCP::iRangeDrag bit:
848 
850  {
851  // qDebug() << __FILE__ << __LINE__
852  // << "Click outside of axes.";
853 
854  // int currentInteractions = interactions();
855  // currentInteractions = currentInteractions & ~QCP::iRangeDrag;
856  // setInteractions((QCP::Interaction)currentInteractions);
857  }
858 
859  m_context.startDragPoint.setX(xAxis->pixelToCoord(mousePoint.x()));
860  m_context.startDragPoint.setY(yAxis->pixelToCoord(mousePoint.y()));
861 
862  // Now install the vertical start tracer at the last cursor hovered
863  // position.
865  mp_vStartTracerItem->setVisible(true);
866 
868  yAxis->range().upper);
870  yAxis->range().lower);
871 
872  replot();
873 }
874 
875 
876 void
878 {
879  m_context.lastReleasedMouseButton = event->button();
880 
881  // The event->buttons() is the description of the buttons that are pressed at
882  // the moment the handler is invoked, that is now. If left and right were
883  // pressed, and left was released, event->buttons() would be right.
884  m_context.mouseButtonsAtMouseRelease = event->buttons();
885 
886  // The pressedMouseButtons must continually inform on the status of pressed
887  // buttons so remove the released button.
888  m_context.pressedMouseButtons ^= event->button();
889 
890  // qDebug().noquote() << m_context.toString();
891 
892  // We'll need to know if modifiers were pressed a the moment the user
893  // released the mouse button.
894  m_context.keyboardModifiers = QGuiApplication::keyboardModifiers();
895 
897  {
898  // Let the user know that the mouse was *not* being dragged.
899  m_context.wasMouseDragging = false;
900 
901  event->accept();
902 
903  return;
904  }
905 
906  // Let the user know that the mouse was being dragged.
908 
909  // We cannot hide all items in one go because we rely on their visibility
910  // to know what kind of dragging operation we need to perform (line-only
911  // X-based zoom or rectangle-based X- and Y-based zoom, for example). The
912  // only thing we know is that we can make the text invisible.
913 
914  // We would not want to still see the selection line item.
915  mp_selectLineItem->setVisible(false);
916 
917  // Same for the x delta text item
918  mp_xDeltaTextItem->setVisible(false);
919 
920  // We do not show the end vertical region range marker.
921  mp_vEndTracerItem->setVisible(false);
922 
923  // Horizontal position tracer.
924  mp_hPosTracerItem->setVisible(true);
925  mp_hPosTracerItem->start->setCoords(xAxis->range().lower,
927  mp_hPosTracerItem->end->setCoords(xAxis->range().upper,
929 
930  // Vertical position tracer.
931  mp_vPosTracerItem->setVisible(true);
932 
933  mp_vPosTracerItem->setVisible(true);
934  mp_vPosTracerItem->start->setCoords(m_context.lastCursorHoveredPoint.x(),
935  yAxis->range().upper);
937  yAxis->range().lower);
938 
939  // Force replot now because later that call might not be performed.
940  replot();
941 
942  // If we were using the "quantum" display for the rescale of the axes
943  // using the Ctrl-modified left button click drag in the axes, then reset
944  // the count to 0.
946 
947  // Compute the delta values, X and Y, that correspond to the movement that
948  // was done by the user while pressing the mouse button, that is get the
949  // geometry of the drag movement.
950 
952 
953  // Now that we have computed the useful ranges, we need to check what to do
954  // depending on the button that was pressed.
955 
956  if(m_context.lastReleasedMouseButton == Qt::LeftButton)
957  {
959  }
960  else if(m_context.lastReleasedMouseButton == Qt::RightButton)
961  {
963  }
964 
965 
966  // By definition we are stopping the drag operation by releasing the mouse
967  // button. Whatever that mouse button was pressed before and if there was
968  // one pressed before. We cannot set that boolean value to false before
969  // this place, because we call a number of routines above that need to know
970  // that dragging was occurring. Like mouseReleaseHandledEvent(event) for
971  // example.
972 
973  m_context.isMouseDragging = false;
974 
975  event->accept();
976 
977  return;
978 }
979 
980 
981 void
983 {
984 
986  {
987 
988  // When the mouse move handler pans the plot, we cannot store each axes
989  // range history element that would mean store a huge amount of such
990  // elements, as many element as there are mouse move event handled by
991  // the Qt event queue. But we can store an axis range history element
992  // for the last situation of the mouse move: when the button is
993  // released:
994 
996 
998 
999  replot();
1000 
1001  // Nothing else to do.
1002  return;
1003  }
1004 
1005  // Start handling the zoom rectangle so that we can skip any keyboard
1006  // modified, like Ctrl that would not mean anything anyway.
1007  if(mp_zoomRectItem->visible())
1008  {
1009 
1010  // If we were dragging with the left button pressed and could draw a
1011  // rectangle, then we were preparing a zoom operation. Let's bring
1012  // that operation to an end.
1013 
1014  mp_zoomRectItem->setVisible(false);
1015 
1016  axisZoom();
1017 
1018  return;
1019  }
1020 
1021  // If the user started by clicking in the plot region, dragged the mouse
1022  // cursor with the left button and pressed the Ctrl modifier, then that
1023  // means that they wanted to do a rescale over the x-axis in the form of a
1024  // reframing.
1025 
1026  if(m_context.keyboardModifiers & Qt::ControlModifier)
1027  {
1028  return axisReframe();
1029  }
1030 }
1031 
1032 
1033 void
1035 {
1036 
1037  // The right button is used for the integrations. Not for axis range
1038  // operations. So all we have to do is remove the various graphics items and
1039  // send a signal with the context that contains all the data required by the
1040  // user to perform the integrations over the right plot regions.
1041 
1042  // Whatever we were doing we need to make the selection line invisible:
1043 
1044  if(mp_selectLineItem->visible())
1045  mp_selectLineItem->setVisible(false);
1046 
1047  if(mp_xDeltaTextItem->visible())
1048  mp_xDeltaTextItem->setVisible(false);
1049 
1050  // Also make the vertical end tracer invisible.
1051  mp_vEndTracerItem->setVisible(false);
1052 
1053  // Force replot now because later that call might not be performed.
1054  replot();
1055 
1056  // Note that we only request an integration if the x-axis delta is enough.
1057 
1058  double x_delta_pixel =
1059  fabs(xAxis->coordToPixel(m_context.currentDragPoint.x()) -
1060  xAxis->coordToPixel(m_context.startDragPoint.x()));
1061 
1062  if(x_delta_pixel > 3)
1064  //else
1065  //qDebug() << "Not asking for integration.";
1066 }
1067 
1068 
1069 void
1071 {
1072 
1073  // If we have no focus, then get it. See setFocus() to understand why asking
1074  // for focus is cosly and thus why we want to make this decision first.
1075  if(!hasFocus())
1076  setFocus();
1077 
1078  // The event->button() must be by Qt instructions considered to be 0.
1079 
1080  // Whatever happens, we want to store the plot coordinates of the current
1081  // mouse cursor position (will be useful later for countless needs).
1082 
1083  QPointF mousePoint = event->localPos();
1084 
1085  // qDebug() << "local mousePoint position in pixels:" << mousePoint;
1086 
1087  m_context.lastCursorHoveredPoint.setX(xAxis->pixelToCoord(mousePoint.x()));
1088  m_context.lastCursorHoveredPoint.setY(yAxis->pixelToCoord(mousePoint.y()));
1089 
1090  // qDebug() << "lastCursorHoveredPoint coord:"
1091  //<< m_context.lastCursorHoveredPoint;
1092 
1093  // Now, depending on the button(s) (if any) that are pressed or not, we have
1094  // a different processing.
1095 
1096  if(m_context.pressedMouseButtons & Qt::LeftButton ||
1097  m_context.pressedMouseButtons & Qt::RightButton)
1099  else
1101 
1102  event->accept();
1103 }
1104 
1105 
1106 void
1108 {
1109 
1110  m_context.isMouseDragging = false;
1111 
1112  // We are not dragging the mouse (no button pressed), simply let this
1113  // widget's consumer know the position of the cursor and update the markers.
1114 
1116 
1117  // We are not dragging, so we do not show the region end tracer we only show
1118  // the anchoring start trace that might be of use if the user starts using
1119  // the arrow keys to move the cursor.
1120  mp_vEndTracerItem->setVisible(false);
1121 
1122  // Only bother with the tracers if the user wants them to be visible. Their
1123  // crossing point must be exactly at the last cursor-hovered point.
1124 
1126  {
1127  // We are not dragging, so only show the position markers (v and h);
1128 
1129  // Horizontal position tracer.
1130  mp_hPosTracerItem->setVisible(true);
1131  mp_hPosTracerItem->start->setCoords(xAxis->range().lower,
1133  mp_hPosTracerItem->end->setCoords(xAxis->range().upper,
1135 
1136  // Vertical position tracer.
1137  mp_vPosTracerItem->setVisible(true);
1138 
1139  mp_vPosTracerItem->setVisible(true);
1140  mp_vPosTracerItem->start->setCoords(m_context.lastCursorHoveredPoint.x(),
1141  yAxis->range().upper);
1143  yAxis->range().lower);
1144 
1145  replot();
1146  }
1147 
1148  return;
1149 }
1150 
1151 
1152 void
1154 {
1155 
1156  m_context.isMouseDragging = true;
1157 
1158  // Now store the mouse position data into the the current drag point
1159  // member datum, that will be used in countless occasions later.
1161  m_context.keyboardModifiers = QGuiApplication::queryKeyboardModifiers();
1162 
1163  // When we drag (either keyboard or mouse), we hide the position markers
1164  // (black) and we show the start and end vertical markers for the region.
1165  // Then, we draw the horizontal region range marker that delimits
1166  // horizontally the dragged-over region.
1167 
1168  mp_hPosTracerItem->setVisible(false);
1169  mp_vPosTracerItem->setVisible(false);
1170 
1171  // Only bother with the tracers if the user wants them to be visible.
1173  {
1174 
1175  // The vertical end tracer position must be refreshed.
1176  mp_vEndTracerItem->start->setCoords(m_context.currentDragPoint.x(),
1177  yAxis->range().upper);
1178 
1179  mp_vEndTracerItem->end->setCoords(m_context.currentDragPoint.x(),
1180  yAxis->range().lower);
1181 
1182  mp_vEndTracerItem->setVisible(true);
1183  }
1184 
1185  // Whatever the button, when we are dealing with the axes, we do not
1186  // want to show any of the tracers.
1187 
1189  {
1190  mp_hPosTracerItem->setVisible(false);
1191  mp_vPosTracerItem->setVisible(false);
1192 
1193  mp_vStartTracerItem->setVisible(false);
1194  mp_vEndTracerItem->setVisible(false);
1195  }
1196 
1197  // We will need the axes ranges matching the region being selected by the
1198  // user while left-mouse-dragging the cursor.
1199 
1201 
1202  // Now deal with the BUTTON-SPECIFIC CODE.
1203 
1204  if(m_context.mouseButtonsAtMousePress & Qt::LeftButton)
1205  {
1207  }
1208  else if(m_context.mouseButtonsAtMousePress & Qt::RightButton)
1209  {
1211  }
1212 }
1213 
1214 
1215 void
1217 {
1218  // qDebug() << "the left button is dragging.";
1219 
1220  // Set the context.isMeasuringDistance to false, which later might be set to
1221  // true if effectively we are measuring a distance. This is required because
1222  // the derived widget classes might want to know if they have to perform
1223  // some action on the basis that context is measuring a distance, for
1224  // example the mass spectrum-specific widget might want to compute
1225  // deconvolutions.
1226 
1228 
1229  // Let's first check if the mouse drag operation originated on either
1230  // axis. In that case, the user is performing axis reframing or rescaling.
1231 
1233  {
1234  // qDebug() << __FILE__ << __LINE__ << "Click was on one of the axes.";
1235 
1236  if(m_context.keyboardModifiers & Qt::ControlModifier)
1237  {
1238  // The user is asking a rescale of the plot.
1239 
1240  // We know that we do not want the tracers when we perform axis
1241  // rescaling operations.
1242 
1243  mp_hPosTracerItem->setVisible(false);
1244  mp_vPosTracerItem->setVisible(false);
1245 
1246  mp_vStartTracerItem->setVisible(false);
1247  mp_vEndTracerItem->setVisible(false);
1248 
1249  // This operation is particularly intensive, thus we want to
1250  // reduce the number of calculations by skipping this calculation
1251  // a number of times. The user can ask for this feature by
1252  // clicking the 'Q' letter.
1253 
1254  if(m_context.pressedKeyCode == Qt::Key_Q)
1255  {
1257  {
1259  return;
1260  }
1261  else
1262  {
1264  }
1265  }
1266 
1267  // qDebug() << "Asking that the axes be rescaled.";
1268 
1269  axisRescale();
1270  }
1271  else
1272  {
1273  // The user was simply dragging the axis. Just pan, that is slide
1274  // the plot in the same direction as the mouse movement and with the
1275  // same amplitude.
1276 
1277  // qDebug() << "Asking that the axes be panned.";
1278 
1279  axisPan();
1280  }
1281 
1282  return;
1283  }
1284 
1285  // At this point we understand that the user was not performing any
1286  // panning/rescaling operation by clicking on any one of the axes.. Go on
1287  // with other possibilities.
1288 
1289  // Let's check if the user is actually drawing a rectangle (covering a
1290  // real area) or is drawing a line.
1291 
1292  // qDebug() << "The mouse dragging did not originate on an axis.";
1293 
1295  {
1296  // qDebug() << "Apparently the selection is a real rectangle.";
1297 
1298  // When we draw a rectangle the tracers are of no use.
1299 
1300  mp_hPosTracerItem->setVisible(false);
1301  mp_vPosTracerItem->setVisible(false);
1302 
1303  mp_vStartTracerItem->setVisible(false);
1304  mp_vEndTracerItem->setVisible(false);
1305 
1307  }
1308  else
1309  {
1310  // qDebug() << "Apparently we are measuring a delta.";
1311 
1312  // The pure position tracers should be hidden.
1313  mp_hPosTracerItem->setVisible(true);
1314  mp_vPosTracerItem->setVisible(true);
1315 
1316  // Then, make sure the region range vertical tracers are visible.
1317  mp_vStartTracerItem->setVisible(true);
1318  mp_vEndTracerItem->setVisible(true);
1319 
1321  }
1322 }
1323 
1324 
1325 void
1327 {
1328  // qDebug() << "the right button is dragging.";
1329 
1330  // Set the context.isMeasuringDistance to false, which later might be set to
1331  // true if effectively we are measuring a distance. This is required because
1332  // the derived widgets might want to know if they have to perform some
1333  // action on the basis that context is measuring a distance, for example the
1334  // mass spectrum-specific widget might want to compute deconvolutions.
1335 
1337 
1339 }
1340 
1341 
1342 void
1344  QCPAxis::SelectablePart part,
1345  QMouseEvent *event)
1346 {
1347 
1348  m_context.keyboardModifiers = QGuiApplication::queryKeyboardModifiers();
1349 
1350  if(m_context.keyboardModifiers & Qt::ControlModifier)
1351  {
1352 
1353  // If the Ctrl modifiers is active, then both axes are to be reset. Also
1354  // the histories are reset also.
1355 
1356  rescaleAxes();
1358  }
1359  else
1360  {
1361  // Only the axis passed as parameter is to be rescaled.
1362  // Reset the range of that axis to the max view possible.
1363 
1364  axis->rescale();
1365 
1367 
1368  event->accept();
1369  }
1370 
1371  // The double-click event does not cancel the mouse press event. That is, if
1372  // left-double-clicking, at the end of the operation the button still
1373  // "pressed". We need to remove manually the button from the pressed buttons
1374  // context member.
1375 
1376  m_context.pressedMouseButtons ^= event->button();
1377 
1379 
1381 
1382  replot();
1383 }
1384 
1385 
1386 bool
1387 BasePlotWidget::isClickOntoXAxis(const QPointF &mousePoint)
1388 {
1389  QCPLayoutElement *layoutElement = layoutElementAt(mousePoint);
1390 
1391  if(layoutElement &&
1392  layoutElement == dynamic_cast<QCPLayoutElement *>(axisRect()))
1393  {
1394  // The graph is *inside* the axisRect that is the outermost envelope of
1395  // the graph. Thus, if we want to know if the click was indeed on an
1396  // axis, we need to check what selectable part of the the axisRect we
1397  // were
1398  // clicking:
1399  QCPAxis::SelectablePart selectablePart;
1400 
1401  selectablePart = xAxis->getPartAt(mousePoint);
1402 
1403  if(selectablePart == QCPAxis::spAxisLabel ||
1404  selectablePart == QCPAxis::spAxis ||
1405  selectablePart == QCPAxis::spTickLabels)
1406  return true;
1407  }
1408 
1409  return false;
1410 }
1411 
1412 
1413 bool
1414 BasePlotWidget::isClickOntoYAxis(const QPointF &mousePoint)
1415 {
1416  QCPLayoutElement *layoutElement = layoutElementAt(mousePoint);
1417 
1418  if(layoutElement &&
1419  layoutElement == dynamic_cast<QCPLayoutElement *>(axisRect()))
1420  {
1421  // The graph is *inside* the axisRect that is the outermost envelope of
1422  // the graph. Thus, if we want to know if the click was indeed on an
1423  // axis, we need to check what selectable part of the the axisRect we
1424  // were
1425  // clicking:
1426  QCPAxis::SelectablePart selectablePart;
1427 
1428  selectablePart = yAxis->getPartAt(mousePoint);
1429 
1430  if(selectablePart == QCPAxis::spAxisLabel ||
1431  selectablePart == QCPAxis::spAxis ||
1432  selectablePart == QCPAxis::spTickLabels)
1433  return true;
1434  }
1435 
1436  return false;
1437 }
1438 
1439 /// MOUSE-related EVENTS
1440 
1441 
1442 /// MOUSE MOVEMENTS mouse/keyboard-triggered
1443 
1444 int
1446 {
1447  // The user is dragging the mouse, probably to rescale the axes, but we need
1448  // to sort out in which direction the drag is happening.
1449 
1450  // This function should be called after calculateDragDeltas, so that
1451  // m_context has the proper x/y delta values that we'll compare.
1452 
1453  // Note that we cannot compare simply x or y deltas because the y axis might
1454  // have a different scale that the x axis. So we first need to convert the
1455  // positions to pixels.
1456 
1457  double x_delta_pixel =
1458  fabs(xAxis->coordToPixel(m_context.currentDragPoint.x()) -
1459  xAxis->coordToPixel(m_context.startDragPoint.x()));
1460 
1461  double y_delta_pixel =
1462  fabs(yAxis->coordToPixel(m_context.currentDragPoint.y()) -
1463  yAxis->coordToPixel(m_context.startDragPoint.y()));
1464 
1465  if(x_delta_pixel > y_delta_pixel)
1466  return Qt::Horizontal;
1467 
1468  return Qt::Vertical;
1469 }
1470 
1471 
1472 void
1474 {
1475  // First convert the graph coordinates to pixel coordinates.
1476 
1477  QPointF pixels_coordinates(xAxis->coordToPixel(graph_coordinates.x()),
1478  yAxis->coordToPixel(graph_coordinates.y()));
1479 
1480  moveMouseCursorPixelCoordToGlobal(pixels_coordinates.toPoint());
1481 }
1482 
1483 
1484 void
1486 {
1487  // qDebug() << "Calling set pos with new cursor position.";
1488  QCursor::setPos(mapToGlobal(pixel_coordinates.toPoint()));
1489 }
1490 
1491 
1492 void
1494 {
1495  QPointF graph_coord = horizontalGetGraphCoordNewPointCountPixels(pixel_count);
1496 
1497  QPointF pixel_coord(xAxis->coordToPixel(graph_coord.x()),
1498  yAxis->coordToPixel(graph_coord.y()));
1499 
1500  // Now we need ton convert the new coordinates to the global position system
1501  // and to move the cursor to that new position. That will create an event to
1502  // move the mouse cursor.
1503 
1504  moveMouseCursorPixelCoordToGlobal(pixel_coord.toPoint());
1505 }
1506 
1507 
1508 QPointF
1510 {
1511  QPointF pixel_coordinates(
1512  xAxis->coordToPixel(m_context.lastCursorHoveredPoint.x()) + pixel_count,
1513  yAxis->coordToPixel(m_context.lastCursorHoveredPoint.y()));
1514 
1515  // Now convert back to local coordinates.
1516 
1517  QPointF graph_coordinates(xAxis->pixelToCoord(pixel_coordinates.x()),
1518  yAxis->pixelToCoord(pixel_coordinates.y()));
1519 
1520  return graph_coordinates;
1521 }
1522 
1523 
1524 void
1526 {
1527 
1528  QPointF graph_coord = verticalGetGraphCoordNewPointCountPixels(pixel_count);
1529 
1530  QPointF pixel_coord(xAxis->coordToPixel(graph_coord.x()),
1531  yAxis->coordToPixel(graph_coord.y()));
1532 
1533  // Now we need ton convert the new coordinates to the global position system
1534  // and to move the cursor to that new position. That will create an event to
1535  // move the mouse cursor.
1536 
1537  moveMouseCursorPixelCoordToGlobal(pixel_coord.toPoint());
1538 }
1539 
1540 
1541 QPointF
1543 {
1544  QPointF pixel_coordinates(
1545  xAxis->coordToPixel(m_context.lastCursorHoveredPoint.x()),
1546  yAxis->coordToPixel(m_context.lastCursorHoveredPoint.y()) + pixel_count);
1547 
1548  // Now convert back to local coordinates.
1549 
1550  QPointF graph_coordinates(xAxis->pixelToCoord(pixel_coordinates.x()),
1551  yAxis->pixelToCoord(pixel_coordinates.y()));
1552 
1553  return graph_coordinates;
1554 }
1555 
1556 /// MOUSE MOVEMENTS mouse/keyboard-triggered
1557 
1558 
1559 /// RANGE-related functions
1560 
1561 QCPRange
1562 BasePlotWidget::getRangeX(bool &found_range, int index) const
1563 {
1564  QCPGraph *graph_p = graph(index);
1565 
1566  if(graph_p == nullptr)
1567  qFatal("Programming error.");
1568 
1569  return graph_p->getKeyRange(found_range);
1570 }
1571 
1572 
1573 QCPRange
1574 BasePlotWidget::getRangeY(bool &found_range, int index) const
1575 {
1576  QCPGraph *graph_p = graph(index);
1577 
1578  if(graph_p == nullptr)
1579  qFatal("Programming error.");
1580 
1581  return graph_p->getValueRange(found_range);
1582 }
1583 
1584 
1585 QCPRange
1587  RangeType range_type,
1588  bool &found_range) const
1589 {
1590 
1591  // Iterate in all the graphs in this widget and return a QCPRange that has
1592  // its lower member as the greatest lower value of all
1593  // its upper member as the smallest upper value of all
1594 
1595  if(!graphCount())
1596  {
1597  found_range = false;
1598 
1599  return QCPRange(0, 1);
1600  }
1601 
1602  if(graphCount() == 1)
1603  return graph()->getKeyRange(found_range);
1604 
1605  bool found_at_least_one_range = false;
1606 
1607  // Create an invalid range.
1608  QCPRange result_range(QCPRange::minRange + 1, QCPRange::maxRange + 1);
1609 
1610  for(int iter = 0; iter < graphCount(); ++iter)
1611  {
1612  QCPRange temp_range;
1613 
1614  bool found_range_for_iter = false;
1615 
1616  QCPGraph *graph_p = graph(iter);
1617 
1618  // Depending on the axis param, select the key or value range.
1619 
1620  if(axis == PlotAxis::x_axis)
1621  temp_range = graph_p->getKeyRange(found_range_for_iter);
1622  else if(axis == PlotAxis::y_axis)
1623  temp_range = graph_p->getValueRange(found_range_for_iter);
1624  else
1625  qFatal("Cannot reach this point. Programming error.");
1626 
1627  // Was a range found for the iterated graph ? If not skip this
1628  // iteration.
1629 
1630  if(!found_range_for_iter)
1631  continue;
1632 
1633  // While the innermost_range is invalid, we need to seed it with a good
1634  // one. So check this.
1635 
1636  if(!QCPRange::validRange(result_range))
1637  qFatal("The obtained range is invalid !");
1638 
1639  // At this point we know the obtained range is OK.
1640  result_range = temp_range;
1641 
1642  // We found at least one valid range!
1643  found_at_least_one_range = true;
1644 
1645  // At this point we have two valid ranges to compare. Depending on
1646  // range_type, we need to perform distinct comparisons.
1647 
1648  if(range_type == RangeType::innermost)
1649  {
1650  if(temp_range.lower > result_range.lower)
1651  result_range.lower = temp_range.lower;
1652  if(temp_range.upper < result_range.upper)
1653  result_range.upper = temp_range.upper;
1654  }
1655  else if(range_type == RangeType::outermost)
1656  {
1657  if(temp_range.lower < result_range.lower)
1658  result_range.lower = temp_range.lower;
1659  if(temp_range.upper > result_range.upper)
1660  result_range.upper = temp_range.upper;
1661  }
1662  else
1663  qFatal("Cannot reach this point. Programming error.");
1664 
1665  // Continue to next graph, if any.
1666  }
1667  // End of
1668  // for(int iter = 0; iter < graphCount(); ++iter)
1669 
1670  // Let the caller know if we found at least one range.
1671  found_range = found_at_least_one_range;
1672 
1673  return result_range;
1674 }
1675 
1676 
1677 QCPRange
1678 BasePlotWidget::getInnermostRangeX(bool &found_range) const
1679 {
1680 
1681  return getRange(PlotAxis::x_axis, RangeType::innermost, found_range);
1682 }
1683 
1684 
1685 QCPRange
1686 BasePlotWidget::getOutermostRangeX(bool &found_range) const
1687 {
1688  return getRange(PlotAxis::x_axis, RangeType::outermost, found_range);
1689 }
1690 
1691 
1692 QCPRange
1693 BasePlotWidget::getInnermostRangeY(bool &found_range) const
1694 {
1695 
1696  return getRange(PlotAxis::y_axis, RangeType::innermost, found_range);
1697 }
1698 
1699 
1700 QCPRange
1701 BasePlotWidget::getOutermostRangeY(bool &found_range) const
1702 {
1703  return getRange(PlotAxis::y_axis, RangeType::outermost, found_range);
1704 }
1705 
1706 
1707 /// RANGE-related functions
1708 
1709 
1710 /// PLOTTING / REPLOTTING functions
1711 
1712 void
1714 {
1715  double xLower = xAxis->range().lower;
1716  double xUpper = xAxis->range().upper;
1717 
1718  // Get the current y lower/upper range.
1719  double yLower = yAxis->range().lower;
1720  double yUpper = yAxis->range().upper;
1721 
1722  // This function is called only when the user has clicked on the x/y axis or
1723  // when the user has dragged the left mouse button with the Ctrl key
1724  // modifier. The m_context.wasClickOnXAxis is then simulated in the mouse
1725  // move handler. So we need to test which axis was clicked-on.
1726 
1728  {
1729 
1730  // We are changing the range of the X axis.
1731 
1732  // What is the x delta ?
1733  double xDelta =
1735 
1736  // If xDelta is < 0, the we were dragging from right to left, we are
1737  // compressing the view on the x axis, by adding new data to the right
1738  // hand size of the graph. So we add xDelta to the upper bound of the
1739  // range. Otherwise we are uncompressing the view on the x axis and
1740  // remove the xDelta from the upper bound of the range. This is why we
1741  // have the
1742  // '-'
1743  // and not '+' below;
1744 
1745  // qDebug() << "Setting xaxis:" << xLower << "--" << xUpper - xDelta;
1746 
1747  xAxis->setRange(xLower, xUpper - xDelta);
1748  }
1749  // End of
1750  // if(m_context.wasClickOnXAxis)
1751  else // that is, if(m_context.wasClickOnYAxis)
1752  {
1753  // We are changing the range of the Y axis.
1754 
1755  // What is the y delta ?
1756  double yDelta =
1758 
1759  // See above for an explanation of the computation.
1760 
1761  yAxis->setRange(yLower, yUpper - yDelta);
1762 
1763  // Old version
1764  // if(yDelta < 0)
1765  //{
1766  //// The dragging operation was from top to bottom, we are enlarging
1767  //// the range (thus, we are unzooming the view, since the widget
1768  //// always has the same size).
1769 
1770  // yAxis->setRange(yLower, yUpper + fabs(yDelta));
1771  //}
1772  // else
1773  //{
1774  //// The dragging operation was from bottom to top, we are reducing
1775  //// the range (thus, we are zooming the view, since the widget
1776  //// always has the same size).
1777 
1778  // yAxis->setRange(yLower, yUpper - fabs(yDelta));
1779  //}
1780  }
1781  // End of
1782  // else // that is, if(m_context.wasClickOnYAxis)
1783 
1784  // Update the context with the current axes ranges
1785 
1787 
1789 
1790  replot();
1791 }
1792 
1793 
1794 void
1796 {
1797 
1798  // double sorted_start_drag_point_x =
1799  // std::min(m_context.startDragPoint.x(), m_context.currentDragPoint.x());
1800 
1801  // xAxis->setRange(sorted_start_drag_point_x,
1802  // sorted_start_drag_point_x + fabs(m_context.xDelta));
1803 
1804  xAxis->setRange(
1806 
1807  // Note that the y axis should be rescaled from current lower value to new
1808  // upper value matching the y-axis position of the cursor when the mouse
1809  // button was released.
1810 
1811  yAxis->setRange(
1812  xAxis->range().lower,
1814 
1815  // qDebug() << "xaxis:" << xAxis->range().lower << "-" <<
1816  // xAxis->range().upper
1817  //<< "yaxis:" << yAxis->range().lower << "-" << yAxis->range().upper;
1818 
1820 
1823 
1824  replot();
1825 }
1826 
1827 
1828 void
1830 {
1831 
1832  // Use the m_context.xRegionRangeStart/End values, but we need to sort the
1833  // values before using them, because now we want to really have the lower x
1834  // value. Simply craft a QCPRange that will swap the values if lower is not
1835  // < than upper QCustomPlot calls this normalization).
1836 
1837  xAxis->setRange(
1839 
1840  yAxis->setRange(
1842 
1844 
1847 
1848  replot();
1849 }
1850 
1851 void
1853 {
1855  {
1856  xAxis->setRange(m_context.xRange.lower - m_context.xDelta,
1857  m_context.xRange.upper - m_context.xDelta);
1858  }
1859 
1861  {
1862  yAxis->setRange(m_context.yRange.lower - m_context.yDelta,
1863  m_context.yRange.upper - m_context.yDelta);
1864  }
1865 
1867 
1868  // We cannot store the new ranges in the history, because the pan operation
1869  // involved a huge quantity of micro-movements elicited upon each mouse move
1870  // cursor event so we would have a huge history.
1871  // updateAxesRangeHistory();
1872 
1873  // Now that the contex has the right range values, we can emit the
1874  // signal that will be used by this plot widget users, typically to
1875  // abide by the x/y range lock required by the user.
1876 
1878 
1879  replot();
1880 }
1881 
1882 
1883 void
1885  QCPRange yAxisRange,
1886  PlotAxis axis)
1887 {
1888  if(static_cast<int>(axis) & static_cast<int>(PlotAxis::x_axis))
1889  {
1890  xAxis->setRange(xAxisRange.lower, xAxisRange.upper);
1891  }
1892 
1893  if(static_cast<int>(axis) & static_cast<int>(PlotAxis::y_axis))
1894  {
1895  yAxis->setRange(yAxisRange.lower, yAxisRange.upper);
1896  }
1897 
1898  // We do not want to update the history, because there would be way too
1899  // much history items, since this function is called upon mouse moving
1900  // handling and not only during mouse release events.
1901  // updateAxesRangeHistory();
1902 
1903  replot();
1904 }
1905 
1906 
1907 void
1908 BasePlotWidget::replotWithAxisRangeX(double lower, double upper)
1909 {
1910  // qDebug();
1911 
1912  xAxis->setRange(lower, upper);
1913 
1914  replot();
1915 }
1916 
1917 
1918 void
1919 BasePlotWidget::replotWithAxisRangeY(double lower, double upper)
1920 {
1921  // qDebug();
1922 
1923  yAxis->setRange(lower, upper);
1924 
1925  replot();
1926 }
1927 
1928 /// PLOTTING / REPLOTTING functions
1929 
1930 
1931 /// PLOT ITEMS : TRACER TEXT ITEMS...
1932 
1933 //! Hide the selection line, the xDelta text and the zoom rectangle items.
1934 void
1936 {
1937  mp_selectLineItem->setVisible(false);
1938 
1939  mp_xDeltaTextItem->setVisible(false);
1940 
1941  mp_zoomRectItem->setVisible(false);
1942 
1943  // Force a replot to make sure the action is immediately visible by the
1944  // user, even without moving the mouse.
1945  replot();
1946 }
1947 
1948 
1949 //! Show the traces (vertical and horizontal).
1950 void
1952 {
1953  m_shouldTracersBeVisible = true;
1954 
1955  mp_vPosTracerItem->setVisible(true);
1956  mp_hPosTracerItem->setVisible(true);
1957 
1958  mp_vStartTracerItem->setVisible(true);
1959  mp_vEndTracerItem->setVisible(true);
1960 
1961  // Force a replot to make sure the action is immediately visible by the
1962  // user, even without moving the mouse.
1963  replot();
1964 }
1965 
1966 
1967 //! Hide the traces (vertical and horizontal).
1968 void
1970 {
1971  m_shouldTracersBeVisible = false;
1972  mp_hPosTracerItem->setVisible(false);
1973  mp_vPosTracerItem->setVisible(false);
1974 
1975  mp_vStartTracerItem->setVisible(false);
1976  mp_vEndTracerItem->setVisible(false);
1977 
1978  // Force a replot to make sure the action is immediately visible by the
1979  // user, even without moving the mouse.
1980  replot();
1981 }
1982 
1983 
1984 void
1986 {
1987  // The user has drawn the mouse left button on the graph, which means he is
1988  // willing to draw a zoom rectangle.
1989 
1990  mp_selectLineItem->setVisible(false);
1991 
1992  mp_xDeltaTextItem->setVisible(false);
1993 
1994  mp_zoomRectItem->topLeft->setCoords(m_context.startDragPoint.x(),
1996  mp_zoomRectItem->bottomRight->setCoords(m_context.currentDragPoint.x(),
1998 
1999  mp_zoomRectItem->setVisible(true);
2000 
2001  // Now set the geometry of the rectangle to the context so that upon the
2002  // mouse button release, if the zoom rectanble is visible we know how to
2003  // reframe the plot axes. Note that we do not sort the values, if that is
2004  // required the user needs to use the sortAscendingRange() function.
2005 
2008 
2011 
2012  // Note that if we draw a zoom rectangle, then we are certainly not
2013  // measuring anything. So set the boolean value to false so that the user of
2014  // this widget or derived classes know that there is nothing to perform upon
2015  // (like deconvolution, for example).
2016 
2018 
2019  // Also remove the delta value from the pipeline by sending a simple
2020  // distance without measurement signal.
2021 
2022  emit xAxisMeasurementSignal(m_context, false);
2023 
2024  replot();
2025 }
2026 
2027 
2028 void
2030 {
2031  // The user has dragged the mouse left button on the graph in such a way
2032  // that the xDelta is big and the yDelta is almost nothing, that
2033  // means that he does not want to draw a rectangle but a line to
2034  // measure the delta between two points of the graph.
2035 
2036  mp_zoomRectItem->setVisible(false);
2037 
2038  // We also want to show the span as a text item.
2039 
2040  // m_context.xDelta is not an absolute value.
2041  double m_xDeltaHalf = fabs(m_context.xDelta / 2);
2042 
2043  // Use the m_context.xRegionRangeStart/End values, but we need to sort the
2044  // values before using them, because now we want to really have the lower x
2045  // value. Simply craft a QCPRange that will swap the values if lower is not
2046  // < than upper QCustomPlot calls this normalization).
2047 
2048  QCPRange sorted_range(m_context.xRegionRangeStart, m_context.xRegionRangeEnd);
2049 
2050  // qDebug() << "sorted range:" << sorted_range.lower << "-" <<
2051  // sorted_range.upper
2052  //<< "xrangedeltahalf:" << m_xDeltaHalf;
2053 
2054  mp_xDeltaTextItem->position->setCoords(sorted_range.lower + m_xDeltaHalf,
2056 
2057  mp_xDeltaTextItem->setText(QString("%1").arg(m_context.xDelta, 0, 'f', 3));
2058 
2059  mp_xDeltaTextItem->setFont(QFont(font().family(), 7));
2060 
2061  mp_xDeltaTextItem->setVisible(true);
2062 
2063  // We do not want to show the position markers because the only horiontal
2064  // line to be visible must be contained between the start and end vertiacal
2065  // tracer items.
2066  mp_hPosTracerItem->setVisible(false);
2067  mp_vPosTracerItem->setVisible(false);
2068 
2069  mp_selectLineItem->setVisible(true);
2070 
2071  mp_selectLineItem->start->setCoords(m_context.startDragPoint.x(),
2073  // But we want the line to be horizontal, thus we keep the original y
2074  // value.
2075  mp_selectLineItem->end->setCoords(m_context.currentDragPoint.x(),
2077 
2078  // Set the boolean to true so that derived widgets know that something is
2079  // being measured, and they can act accordingly, for example by computing
2080  // deconvolutions in a mass spectrum.
2082 
2083  return;
2084 }
2085 
2086 
2087 void
2089 {
2091 
2092  // Also, we do not want arrows, because we are not integrating anything
2093  // here.
2094  mp_selectLineItem->setHead(QCPLineEnding::esNone);
2095  mp_selectLineItem->setTail(QCPLineEnding::esNone);
2096 
2097  replot();
2098 
2099  // Let the caller know that we were measuring something.
2100  emit xAxisMeasurementSignal(m_context, true);
2101 }
2102 
2103 
2104 void
2106 {
2108 
2109  // Since we draw the selection line with the xDelta text for integration, we
2110  // let the user guess it by the arrows at the ends of the line.
2111  mp_selectLineItem->setHead(QCPLineEnding::esSpikeArrow);
2112  mp_selectLineItem->setTail(QCPLineEnding::esSpikeArrow);
2113 
2114  replot();
2115 
2116  // Let the caller know that we were measuring something.
2117  emit xAxisMeasurementSignal(m_context, true);
2118 }
2119 
2120 
2121 void
2123 {
2124 
2125  // We compute signed differentials. If the user does not want the sign,
2126  // fabs(double) is their friend.
2127 
2128  // Compute the xAxis differential:
2129 
2130  m_context.xDelta =
2132 
2133  // Same with the Y-axis range:
2134 
2135  m_context.yDelta =
2137 
2138  // qDebug() << "xDelta:" << m_context.xDelta
2139  //<< "and yDelta:" << m_context.yDelta;
2140 
2141  return;
2142 }
2143 
2144 
2145 void
2147 {
2148 
2150 
2151  // Note that we do not sort the x value nor the y values. If the user of the
2152  // ranges need them to be sorted, they can use the sortAscendingRange().
2153 
2156 
2159 
2160  return;
2161 }
2162 
2163 
2164 bool
2166 {
2167  // First get the height of the plot.
2168  double plotHeight = yAxis->range().upper - yAxis->range().lower;
2169 
2170  double heightDiff =
2172 
2173  double heightDiffRatio = (heightDiff / plotHeight) * 100;
2174 
2175  if(heightDiffRatio > 10)
2176  return true;
2177 
2178  return false;
2179 }
2180 
2181 
2182 void
2184 {
2185  // qDebug() << "Setting focus to the QCustomPlot:" << this;
2186 
2187  QCustomPlot::setFocus();
2188 
2189  // qDebug() << "Emitting setFocusSignal().";
2190 
2191  emit setFocusSignal();
2192 }
2193 
2194 
2195 //! Redraw the background of the \p focusedPlotWidget plot widget.
2196 void
2197 BasePlotWidget::redrawPlotBackground(QWidget *focusedPlotWidget)
2198 {
2199  if(focusedPlotWidget == nullptr)
2200  qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
2201 
2202  if(dynamic_cast<QWidget *>(this) != focusedPlotWidget)
2203  {
2204  // The focused widget is not *this widget. We should make sure that
2205  // we were not the one that had the focus, because in this case we
2206  // need to redraw an unfocused background.
2207 
2208  axisRect()->setBackground(m_unfocusedBrush);
2209  }
2210  else
2211  {
2212  axisRect()->setBackground(m_focusedBrush);
2213  }
2214 
2215  replot();
2216 }
2217 
2218 
2219 void
2221 {
2222  m_context.xRange = QCPRange(xAxis->range().lower, xAxis->range().upper);
2223  m_context.yRange = QCPRange(yAxis->range().lower, yAxis->range().upper);
2224 }
2225 
2226 
2227 const BasePlotContext &
2229 {
2230  return m_context;
2231 }
2232 
2233 
2234 } // namespace pappso
pappso::BasePlotWidget::m_xAxisRangeHistory
std::vector< QCPRange * > m_xAxisRangeHistory
List of x axis ranges occurring during the panning zooming actions.
Definition: baseplotwidget.h:353
pappso::BasePlotWidget::replotWithAxesRanges
virtual void replotWithAxesRanges(QCPRange xAxisRange, QCPRange yAxisRange, PlotAxis whichAxis)
Definition: baseplotwidget.cpp:1884
pappso::BasePlotWidget::isClickOntoYAxis
bool isClickOntoYAxis(const QPointF &mousePoint)
Definition: baseplotwidget.cpp:1414
pappso::BasePlotWidget::getInnermostRangeX
virtual QCPRange getInnermostRangeX(bool &found_range) const
Definition: baseplotwidget.cpp:1678
pappso::PlotAxis
PlotAxis
Definition: baseplotwidget.h:53
pappso::BasePlotContext::xRegionRangeStart
double xRegionRangeStart
Definition: baseplotwidget.h:104
pappso::BasePlotWidget::mousePseudoButtonKeyReleaseEvent
virtual void mousePseudoButtonKeyReleaseEvent(QKeyEvent *event)
Definition: baseplotwidget.cpp:705
pappso::BasePlotWidget::mouseMoveHandler
virtual void mouseMoveHandler(QMouseEvent *event)
Definition: baseplotwidget.cpp:1070
pappso::BasePlotWidget::setAxisLabelX
virtual void setAxisLabelX(const QString &label)
Definition: baseplotwidget.cpp:350
pappso::BasePlotWidget::updateAxesRangeHistory
virtual void updateAxesRangeHistory()
Create new axis range history items and append them to the history.
Definition: baseplotwidget.cpp:392
pappso::BasePlotWidget::calculateDragDeltas
virtual void calculateDragDeltas()
Definition: baseplotwidget.cpp:2122
pappso::BasePlotContext::lastReleasedMouseButton
Qt::MouseButtons lastReleasedMouseButton
Definition: baseplotwidget.h:119
pappso::BasePlotWidget::lastCursorHoveredPointSignal
void lastCursorHoveredPointSignal(const QPointF &pointf)
pappso::BasePlotWidget::mp_hPosTracerItem
QCPItemLine * mp_hPosTracerItem
Horizontal position tracer.
Definition: baseplotwidget.h:330
pappso::BasePlotWidget::axisDoubleClickHandler
virtual void axisDoubleClickHandler(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event)
Definition: baseplotwidget.cpp:1343
pappso::BasePlotWidget::calculateDragDeltasAndUnSortedRegionCorners
virtual void calculateDragDeltasAndUnSortedRegionCorners()
Definition: baseplotwidget.cpp:2146
pappso::BasePlotWidget::m_mouseMoveHandlerSkipCount
int m_mouseMoveHandlerSkipCount
Counter to handle the "fat data" mouse move event handling.
Definition: baseplotwidget.h:376
pappso::BasePlotWidget::getRangeX
virtual QCPRange getRangeX(bool &found_range, int index) const
MOUSE MOVEMENTS mouse/keyboard-triggered.
Definition: baseplotwidget.cpp:1562
pappso::BasePlotContext::isLeftPseudoButtonKeyPressed
bool isLeftPseudoButtonKeyPressed
Definition: baseplotwidget.h:77
pappso::BasePlotContext::pressedMouseButtons
Qt::MouseButtons pressedMouseButtons
Definition: baseplotwidget.h:121
pappso::BasePlotContext::dataKind
DataKind dataKind
Definition: baseplotwidget.h:71
pappso::BasePlotWidget::m_pen
QPen m_pen
Pen used to draw the graph and textual elements in the plot widget.
Definition: baseplotwidget.h:392
pappso::BasePlotWidget::spaceKeyReleaseEvent
virtual void spaceKeyReleaseEvent(QKeyEvent *event)
Definition: baseplotwidget.cpp:640
basePlotContextMetaTypeId
int basePlotContextMetaTypeId
Definition: baseplotwidget.cpp:39
pappso::BasePlotWidget::hideAllPlotItems
virtual void hideAllPlotItems()
PLOTTING / REPLOTTING functions.
Definition: baseplotwidget.cpp:1935
pappso::BasePlotWidget::mp_vStartTracerItem
QCPItemLine * mp_vStartTracerItem
Vertical selection start tracer (typically in green).
Definition: baseplotwidget.h:336
pappso::BasePlotWidget::mousePressHandler
virtual void mousePressHandler(QMouseEvent *event)
KEYBOARD-related EVENTS.
Definition: baseplotwidget.cpp:772
pappso::BasePlotContext::currentDragPoint
QPointF currentDragPoint
Definition: baseplotwidget.h:82
pappso::BasePlotWidget::horizontalMoveMouseCursorCountPixels
virtual void horizontalMoveMouseCursorCountPixels(int pixel_count)
Definition: baseplotwidget.cpp:1493
pappso::BasePlotWidget::xAxisMeasurementSignal
void xAxisMeasurementSignal(const BasePlotContext &context, bool with_delta)
pappso::BasePlotContext::lastPressedMouseButton
Qt::MouseButtons lastPressedMouseButton
Definition: baseplotwidget.h:118
pappso::BasePlotWidget::BasePlotWidget
BasePlotWidget(QWidget *parent)
Definition: baseplotwidget.cpp:111
pappso::BasePlotContext::wasMouseDragging
bool wasMouseDragging
Definition: baseplotwidget.h:74
pappso::BasePlotWidget::setAxisLabelY
virtual void setAxisLabelY(const QString &label)
Definition: baseplotwidget.cpp:357
pappso
Definition: aa.cpp:38
pappso::BasePlotWidget::drawXDeltaLineAndMeasure
virtual void drawXDeltaLineAndMeasure()
Definition: baseplotwidget.cpp:2088
pappso::BasePlotContext::lastCursorHoveredPoint
QPointF lastCursorHoveredPoint
Definition: baseplotwidget.h:83
pappso::RangeType::innermost
pappso::BasePlotWidget::moveMouseCursorPixelCoordToGlobal
virtual void moveMouseCursorPixelCoordToGlobal(QPointF local_coordinates)
Definition: baseplotwidget.cpp:1485
pappso::BasePlotWidget::getRangeY
virtual QCPRange getRangeY(bool &found_range, int index) const
Definition: baseplotwidget.cpp:1574
pappso::BasePlotWidget::plottableDestructionRequestedSignal
void plottableDestructionRequestedSignal(BasePlotWidget *base_plot_widget_p, QCPAbstractPlottable *plottable_p, const BasePlotContext &context)
pappso::BasePlotContext::xRange
QCPRange xRange
Definition: baseplotwidget.h:86
pappso::BasePlotWidget::mousePseudoButtonKeyPressEvent
virtual void mousePseudoButtonKeyPressEvent(QKeyEvent *event)
Definition: baseplotwidget.cpp:698
pappso::BasePlotWidget::axisRescale
virtual void axisRescale()
RANGE-related functions.
Definition: baseplotwidget.cpp:1713
pappso::BasePlotContext::wasClickOnXAxis
bool wasClickOnXAxis
Definition: baseplotwidget.h:93
pappso::BasePlotWidget::drawRectangleAndPrepareZoom
virtual void drawRectangleAndPrepareZoom()
Definition: baseplotwidget.cpp:1985
pappso::BasePlotWidget::getOutermostRangeX
virtual QCPRange getOutermostRangeX(bool &found_range) const
Definition: baseplotwidget.cpp:1686
pappso::BasePlotWidget::horizontalGetGraphCoordNewPointCountPixels
virtual QPointF horizontalGetGraphCoordNewPointCountPixels(int pixel_count)
Definition: baseplotwidget.cpp:1509
pappso::BasePlotWidget::replotWithAxisRangeX
virtual void replotWithAxisRangeX(double lower, double upper)
Definition: baseplotwidget.cpp:1908
pappso::BasePlotWidget::mp_selectLineItem
QCPItemLine * mp_selectLineItem
Line that is printed when the user selects a range.
Definition: baseplotwidget.h:321
pappso::BasePlotWidget::getContext
virtual const BasePlotContext & getContext() const
Definition: baseplotwidget.cpp:2228
pappso::BasePlotWidget::getRange
QCPRange getRange(PlotAxis axis, RangeType range_type, bool &found_range) const
Definition: baseplotwidget.cpp:1586
pappso::BasePlotContext
Definition: baseplotwidget.h:69
pappso::BasePlotWidget::getInnermostRangeY
virtual QCPRange getInnermostRangeY(bool &found_range) const
Definition: baseplotwidget.cpp:1693
pappso::BasePlotWidget::getOutermostRangeY
virtual QCPRange getOutermostRangeY(bool &found_range) const
Definition: baseplotwidget.cpp:1701
pappso::BasePlotContext::isMeasuringDistance
bool isMeasuringDistance
Definition: baseplotwidget.h:96
pappso::BasePlotWidget::m_leftMousePseudoButtonKey
int m_leftMousePseudoButtonKey
Definition: baseplotwidget.h:314
pappso::BasePlotWidget::axisReframe
virtual void axisReframe()
Definition: baseplotwidget.cpp:1795
pappso::BasePlotContext::mouseButtonsAtMousePress
Qt::MouseButtons mouseButtonsAtMousePress
Definition: baseplotwidget.h:123
pappso::BasePlotWidget::mouseMoveHandlerDraggingCursor
virtual void mouseMoveHandlerDraggingCursor()
Definition: baseplotwidget.cpp:1153
pappso::BasePlotWidget::updateContextRanges
virtual void updateContextRanges()
Definition: baseplotwidget.cpp:2220
pappso::BasePlotWidget::replotWithAxisRangeY
virtual void replotWithAxisRangeY(double lower, double upper)
Definition: baseplotwidget.cpp:1919
pappso::BasePlotWidget::getPlottingColor
virtual QColor getPlottingColor(QCPAbstractPlottable *plottable_p) const
Definition: baseplotwidget.cpp:328
pappso::BasePlotContext::pressedKeyCode
int pressedKeyCode
Definition: baseplotwidget.h:113
pappso::BasePlotContext::keyboardModifiers
Qt::KeyboardModifiers keyboardModifiers
Definition: baseplotwidget.h:116
pappso::BasePlotWidget::mouseReleaseHandler
virtual void mouseReleaseHandler(QMouseEvent *event)
Definition: baseplotwidget.cpp:877
pappso::BasePlotWidget::isProperSelectionRectangle
virtual bool isProperSelectionRectangle()
Definition: baseplotwidget.cpp:2165
pappso::RangeType
RangeType
Definition: baseplotwidget.h:62
pappso::BasePlotWidget::keyPressEvent
virtual void keyPressEvent(QKeyEvent *event)
KEYBOARD-related EVENTS.
Definition: baseplotwidget.cpp:491
pappso::BasePlotWidget::setPen
virtual void setPen(const QPen &pen)
Definition: baseplotwidget.cpp:281
pappso::BasePlotWidget::mouseMoveHandlerRightButtonDraggingCursor
virtual void mouseMoveHandlerRightButtonDraggingCursor()
Definition: baseplotwidget.cpp:1326
pappso::BasePlotWidget::prepareXDeltaLineAndMeasure
virtual void prepareXDeltaLineAndMeasure()
Definition: baseplotwidget.cpp:2029
pappso::BasePlotContext::mouseButtonsAtMouseRelease
Qt::MouseButtons mouseButtonsAtMouseRelease
Definition: baseplotwidget.h:124
pappso::BasePlotWidget::m_focusedBrush
QBrush m_focusedBrush
Color used for the background of focused plot.
Definition: baseplotwidget.h:389
pappso::BasePlotContext::yRegionRangeStart
double yRegionRangeStart
Definition: baseplotwidget.h:107
pappso::BasePlotWidget::mp_vPosTracerItem
QCPItemLine * mp_vPosTracerItem
Vertical position tracer.
Definition: baseplotwidget.h:333
pappso::BasePlotWidget::~BasePlotWidget
virtual ~BasePlotWidget()
Destruct this BasePlotWidget instance.
Definition: baseplotwidget.cpp:162
pappso::BasePlotWidget::m_yAxisRangeHistory
std::vector< QCPRange * > m_yAxisRangeHistory
List of y axis ranges occurring during the panning zooming actions.
Definition: baseplotwidget.h:356
pappso::BasePlotWidget::hideTracers
virtual void hideTracers()
Hide the traces (vertical and horizontal).
Definition: baseplotwidget.cpp:1969
pappso::BasePlotWidget::mp_vEndTracerItem
QCPItemLine * mp_vEndTracerItem
Vertical selection end tracer (typically in red).
Definition: baseplotwidget.h:339
pappso::BasePlotWidget::mouseMoveHandlerNotDraggingCursor
virtual void mouseMoveHandlerNotDraggingCursor()
Definition: baseplotwidget.cpp:1107
pappso::BasePlotWidget::mouseMoveHandlerLeftButtonDraggingCursor
virtual void mouseMoveHandlerLeftButtonDraggingCursor()
Definition: baseplotwidget.cpp:1216
pappso::BasePlotWidget::directionKeyPressEvent
virtual void directionKeyPressEvent(QKeyEvent *event)
Definition: baseplotwidget.cpp:647
pappso::BasePlotWidget::dragDirection
int dragDirection()
MOUSE-related EVENTS.
Definition: baseplotwidget.cpp:1445
pappso::BasePlotWidget::setFocusSignal
void setFocusSignal()
pappso::BasePlotContext::yRange
QCPRange yRange
Definition: baseplotwidget.h:87
pappso::BasePlotWidget::verticalMoveMouseCursorCountPixels
virtual void verticalMoveMouseCursorCountPixels(int pixel_count)
Definition: baseplotwidget.cpp:1525
pappso::BasePlotWidget::resetAxesRangeHistory
virtual void resetAxesRangeHistory()
Definition: baseplotwidget.cpp:365
pappso::BasePlotWidget::mp_zoomRectItem
QCPItemRect * mp_zoomRectItem
Rectangle defining the borders of zoomed-in/out data.
Definition: baseplotwidget.h:318
pappso::BasePlotContext::toString
QString toString() const
Definition: baseplotwidget.cpp:47
pappso::BasePlotWidget::mp_xDeltaTextItem
QCPItemText * mp_xDeltaTextItem
Text describing the x-axis delta value during a drag operation.
Definition: baseplotwidget.h:324
pappso::BasePlotWidget::moveMouseCursorGraphCoordToGlobal
virtual void moveMouseCursorGraphCoordToGlobal(QPointF plot_coordinates)
Definition: baseplotwidget.cpp:1473
pappso::BasePlotWidget::isClickOntoXAxis
bool isClickOntoXAxis(const QPointF &mousePoint)
Definition: baseplotwidget.cpp:1387
pappso::RangeType::outermost
pappso::BasePlotWidget::restoreAxesRangeHistory
virtual void restoreAxesRangeHistory(std::size_t index)
Get the axis histories at index index and update the plot ranges.
Definition: baseplotwidget.cpp:443
pappso::BasePlotContext::isRightPseudoButtonKeyPressed
bool isRightPseudoButtonKeyPressed
Definition: baseplotwidget.h:78
pappso::BasePlotWidget::drawXDeltaLineForIntegration
virtual void drawXDeltaLineForIntegration()
Definition: baseplotwidget.cpp:2105
pappso::BasePlotWidget::setupWidget
virtual bool setupWidget()
Definition: baseplotwidget.cpp:172
pappso::BasePlotWidget::mouseReleaseHandlerLeftButton
virtual void mouseReleaseHandlerLeftButton()
Definition: baseplotwidget.cpp:982
baseplotwidget.h
pappso::BasePlotWidget::showTracers
virtual void showTracers()
Show the traces (vertical and horizontal).
Definition: baseplotwidget.cpp:1951
pappso::BasePlotContext::wasClickOnYAxis
bool wasClickOnYAxis
Definition: baseplotwidget.h:94
pappso::BasePlotWidget::getPen
virtual const QPen & getPen() const
Definition: baseplotwidget.cpp:288
basePlotContextPtrMetaTypeId
int basePlotContextPtrMetaTypeId
Definition: baseplotwidget.cpp:40
pappso::BasePlotContext::releasedKeyCode
int releasedKeyCode
Definition: baseplotwidget.h:114
pappso::BasePlotContext::xRegionRangeEnd
double xRegionRangeEnd
Definition: baseplotwidget.h:105
pappso::BasePlotWidget::m_rightMousePseudoButtonKey
int m_rightMousePseudoButtonKey
Definition: baseplotwidget.h:315
pappso::BasePlotWidget::verticalGetGraphCoordNewPointCountPixels
virtual QPointF verticalGetGraphCoordNewPointCountPixels(int pixel_count)
Definition: baseplotwidget.cpp:1542
pappso::BasePlotWidget::keyReleaseEvent
virtual void keyReleaseEvent(QKeyEvent *event)
Handle specific key codes and trigger respective actions.
Definition: baseplotwidget.cpp:520
pappso::BasePlotWidget::keyReleaseEventSignal
void keyReleaseEventSignal(const BasePlotContext &context)
pappso::BasePlotWidget::setFocus
virtual void setFocus()
PLOT ITEMS : TRACER TEXT ITEMS...
Definition: baseplotwidget.cpp:2183
pappso::BasePlotContext::yDelta
double yDelta
Definition: baseplotwidget.h:111
pappso::BasePlotContext::yRegionRangeEnd
double yRegionRangeEnd
Definition: baseplotwidget.h:108
pappso::BasePlotWidget::m_unfocusedBrush
QBrush m_unfocusedBrush
Color used for the background of unfocused plot.
Definition: baseplotwidget.h:384
pappso::BasePlotWidget::m_lastAxisRangeHistoryIndex
std::size_t m_lastAxisRangeHistoryIndex
Index of the last axis range history item.
Definition: baseplotwidget.h:350
pappso::PlotAxis::y_axis
pappso::BasePlotWidget::m_mouseMoveHandlerSkipAmount
int m_mouseMoveHandlerSkipAmount
How many mouse move events must be skipped *‍/.
Definition: baseplotwidget.h:368
pappso::BasePlotWidget::restorePreviousAxesRangeHistory
virtual void restorePreviousAxesRangeHistory()
Go up one history element in the axis history.
Definition: baseplotwidget.cpp:415
pappso::BasePlotContext::isMouseDragging
bool isMouseDragging
Definition: baseplotwidget.h:73
pappso::BasePlotWidget::redrawPlotBackground
virtual void redrawPlotBackground(QWidget *focusedPlotWidget)
Redraw the background of the focusedPlotWidget plot widget.
Definition: baseplotwidget.cpp:2197
pappso::BasePlotWidget::integrationRequestedSignal
void integrationRequestedSignal(const BasePlotContext &context)
pappso::BasePlotWidget::axisPan
virtual void axisPan()
Definition: baseplotwidget.cpp:1852
pappso::PlotAxis::x_axis
pappso::BasePlotWidget::directionKeyReleaseEvent
virtual void directionKeyReleaseEvent(QKeyEvent *event)
Definition: baseplotwidget.cpp:690
pappso::BasePlotContext::xDelta
double xDelta
Definition: baseplotwidget.h:110
pappso::BasePlotWidget::m_shouldTracersBeVisible
bool m_shouldTracersBeVisible
Tells if the tracers should be visible.
Definition: baseplotwidget.h:327
pappso::BasePlotWidget::setPlottingColor
virtual void setPlottingColor(QCPAbstractPlottable *plottable_p, const QColor &new_color)
Definition: baseplotwidget.cpp:295
pappso::BasePlotWidget::m_context
BasePlotContext m_context
Definition: baseplotwidget.h:312
pappso::BasePlotContext::startDragPoint
QPointF startDragPoint
Definition: baseplotwidget.h:81
pappso::BasePlotWidget::axisZoom
virtual void axisZoom()
Definition: baseplotwidget.cpp:1829
pappso::BasePlotWidget::mouseReleaseHandlerRightButton
virtual void mouseReleaseHandlerRightButton()
Definition: baseplotwidget.cpp:1034
pappso::BasePlotWidget::plotRangesChangedSignal
void plotRangesChangedSignal(const BasePlotContext &context)