|
17 | 17 | SetBoundingBoxVisibilityPayload, |
18 | 18 | SetCrossSectionVisibilityPayload, |
19 | 19 | SetEdgesVisiblePayload, |
| 20 | + SetPanelTopLeftPanelCollapsedPayload, |
| 21 | + SetPanelTopRightLegendCollapsedPayload, |
| 22 | + SetPanelTopRightPanelCollapsedPayload, |
| 23 | + SetPanelTopRightTabIndexPayload, |
20 | 24 | SetProjectionPayload, |
21 | 25 | SyncCrossSectionPlanePayload, |
22 | 26 | ) |
@@ -76,6 +80,14 @@ def sync_cross_section_plane( |
76 | 80 | self, origin: List[float], normal: List[float] |
77 | 81 | ) -> None: ... |
78 | 82 |
|
| 83 | + def set_panel_top_left_panel_collapsed(self, collapsed: bool) -> None: ... |
| 84 | + |
| 85 | + def set_panel_top_right_panel_collapsed(self, collapsed: bool) -> None: ... |
| 86 | + |
| 87 | + def set_panel_top_right_legend_collapsed(self, collapsed: bool) -> None: ... |
| 88 | + |
| 89 | + def set_panel_top_right_tab_index(self, tab_index: int) -> None: ... |
| 90 | + |
79 | 91 |
|
80 | 92 | # ---------------------------------------------------------------------- |
81 | 93 | # Trigger payload models |
@@ -209,6 +221,10 @@ class LocalApp: |
209 | 221 | set_bounding_box_visibility: shows or hides the bounding-box outline |
210 | 222 | set_projection: sets parallel or perspective projection on the camera record |
211 | 223 | sync_cross_section_plane: records a settled cross-section plane reported by the frontend |
| 224 | + set_panel_top_left_panel_collapsed: records whether the top-left panel is collapsed |
| 225 | + set_panel_top_right_panel_collapsed: records whether the top-right panel is collapsed |
| 226 | + set_panel_top_right_legend_collapsed: records whether the top-right legend is collapsed |
| 227 | + set_panel_top_right_tab_index: records which top-right tab is active |
212 | 228 | set_only_cookie: sets a cookie on the server (note: Trame server only allows a single cookie header) |
213 | 229 | Protected Methods: |
214 | 230 | _cleanup(): Cleans up the active actor in the visualization pipeline. |
@@ -504,6 +520,10 @@ def sync_camera(self, payload) -> None: |
504 | 520 | # ``set_projection`` lives here too: it is delivered the same way, but |
505 | 521 | # it writes the camera record's projection field rather than a toggle |
506 | 522 | # of its own. |
| 523 | + # |
| 524 | + # The last four carry UI panel layout, not widget state: no renderer |
| 525 | + # depends on them, so each coordinator just writes one store field. |
| 526 | + # Echoes are idempotent for the same reason as the toggles'. |
507 | 527 | # ------------------------------------------------------------------ |
508 | 528 |
|
509 | 529 | @trigger("set_cross_section_visibility") |
@@ -567,6 +587,47 @@ def sync_cross_section_plane(self, payload) -> None: |
567 | 587 | return |
568 | 588 | api.sync_cross_section_plane(payload.origin, payload.normal) |
569 | 589 |
|
| 590 | + @trigger("set_panel_top_left_panel_collapsed") |
| 591 | + @parse_payload(SetPanelTopLeftPanelCollapsedPayload) |
| 592 | + def set_panel_top_left_panel_collapsed(self, payload) -> None: |
| 593 | + """Frontend -> Backend: the top-left panel reports its collapsed state.""" |
| 594 | + api = self._mutation_api("set_panel_top_left_panel_collapsed", payload) |
| 595 | + if api is None: |
| 596 | + return |
| 597 | + api.set_panel_top_left_panel_collapsed(payload.collapsed) |
| 598 | + |
| 599 | + @trigger("set_panel_top_right_panel_collapsed") |
| 600 | + @parse_payload(SetPanelTopRightPanelCollapsedPayload) |
| 601 | + def set_panel_top_right_panel_collapsed(self, payload) -> None: |
| 602 | + """Frontend -> Backend: the top-right panel reports its collapsed state.""" |
| 603 | + api = self._mutation_api("set_panel_top_right_panel_collapsed", payload) |
| 604 | + if api is None: |
| 605 | + return |
| 606 | + api.set_panel_top_right_panel_collapsed(payload.collapsed) |
| 607 | + |
| 608 | + @trigger("set_panel_top_right_legend_collapsed") |
| 609 | + @parse_payload(SetPanelTopRightLegendCollapsedPayload) |
| 610 | + def set_panel_top_right_legend_collapsed(self, payload) -> None: |
| 611 | + """Frontend -> Backend: the top-right legend reports its collapsed state.""" |
| 612 | + api = self._mutation_api("set_panel_top_right_legend_collapsed", payload) |
| 613 | + if api is None: |
| 614 | + return |
| 615 | + api.set_panel_top_right_legend_collapsed(payload.collapsed) |
| 616 | + |
| 617 | + @trigger("set_panel_top_right_tab_index") |
| 618 | + @parse_payload(SetPanelTopRightTabIndexPayload) |
| 619 | + def set_panel_top_right_tab_index(self, payload) -> None: |
| 620 | + """Frontend -> Backend: the top-right panel reports its active tab. |
| 621 | +
|
| 622 | + The index is forwarded verbatim and is never range-checked here; the |
| 623 | + client's ``selectTab`` is the guard, so a future third tab is a UI |
| 624 | + change rather than a validation failure at this boundary. |
| 625 | + """ |
| 626 | + api = self._mutation_api("set_panel_top_right_tab_index", payload) |
| 627 | + if api is None: |
| 628 | + return |
| 629 | + api.set_panel_top_right_tab_index(payload.tab_index) |
| 630 | + |
570 | 631 | def set_only_cookie(self, key: str, value: str): |
571 | 632 | """ |
572 | 633 | Sets a cookie on the server. NOTE: there is a limitation |
|
0 commit comments