Source code for pyqt_reactive.forms.object_form_document_renderer
"""Render one or more ObjectState-backed objects as read-only forms."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Generic, TypeVar
from PyQt6.QtWidgets import QComboBox, QHBoxLayout, QLabel, QVBoxLayout, QWidget
from pyqt_reactive.theming import ColorScheme
T = TypeVar("T")
[docs]
@dataclass(frozen=True, slots=True)
class ObjectFormEntry(Generic[T]):
"""One named object rendered by ObjectFormDocumentRenderer."""
name: str
object_instance: T
summary: str | None = None
[docs]
@dataclass(frozen=True, slots=True)
class ObjectFormDocument(Generic[T]):
"""A read-only object-form document with one or more selectable entries."""
title: str
entries: tuple[ObjectFormEntry[T], ...]
selector_label: str = "Entry:"
def __post_init__(self) -> None:
if not self.entries:
raise ValueError("ObjectFormDocument requires at least one entry.")
[docs]
@dataclass(frozen=True, slots=True)
class ObjectFormRenderContext:
"""Rendering context for ObjectState-backed read-only forms."""
parent: QWidget
scope_id: str | None = None
color_scheme: ColorScheme | None = None
exclude_params: tuple[str, ...] = ()
[docs]
class ObjectFormDocumentRenderer:
"""Render an ObjectFormDocument into an existing Qt layout."""
[docs]
def render(self, layout: QVBoxLayout, document: ObjectFormDocument[T]) -> None:
entries = document.entries
if len(entries) == 1:
self._add_object_form(layout, entries[0])
return
selector_row = QHBoxLayout()
selector_label = QLabel(document.selector_label)
selector = QComboBox()
selector.addItems([entry.name for entry in entries])
selector_row.addWidget(selector_label)
selector_row.addWidget(selector, 1)
layout.addLayout(selector_row)
form_container = QWidget()
form_layout = QVBoxLayout(form_container)
form_layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(form_container)
entries_by_name = {entry.name: entry for entry in entries}
def render_selected(entry_name: str) -> None:
_clear_layout(form_layout)
self._add_object_form(form_layout, entries_by_name[entry_name])
selector.currentTextChanged.connect(render_selected)
render_selected(selector.currentText())
def _add_object_form(
self,
layout: QVBoxLayout,
entry: ObjectFormEntry[T],
) -> None:
from objectstate import ObjectState
from pyqt_reactive.forms.parameter_form_manager import (
FormManagerConfig,
ParameterFormManager,
)
if entry.summary:
layout.addWidget(QLabel(entry.summary))
state = ObjectState(
object_instance=entry.object_instance,
scope_id=self._context.scope_id,
)
object_form = ParameterFormManager(
state=state,
config=FormManagerConfig(
parent=self._context.parent,
read_only=True,
color_scheme=self._context.color_scheme,
exclude_params=list(self._context.exclude_params),
),
)
layout.addWidget(object_form)
def _clear_layout(layout: QVBoxLayout) -> None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()