Расширить обмен по шинам, CAN-адаптеры и обработку графиков
Добавить очереди операций PBUS/SBUS, общую консоль, настройки Candle и SLCAN, декодеры DSView и обработку плотных графиков. Обновить протокол Бальзам и проверки общих компонентов.
This commit is contained in:
@@ -8,6 +8,13 @@ except ImportError:
|
||||
from PySide2.QtCore import QPointF, Qt
|
||||
from PySide2.QtGui import QColor
|
||||
from protocan.plot import Bounds, Viewport
|
||||
from set_devices.plot_ticks import tick_precision # Обе амплитудные шкалы должны различать соседние деления даже при сильном приближении.
|
||||
|
||||
|
||||
def amplitude_axis_margin(widget, bounds): # Отступ правой шкалы зависит от ширины её уточнённых подписей в текущем шрифте виджета.
|
||||
step = (bounds.top - bounds.bottom) / max(100, widget.height() / 50) # Консервативная плотность делений даёт запас точности без обращения к геометрии, которая сама вычисляет этот отступ.
|
||||
labels = [f'{value:.{tick_precision(value, step)}g}' for value in (bounds.bottom, bounds.top)] # Оцениваем самые длинные крайние подписи в том же формате, что используется при отрисовке шкалы.
|
||||
return max(72, 14 + max(widget.fontMetrics().horizontalAdvance(label) for label in labels)) # Прежний минимум 72 пикселя и запас 14 пикселей сохраняют обычный вид и предотвращают обрезание длинных чисел.
|
||||
|
||||
|
||||
def small_amplitude(values, threshold=30):
|
||||
@@ -32,7 +39,8 @@ def split_amplitudes(series, threshold=30):
|
||||
class DualAxisPlot:
|
||||
"""Mixin: left axis for large channels, right for small channels.
|
||||
|
||||
Shift-wheel selects the axis by the pointer's half of the analog pane.
|
||||
Ctrl + колесо выбирает шкалу по половине аналоговой области под указателем.
|
||||
Shift + ЛКМ перемещает одну Y, выбранную стороной графика при нажатии.
|
||||
The host supplies series_bounds/project_series rendering hooks.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -115,23 +123,28 @@ class DualAxisPlot:
|
||||
def plot_rect(self):
|
||||
rect = super().plot_rect()
|
||||
if self.right_axis_keys:
|
||||
rect.setWidth(max(1, rect.width() - 72))
|
||||
rect.setWidth(max(1, rect.width() - self.right_axis_margin())) # Уточнённые подписи правой Y получают достаточно места без выхода за границы виджета.
|
||||
return rect
|
||||
|
||||
def right_axis_margin(self):
|
||||
return 72 if self.right_axis_keys else 0
|
||||
return amplitude_axis_margin(self, self.right_visible_bounds) if self.right_axis_keys else 0 # Используем фактический правый диапазон и текущий шрифт; при отсутствии правой шкалы отступ не нужен.
|
||||
|
||||
def reset_viewport(self):
|
||||
self.right_viewport = Viewport()
|
||||
super().reset_viewport()
|
||||
|
||||
def _capture_y_pan(self):
|
||||
return super()._capture_y_pan(), self.right_viewport
|
||||
def _capture_y_pan(self, event=None): # Снимок содержит области выбранных шкал; None исключает другую шкалу из всего текущего жеста.
|
||||
left, right = super()._capture_y_pan(event), self.right_viewport # Сохраняем начальные области до движения, чтобы смещение считалось от точки нажатия без накопления ошибок.
|
||||
if event is not None and event.modifiers() & Qt.ShiftModifier and self.right_axis_keys and self.has_left_axis(): # Выбор стороны нужен только для Shift с двумя отдельными Y; Ctrl, стрелки и единственная Y сохраняют общий перенос.
|
||||
position = event.position() if hasattr(event, 'position') else event.localPos() # Получаем локальную точку нажатия одинаково для Qt 6 и Qt 5.
|
||||
return (None, right) if position.x() >= self.value_rect().center().x() else (left, None) # Центр аналоговой области разделяет стороны; на самой границе выбираем правую Y, как при Ctrl с колесом.
|
||||
return left, right # Общие команды перемещения получают обе области, а график с одной Y использует свою основную область.
|
||||
|
||||
def _apply_y_pan(self, fraction, initial):
|
||||
left, right = initial
|
||||
super()._apply_y_pan(fraction, left)
|
||||
if self.core and not self.lock_y and self.right_axis_keys and self.has_left_axis():
|
||||
if left is not None: # Отсутствующая левая область означает, что Shift выбрал только правую шкалу при нажатии.
|
||||
super()._apply_y_pan(fraction, left) # Общий обработчик перемещает левую Y и учитывает её фиксацию без изменения временной оси.
|
||||
if right is not None and self.core and not self.lock_y and self.right_axis_keys and self.has_left_axis(): # Правая Y сдвигается лишь при включении в снимок жеста, наличии двух шкал и снятой общей фиксации Y.
|
||||
self.right_viewport = right.transform(self.core, pan_y=fraction)
|
||||
|
||||
def reset_interaction(self):
|
||||
@@ -139,7 +152,7 @@ class DualAxisPlot:
|
||||
super().reset_interaction()
|
||||
|
||||
def wheelEvent(self, event):
|
||||
if not event.modifiers() & Qt.ShiftModifier:
|
||||
if not event.modifiers() & Qt.ControlModifier: # Ctrl включает масштаб Y выбранной стороны; колесо без Ctrl, включая Shift, передаётся общей навигации по X.
|
||||
return super().wheelEvent(event)
|
||||
pos = event.position() if hasattr(event, 'position') else event.posF()
|
||||
rect = self.value_rect()
|
||||
@@ -177,7 +190,7 @@ def paint_right_axis(painter, core, rect, bounds):
|
||||
for index in range(count):
|
||||
value = (first + index) * step
|
||||
y = rect.top() + bounds.fraction(core, value, True) * rect.height()
|
||||
painter.drawText(QPointF(rect.right() + 7, y + 4), f'{value:.4g}')
|
||||
painter.drawText(QPointF(rect.right() + 7, y + 4), f'{value:.{tick_precision(value, step)}g}') # Сохраняем четыре значащие цифры при обычном масштабе и добавляем разряды по шагу правой шкалы при приближении.
|
||||
painter.restore()
|
||||
|
||||
|
||||
@@ -189,7 +202,7 @@ class SingleAmplitudeAxis:
|
||||
def plot_rect(self):
|
||||
rect = super().plot_rect()
|
||||
if not self.has_left_axis():
|
||||
rect.setWidth(max(1, rect.width() - 72))
|
||||
rect.setWidth(max(1, rect.width() - amplitude_axis_margin(self, self.visible_bounds))) # Единственная правая шкала тренда или спектра получает тот же запас для длинных подписей при приближении.
|
||||
return rect
|
||||
|
||||
def paint_axes(self, painter):
|
||||
|
||||
Reference in New Issue
Block a user