"""Presentation state for waveform rulers; no transport or wire processing.""" from dataclasses import dataclass def drag_zoom_factor(delta_pixels): """Visual gesture mapping: 200 pixels doubles the selected axis.""" return 2 ** (max(-1000., min(1000., delta_pixels)) / 200.) @dataclass class Marker: name: str axis: str value: float color: str visible: bool = False class WaveformMarkers: def __init__(self): self.items = [Marker('X1', 'x', .2, '#ffce63'), Marker('X2', 'x', .4, '#ffce63'), Marker('X3', 'x', .6, '#e794ff'), Marker('X4', 'x', .8, '#e794ff'), Marker('Y1', 'y', .2, '#72e7ff'), Marker('Y2', 'y', .4, '#72e7ff'), Marker('Y3', 'y', .6, '#a9df79'), Marker('Y4', 'y', .8, '#a9df79')] self._math = None self.session = None self.bounds = None def window(self, session, start, end): if session != self.session or self.bounds is None: for marker, fraction in zip(self.items[:4], (.2, .4, .6, .8)): marker.value = start + (end-start)*fraction self.session, self.bounds = session, (start, end) def reset(self): if self.bounds: start, end = self.bounds for marker, fraction in zip(self.items[:4], (.2, .4, .6, .8)): marker.value = start + (end-start)*fraction for marker, fraction in zip(self.items[4:], (.2, .4, .6, .8)): marker.value = fraction def measurements(self, period_ns): """Use the same native delta operation as Android's plotDelta.""" if self._math is None: from protocan.plot import PlotMath from .native import NativeAnalyzer self._math = PlotMath(NativeAnalyzer().lib) result = [] for index in range(0, 8, 2): a, b = self.items[index:index+2] if not (a.visible and b.visible): continue if a.axis == 'x': if self.bounds is None: continue factor = period_ns / 1e9 av, bv = a.value*factor, b.value*factor delta = self._math.delta(a.value, b.value, factor) frequency = 1/abs(delta) if delta else None else: av, bv = 100*(1-a.value), 100*(1-b.value) delta = self._math.delta(av, bv) frequency = None result.append((a, b, av, bv, delta, frequency)) return result def place(self, index, fraction): marker = self.items[index] fraction = min(1., max(0., fraction)) if marker.axis == 'x': if self.bounds is None: return start, end = self.bounds marker.value = start + (end-start)*fraction else: marker.value = fraction def fraction(self, marker): if marker.axis == 'y': return marker.value if self.bounds is None: return 0. start, end = self.bounds return (marker.value-start)/max(1, end-start)