Добавить общее перетаскивание графиков и независимые шкалы амплитуд

This commit is contained in:
2026-10-02 16:41:26 +03:00
parent 025a3fde28
commit 3463e95eb3
3 changed files with 361 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
"""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()