"""Shared drag gestures, with real Qt events and C math, without SETGUI imports.""" import ctypes import os import unittest from dataclasses import replace os.environ.setdefault('QT_QPA_PLATFORM', 'offscreen') try: from PySide6.QtCore import QEvent, QPoint, QPointF, QRectF, Qt, Signal from PySide6.QtGui import QMouseEvent from PySide6.QtTest import QTest from PySide6.QtWidgets import QApplication, QCheckBox, QWidget except ImportError: from PySide2.QtCore import QEvent, QPoint, QPointF, QRectF, Qt, Signal from PySide2.QtGui import QMouseEvent from PySide2.QtTest import QTest from PySide2.QtWidgets import QApplication, QCheckBox, QWidget from protocan.plot import Bounds, Marker, Markers, PlotMath, Viewport from set_devices.qt_ports.plot_drag import PlotDragInteraction class Canvas(PlotDragInteraction, QWidget): view_changed = Signal() def __init__(self, core): super().__init__() self.core = core self.viewport = Viewport(.25, .25, .5, .5) self.markers = replace(Markers(a=40, b=60, e=50, f=65), y_enabled=True) self.marker_mode = QCheckBox(self) self.marker_mode.setChecked(True) self.marker_mode.hide() self.has_plot_data = True self.lock_x = self.lock_y = False self._press = self._dragged = None self.single_clicks = [] self.resize(440, 340) @property def visible_bounds(self): return Bounds(0, 100, 0, 100).visible(self.core, self.viewport) def plot_rect(self): return QRectF(20, 20, 400, 300) def value_rect(self): return QRectF(20, 20, 400, 200) def _refresh_controls(self): pass def _single_cursor_click(self, pos): self.single_clicks.append(pos) @unittest.skipUnless(os.environ.get('SETPROTOCOL_LIBRARY'), 'Set SETPROTOCOL_LIBRARY') class PlotDragTests(unittest.TestCase): @classmethod def setUpClass(cls): cls.app = QApplication.instance() or QApplication([]) cls.core = PlotMath(ctypes.CDLL(os.environ['SETPROTOCOL_LIBRARY'])) def setUp(self): self.plot = Canvas(self.core) self.plot.show() self.app.processEvents() def tearDown(self): self.plot.close() def drag(self, start, end, modifiers=Qt.NoModifier): QTest.mousePress(self.plot, Qt.LeftButton, modifiers, start) QTest.mouseRelease(self.plot, Qt.LeftButton, modifiers, end) def test_empty_space_pans_x_and_preserves_markers(self): before, markers = self.plot.viewport, self.plot.markers self.drag(QPoint(220, 180), QPoint(260, 210)) self.assertEqual(before.transform(self.core, pan_x=.1), self.plot.viewport) self.assertEqual(markers, self.plot.markers) def test_shift_over_marker_pans_only_y_and_respects_lock(self): before, markers = self.plot.viewport, self.plot.markers self.drag(QPoint(140, 180), QPoint(180, 200), Qt.ShiftModifier) self.assertEqual(before.transform(self.core, pan_y=.1), self.plot.viewport) self.assertEqual(markers, self.plot.markers) self.plot.lock_y = True before = self.plot.viewport self.drag(QPoint(140, 180), QPoint(180, 200), Qt.ShiftModifier) self.assertEqual(before, self.plot.viewport) def test_marker_capture_in_analog_and_digital_panes(self): before = self.plot.viewport # X marker A at x=140 remains draggable in a digital lane. self.drag(QPoint(145, 270), QPoint(185, 290)) self.assertAlmostEqual(45, self.plot.markers.a) self.assertEqual(before, self.plot.viewport) # Y marker E at y=120 uses the analog pane's height. self.drag(QPoint(220, 125), QPoint(240, 145)) self.assertAlmostEqual(45, self.plot.markers.e) self.assertEqual(before, self.plot.viewport) def test_click_miss_and_locked_x_do_not_move_markers(self): before, markers = self.plot.viewport, self.plot.markers self.drag(QPoint(220, 180), QPoint(220, 180)) self.assertEqual(before, self.plot.viewport) self.assertEqual(markers, self.plot.markers) self.assertEqual(1, len(self.plot.single_clicks)) self.plot.lock_x = True self.drag(QPoint(220, 180), QPoint(260, 210)) self.assertEqual(before, self.plot.viewport) self.assertEqual(markers, self.plot.markers) self.assertEqual(1, len(self.plot.single_clicks)) def test_marker_click_and_drag_returning_to_start_are_not_single_clicks(self): point = QPoint(220, 180) self.drag(QPoint(140, 180), QPoint(140, 180)) QTest.mousePress(self.plot, Qt.LeftButton, pos=point) moved = point + QPoint(40, 0) event = QMouseEvent(QEvent.MouseMove, QPointF(moved), QPointF(self.plot.mapToGlobal(moved)), Qt.NoButton, Qt.LeftButton, Qt.NoModifier) self.app.sendEvent(self.plot, event) QTest.mouseRelease(self.plot, Qt.LeftButton, pos=point) self.assertEqual([], self.plot.single_clicks) if __name__ == '__main__': unittest.main()