feat: route both canvas backends through RenderStyle

Colours that were hard-coded in the renderers now come from the shared
style: nodes, supports, nodal/element loads, section extrusions (+
opacity) and label font size. The PyVista frame LUT becomes a four-slot
palette [beam, truss, link, selected] with the cell scalar carrying the
family slot, so VTK matches the Plotly backend's per-family colouring
that landed earlier. Adds style helpers shared by both backends
(element_family_index, family_palette) and an immutable with_updates().

The style also gains the editable field table (STYLE_FIELDS) the Plot
Properties dialog is built from.
This commit is contained in:
smillmorel 2026-09-16 19:31:30 -04:00
commit 56f1f6c08b
5 changed files with 285 additions and 57 deletions

View file

@ -24,6 +24,7 @@ from otko.views.canvas3d.model_renderer import (
RendererMode,
_classify_support,
)
from otko.views.canvas3d.style import SELECTED_STATE
# ──────────────────────────── support classification ────────────────────────────
@ -125,9 +126,13 @@ def test_update_selection_writes_state_array(offscreen_plotter, small_3d_project
frame_states = np.asarray(r._frame_pd.cell_data["_oss_state"]).tolist()
# Nodes 1 and 3 selected → row 0 and row 2
assert node_states == [1, 0, 1]
# Element 2 selected → it's the second frame (index 1 in frame_ids_ordered)
# Frame cells carry the palette slot: the element family normally, and
# SELECTED_STATE when selected.
selected_frame_idx = r._frame_id_to_row[2]
assert frame_states[selected_frame_idx] == 1
assert frame_states[selected_frame_idx] == SELECTED_STATE
for index, family in enumerate(r._frame_family):
expected = SELECTED_STATE if index == selected_frame_idx else family
assert frame_states[index] == expected
def test_clear_selection(offscreen_plotter, small_3d_project) -> None: # type: ignore[no-untyped-def]