Le test exerce enfin l'annulation de la garde, dans les deux interfaces

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 19:16:41 +02:00
co-authored by Claude Opus 5
parent 82e0e16393
commit 99376a8e12
2 changed files with 123 additions and 51 deletions
+52 -51
View File
@@ -23,8 +23,8 @@ repère basculé, pour ne pas sortir à l'envers.
import threading
from PySide6.QtCore import QPointF, QRectF, Qt, QTimer
from PySide6.QtGui import QColor, QFontMetrics, QPainter, QPainterPath, QPen
from PySide6.QtWidgets import QWidget
from PySide6.QtGui import QColor, QFontMetrics, QGuiApplication, QPainter, QPainterPath, QPen
from PySide6.QtWidgets import QApplication, QWidget
from audio_level import bar_heights, push_level
from core import CONFIG, bar_metrics
@@ -184,51 +184,54 @@ class VueOverlay(QWidget):
painter.drawPath(tail)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
# `with` ferme le QPainter (.end()) meme si une exception surgit en
# cours de dessin : sans ca, la fermeture ne tenait qu'au comptage de
# references de PySide6 — suffisant aujourd'hui, fragile demain.
with QPainter(self) as painter:
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
w = CONFIG["bar_width"]
h = CONFIG["bar_height"]
x = (self.width() - w) / 2.0
y = _BOTTOM_INSET
cy = y + h / 2.0
w = CONFIG["bar_width"]
h = CONFIG["bar_height"]
x = (self.width() - w) / 2.0
y = _BOTTOM_INSET
cy = y + h / 2.0
m = bar_metrics(h)
pad, stop_d, mic_w, ecart = (
m["marge_laterale"], m["stop_diametre"], m["mic_largeur"], m["ecart_interne"]
)
bubble = self._bubble_box(x, y + h, w)
# Bascule de repère : à partir d'ici, y croît vers le HAUT comme dans
# Cocoa (voir docstring du module). On la retire (`restore`) avant de
# dessiner le texte de la bulle plus bas, pour qu'il ne sorte pas à
# l'envers.
painter.save()
painter.translate(0, self.height())
painter.scale(1, -1)
self._draw_bar_background(painter, x, y, w, h)
self._draw_stop_button(painter, x + pad + stop_d / 2, cy, stop_d)
self._draw_mic(painter, x + w - pad - mic_w / 2, cy, m)
wave_x = x + pad + stop_d + ecart
wave_w = (x + w - pad - mic_w - ecart) - wave_x
self._draw_waveform(painter, wave_x, cy, wave_w)
if bubble is not None:
self._draw_bubble_shape(painter, bubble)
painter.restore()
if bubble is not None:
# Repère Qt normal (y vers le bas) : on convertit le coin bas-gauche
# « repère Cocoa » de la bulle en un rectangle Qt haut-gauche.
text_top_qt = self.height() - (bubble["y"] + _BUBBLE_PAD + bubble["th"])
painter.setFont(bubble["font"])
painter.setPen(_qcolor(CONFIG["bubble_text_rgb"]))
painter.drawText(
QRectF(bubble["x"] + _BUBBLE_PAD, text_top_qt, bubble["tw"], bubble["th"]),
int(Qt.TextFlag.TextWordWrap),
self._status,
m = bar_metrics(h)
pad, stop_d, mic_w, ecart = (
m["marge_laterale"], m["stop_diametre"], m["mic_largeur"], m["ecart_interne"]
)
bubble = self._bubble_box(x, y + h, w)
# Bascule de repère : à partir d'ici, y croît vers le HAUT comme dans
# Cocoa (voir docstring du module). On la retire (`restore`) avant de
# dessiner le texte de la bulle plus bas, pour qu'il ne sorte pas à
# l'envers.
painter.save()
painter.translate(0, self.height())
painter.scale(1, -1)
self._draw_bar_background(painter, x, y, w, h)
self._draw_stop_button(painter, x + pad + stop_d / 2, cy, stop_d)
self._draw_mic(painter, x + w - pad - mic_w / 2, cy, m)
wave_x = x + pad + stop_d + ecart
wave_w = (x + w - pad - mic_w - ecart) - wave_x
self._draw_waveform(painter, wave_x, cy, wave_w)
if bubble is not None:
self._draw_bubble_shape(painter, bubble)
painter.restore()
if bubble is not None:
# Repère Qt normal (y vers le bas) : on convertit le coin bas-gauche
# « repère Cocoa » de la bulle en un rectangle Qt haut-gauche.
text_top_qt = self.height() - (bubble["y"] + _BUBBLE_PAD + bubble["th"])
painter.setFont(bubble["font"])
painter.setPen(_qcolor(CONFIG["bubble_text_rgb"]))
painter.drawText(
QRectF(bubble["x"] + _BUBBLE_PAD, text_top_qt, bubble["tw"], bubble["th"]),
int(Qt.TextFlag.TextWordWrap),
self._status,
)
class OverlayQt:
@@ -253,13 +256,11 @@ class OverlayQt:
def _ensure_view(self):
if self._view is not None:
return
# Import local : PySide6 ne doit être exigé QUE quand cette classe est
# réellement instanciée (cf interface/__init__.py::classe_overlay_pour),
# jamais au chargement du module — sinon les tests réclameraient Qt sur
# toute machine, y compris ce Mac où Cocoa suffit.
from PySide6.QtGui import QGuiApplication
from PySide6.QtWidgets import QApplication
# PySide6 est déjà exigé dès l'IMPORT de ce module (QWidget, QTimer...
# ci-dessus) : le report réel n'est pas ici, mais dans la fabrique
# (interface/__init__.py::classe_overlay_pour), qui n'importe
# `interface.qt` que pour la branche win32 — jamais sur ce Mac, où
# Cocoa suffit.
if QApplication.instance() is None:
QApplication([])