Source code for radioviz.services.mpl_helpers

#  Copyright 2025–2026 European Union
#  Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
#  SPDX-License-Identifier: EUPL-1.2
"""
Helper utilities for bridging Matplotlib and Qt interactions.

This module provides utilities to manage Matplotlib navigation modes and
handle context menu events between Qt widgets and Matplotlib canvases.
"""

from typing import Any, cast

from matplotlib.backend_bases import MouseButton, MouseEvent, _Mode
from PySide6.QtCore import QPoint






[docs] class MplContextMenuBridge: """ Helper to bridge Qt context menu events with Matplotlib interaction state. This class handles the conversion of Qt context menu events to Matplotlib coordinates and ensures proper interaction state management when context menus are triggered over Matplotlib canvases. """ def __init__(self, canvas: Any) -> None: """ Initialize the MplContextMenuBridge. :param canvas: The Matplotlib canvas to bridge events for :type canvas: matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg """ self._canvas: Any = canvas # ------------------------------------------------------------------
[docs] def handle_context_request(self, source_widget: Any, pos: QPoint) -> QPoint: """ Handle a context menu request from a Qt widget. Converts Qt widget coordinates to global coordinates and then to Matplotlib canvas coordinates. Cancels any ongoing Matplotlib interaction if the click is within the canvas area. :param source_widget: The Qt widget that triggered the context menu :type source_widget: QWidget :param pos: The position of the context menu trigger in widget coordinates :type pos: QPoint :return: The global position of the context menu :rtype: QPoint """ # 1. Convert to global coordinates (Qt requirement) global_pos = source_widget.mapToGlobal(pos) # 2. Convert to canvas-local Qt coordinates canvas_pos_qt = self._canvas.mapFromGlobal(global_pos) # 3. Cancel Matplotlib interaction if click is inside canvas if self._canvas.rect().contains(canvas_pos_qt): self._cancel_mpl_interaction(canvas_pos_qt) return cast(QPoint, global_pos)
[docs] def _cancel_mpl_interaction(self, canvas_pos_qt: QPoint) -> None: """ Cancel ongoing Matplotlib interaction at the given position. Injects a synthetic mouse release event to cancel any active pan/zoom operations in Matplotlib. :param canvas_pos_qt: Position in canvas coordinates :type canvas_pos_qt: QPoint """ # Convert Qt → Matplotlib pixel coordinates mpl_x = canvas_pos_qt.x() mpl_y = self._canvas.height() - canvas_pos_qt.y() # Inject synthetic mouse release event = MouseEvent( name='button_release_event', canvas=self._canvas, x=mpl_x, y=mpl_y, button=MouseButton.LEFT, guiEvent=None, ) self._canvas.callbacks.process('button_release_event', event)