"""Layout management helpers for interactive or batch FieldView sessions.
The functions in this module operate on graphics windows within the current
FieldView layout. Window numbers are 1-based and match the numbering used by
the host UI. The current window is the default target whenever an operation
accepts ``window=None``.
Use :mod:`fieldview.layout` when you need to inspect the current pane layout,
switch the active window, split a view into additional panes, close panes, or
configure multi-window view synchronization.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_vertical(mode="copy")
>>> fv.layout.select(split.new_window)
"""
from __future__ import annotations
from typing import cast
from ._core_utils import _core_call, _normalize_window, _require_core_func
from .data import (
WindowList,
WindowSplitResult,
_build_window_list,
_build_window_split_result,
)
from .exceptions import CoreError, InvalidArgumentError
__all__ = [
"get_windows",
"current",
"select",
"split_vertical",
"split_horizontal",
"get_view_sync",
"set_view_sync",
"close",
]
def _normalize_mode(mode: str) -> str:
if not isinstance(mode, str):
raise InvalidArgumentError("mode must be a string")
lowered = mode.strip().lower()
if lowered not in {"copy", "instance", "empty"}:
raise InvalidArgumentError("mode must be 'copy', 'instance', or 'empty'")
return lowered
[docs]
def get_windows() -> WindowList:
"""Return metadata for all graphics windows in the current layout.
This works in both interactive and batch graphics sessions.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> windows = fv.layout.get_windows()
"""
func = _require_core_func("get_windows")
windows = _build_window_list(cast(dict[str, object], _core_call(func)))
if windows is None:
raise CoreError("get_windows returned invalid payload.")
return windows
[docs]
def current() -> int:
"""Return the 1-based number of the current graphics window.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> window = fv.layout.current()
"""
windows = get_windows()
if windows.current_window is None:
raise CoreError("No current window is available.")
return windows.current_window
[docs]
def select(window: int) -> None:
"""Make ``window`` the current graphics window.
Args:
window: 1-based graphics window number to select.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_vertical(mode="copy")
>>> fv.layout.select(split.source_window)
"""
func = _require_core_func("select_window")
_core_call(func, _normalize_window(window))
[docs]
def split_vertical(mode: str = "copy", window: int | None = None) -> WindowSplitResult:
"""Split a window vertically and return metadata for the new window.
``window=None`` targets the current window. The new window becomes
current on success.
Args:
mode: Split mode, one of ``copy``, ``instance``, or ``empty``.
window: Optional 1-based source window number. When omitted, the
current graphics window is split.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_vertical(mode="copy")
"""
func = _require_core_func("split_window_vertical")
resp = cast(
dict[str, object],
_core_call(func, _normalize_mode(mode), _normalize_window(window)),
)
return _build_window_split_result(resp)
[docs]
def split_horizontal(
mode: str = "copy", window: int | None = None
) -> WindowSplitResult:
"""Split a window horizontally and return metadata for the new window.
``window=None`` targets the current window. The new window becomes
current on success.
Args:
mode: Split mode, one of ``copy``, ``instance``, or ``empty``.
window: Optional 1-based source window number. When omitted, the
current graphics window is split.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_horizontal(mode="copy")
"""
func = _require_core_func("split_window_horizontal")
resp = cast(
dict[str, object],
_core_call(func, _normalize_mode(mode), _normalize_window(window)),
)
return _build_window_split_result(resp)
[docs]
def close(window: int | None = None) -> None:
"""Close a graphics window.
``window=None`` closes the current window. When the current child window
is closed, FieldView selects its parent window.
Args:
window: Optional 1-based window number to close. When omitted, the
current graphics window is closed.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_vertical(mode="copy")
>>> fv.layout.close(split.new_window)
"""
func = _require_core_func("close_window")
_core_call(func, _normalize_window(window))
[docs]
def get_view_sync(window: int | None = None) -> bool:
"""Return whether a window propagates view/camera changes to synced panes.
``window=None`` targets the current window.
Args:
window: Optional 1-based window number. When omitted, the current
graphics window is used.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> enabled = fv.layout.get_view_sync()
"""
func = _require_core_func("get_window_view_sync")
return bool(_core_call(func, _normalize_window(window)))
[docs]
def set_view_sync(enabled: bool, window: int | None = None) -> None:
"""Enable or disable multi-window view syncing for a graphics window.
``window=None`` targets the current window.
Args:
enabled: Whether view/camera synchronization should be enabled for the
target window.
window: Optional 1-based window number. When omitted, the current
graphics window is used.
Example:
.. code-block:: python
>>> import os
>>> import fieldview as fv
>>> data_dir = os.path.join(fv.home, "examples", "f18")
>>> ds = fv.data.load_plot3d(
... os.path.join(data_dir, "f18i9b_g_bin"),
... os.path.join(data_dir, "f18i9b_q_bin"),
... )
>>> split = fv.layout.split_vertical(mode="copy")
>>> fv.layout.set_view_sync(True, window=split.source_window)
>>> fv.layout.set_view_sync(True, window=split.new_window)
"""
if not isinstance(enabled, bool):
raise InvalidArgumentError("enabled must be a boolean")
func = _require_core_func("set_window_view_sync")
_core_call(func, enabled, _normalize_window(window))