Bring the Plotly canvas in line with opstool's visualisation recipes. Camera / interaction: - frame the camera in plotly's normalized scene units, using the model bounds (grid excluded); a data-unit eye rendered the model as a speck - use turntable dragmode so Z stays up and the horizon stays level - align mouse bindings with the PyVista/VTK backend and document them in Help → Mouse Controls Visualisation: - colour deformed / modal shapes by response with a shared colourbar - scale load arrows by |F|, tint per load pattern, hover the magnitude, and fix cones rendering as oversized fins (sizemode scaled, not absolute) - draw DOF-accurate support glyphs (ported from opstool; see NOTICE) - add an undeformed-reference overlay on both canvas backends - play mode shapes with plotly frame animation in-page Tests: builder unit tests plus GUI regression tests for gestures, the deformed push, the undeformed reference and animation payloads.
59 lines
1.8 KiB
Python
59 lines
1.8 KiB
Python
"""Smoke test for the MainWindow.
|
|
|
|
Marked as ``gui`` so it can be deselected on environments without a display.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
pytest.importorskip("PySide6")
|
|
pytest.importorskip("pyvistaqt")
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_main_window_opens(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
from otko.views.main_window import MainWindow
|
|
|
|
window = MainWindow()
|
|
qtbot.addWidget(window)
|
|
window.show()
|
|
assert window.isVisible()
|
|
assert window.windowTitle() == "OTKO"
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_close_dirty_hidden_window_does_not_block(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
"""Closing a dirty but hidden window must not raise a modal prompt.
|
|
|
|
Qt closes hidden widgets during teardown (as ``pytest-qt`` does); a
|
|
modal "unsaved changes" dialog there would block forever with no user
|
|
to answer it. The prompt is therefore gated on visibility.
|
|
"""
|
|
from otko.views.main_window import MainWindow
|
|
|
|
window = MainWindow()
|
|
qtbot.addWidget(window)
|
|
window._vm.new_project()
|
|
window._vm.mark_dirty()
|
|
assert not window.isVisible()
|
|
assert window.close() is True
|
|
assert window._vm.is_dirty # unchanged: the prompt was skipped
|
|
|
|
|
|
@pytest.mark.gui
|
|
def test_mouse_controls_dialog_is_wired_and_reused(qtbot) -> None: # type: ignore[no-untyped-def]
|
|
from otko.views.dialogs.mouse_controls import MouseControlsDialog
|
|
from otko.views.main_window import MainWindow
|
|
|
|
window = MainWindow()
|
|
qtbot.addWidget(window)
|
|
|
|
window._on_mouse_controls()
|
|
dialog = window._mouse_controls_dialog
|
|
assert isinstance(dialog, MouseControlsDialog)
|
|
assert dialog.windowTitle() == "Mouse Controls"
|
|
|
|
# Raising the action again reuses the same modeless window.
|
|
window._on_mouse_controls()
|
|
assert window._mouse_controls_dialog is dialog
|