/qt/widgets/mplcpp/src/RangeMarker.cpp

https://github.com/mantidproject/mantid · C++ · 183 lines · 72 code · 30 blank · 81 comment · 0 complexity · 04f92353ae2bcfff177e8d8d13ebc7ec MD5 · raw file

  1. // Mantid Repository : https://github.com/mantidproject/mantid
  2. //
  3. // Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI,
  4. // NScD Oak Ridge National Laboratory, European Spallation Source,
  5. // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
  6. // SPDX - License - Identifier: GPL - 3.0 +
  7. #include "MantidQtWidgets/MplCpp/RangeMarker.h"
  8. #include "MantidPythonInterface/core/CallMethod.h"
  9. #include "MantidQtWidgets/Common/Python/QHashToDict.h"
  10. #include "MantidQtWidgets/Common/Python/Sip.h"
  11. using Mantid::PythonInterface::callMethodNoCheck;
  12. using Mantid::PythonInterface::GlobalInterpreterLock;
  13. using Mantid::PythonInterface::PythonException;
  14. using namespace MantidQt::Widgets::Common;
  15. using namespace MantidQt::Widgets::MplCpp;
  16. namespace {
  17. Python::Object newMarker(FigureCanvasQt *canvas, QString const &colour, double minimum, double maximum,
  18. QString const &rangeType, boost::optional<QHash<QString, QVariant>> const &otherKwargs) {
  19. GlobalInterpreterLock lock;
  20. Python::Object markersModule{Python::NewRef(PyImport_ImportModule("mantidqt.plotting.markers"))};
  21. auto const args = Python::NewRef(Py_BuildValue("(Osdds)", canvas->pyobj().ptr(), colour.toLatin1().constData(),
  22. minimum, maximum, rangeType.toLatin1().constData()));
  23. Python::Dict kwargs = Python::qHashToDict(otherKwargs.get());
  24. auto const marker = markersModule.attr("RangeMarker")(*args, **kwargs);
  25. return marker;
  26. }
  27. } // namespace
  28. namespace MantidQt::Widgets::MplCpp {
  29. /**
  30. * @brief Create a RangeMarker instance
  31. * @param canvas The canvas to draw the range marker on to
  32. * @param colour The color of the range marker
  33. * @param minimum The coordinate of the minimum marker
  34. * @param maximum The coordinate of the maximum marker
  35. */
  36. RangeMarker::RangeMarker(FigureCanvasQt *canvas, QString const &color, double minimum, double maximum,
  37. QString const &rangeType, QHash<QString, QVariant> const &otherKwargs)
  38. : InstanceHolder(newMarker(canvas, color, minimum, maximum, rangeType, otherKwargs)) {}
  39. /**
  40. * @brief Redraw the RangeMarker
  41. */
  42. void RangeMarker::redraw() { callMethodNoCheck<void>(pyobj(), "redraw"); }
  43. /**
  44. * @brief Remove the RangeMarker from the plot
  45. */
  46. void RangeMarker::remove() {
  47. try {
  48. callMethodNoCheck<void>(pyobj(), "remove");
  49. } catch (PythonException const &) {
  50. // Marker has already been removed
  51. }
  52. }
  53. /**
  54. * @brief Sets the color of the RangeMarker.
  55. * @param color The color to set the RangeMarker to.
  56. */
  57. void RangeMarker::setColor(QString const &color) {
  58. callMethodNoCheck<void>(pyobj(), "set_color", color.toLatin1().constData());
  59. }
  60. /**
  61. * @brief Sets the bounds of the RangeMarker.
  62. * @param lowerBound The lower bound.
  63. * @param upperBound The upper bound.
  64. */
  65. void RangeMarker::setBounds(double lowerBound, double upperBound) {
  66. callMethodNoCheck<void>(pyobj(), "set_bounds", lowerBound, upperBound);
  67. }
  68. /**
  69. * @brief Sets the lower bound of the RangeMarker.
  70. * @param minimum The lower bound.
  71. */
  72. void RangeMarker::setLowerBound(double lowerBound) { callMethodNoCheck<void>(pyobj(), "set_lower_bound", lowerBound); }
  73. /**
  74. * @brief Sets the upper bound of the RangeMarker.
  75. * @param upperBound The upper bound.
  76. */
  77. void RangeMarker::setUpperBound(double upperBound) { callMethodNoCheck<void>(pyobj(), "set_upper_bound", upperBound); }
  78. /**
  79. * @brief Sets the range marked by the RangeMarker.
  80. * @param minimum The minimum of the range.
  81. * @param maximum The maximum of the range.
  82. */
  83. void RangeMarker::setRange(double minimum, double maximum) {
  84. callMethodNoCheck<void>(pyobj(), "set_range", minimum, maximum);
  85. }
  86. /**
  87. * @brief Gets the range marked by the RangeMarker.
  88. * @return A tuple containing the minimum and maximum of the range.
  89. */
  90. std::tuple<double, double> RangeMarker::getRange() const {
  91. GlobalInterpreterLock lock;
  92. auto const toDouble = [](Python::Object const &value) { return PyFloat_AsDouble(value.ptr()); };
  93. auto const coords = pyobj().attr("get_range")();
  94. return std::make_tuple<double, double>(toDouble(coords[0]), toDouble(coords[1]));
  95. }
  96. /**
  97. * @brief Sets the minimum the RangeMarker.
  98. * @param minimum The minimum of the range.
  99. */
  100. void RangeMarker::setMinimum(double minimum) { callMethodNoCheck<void>(pyobj(), "set_minimum", minimum); }
  101. /**
  102. * @brief Sets the minimum the RangeMarker.
  103. * @param minimum The minimum of the range.
  104. */
  105. void RangeMarker::setMaximum(double maximum) { callMethodNoCheck<void>(pyobj(), "set_maximum", maximum); }
  106. /**
  107. * @brief Gets minimum of the RangeMarker.
  108. * @return The minimum of the range.
  109. */
  110. double RangeMarker::getMinimum() const {
  111. GlobalInterpreterLock lock;
  112. return PyFloat_AsDouble(pyobj().attr("get_minimum")().ptr());
  113. }
  114. /**
  115. * @brief Gets maximum of the RangeMarker.
  116. * @return The maximum of the range.
  117. */
  118. double RangeMarker::getMaximum() const {
  119. GlobalInterpreterLock lock;
  120. return PyFloat_AsDouble(pyobj().attr("get_maximum")().ptr());
  121. }
  122. /**
  123. * @brief Notifies the relevant marker to start moving.
  124. * @param x The x position of the mouse press in axes coords.
  125. * @param y The y position of the mouse press in axes coords.
  126. */
  127. void RangeMarker::mouseMoveStart(double x, double y) { callMethodNoCheck<void>(pyobj(), "mouse_move_start", x, y); }
  128. /**
  129. * @brief Notifies the relevant marker to stop moving.
  130. */
  131. void RangeMarker::mouseMoveStop() { callMethodNoCheck<void>(pyobj(), "mouse_move_stop"); }
  132. /**
  133. * @brief Notifies the relevant marker to start moving.
  134. * @param x The x position of the mouse press in axes coords.
  135. * @param y The y position of the mouse press in axes coords.
  136. * @return True if one of the marker's within the RangeMarker has been
  137. * moved.
  138. */
  139. bool RangeMarker::mouseMove(double x, double y) {
  140. GlobalInterpreterLock lock;
  141. auto const movedPy = Python::Object(pyobj().attr("mouse_move")(x, y));
  142. return PyLong_AsLong(movedPy.ptr()) > 0;
  143. }
  144. /**
  145. * @brief Returns true if one of the marker's is moving.
  146. * @return True if one of the marker's within the RangeMarker is being moved.
  147. */
  148. bool RangeMarker::isMoving() {
  149. GlobalInterpreterLock lock;
  150. auto const movedPy = Python::Object(pyobj().attr("is_marker_moving")());
  151. return PyLong_AsLong(movedPy.ptr()) > 0;
  152. }
  153. } // namespace MantidQt::Widgets::MplCpp