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