Source code for pyqt_reactive.widgets.shared.manager_ui_scaffold
"""Shared UI scaffold helpers for manager-like widgets."""
from __future__ import annotations
from dataclasses import dataclass
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import (
QHBoxLayout,
QLabel,
QScrollArea,
QSizePolicy,
QSplitter,
QVBoxLayout,
QWidget,
)
from pyqt_reactive.core import ReorderableListWidget
from pyqt_reactive.widgets.shared.button_panel import ButtonPanel
from pyqt_reactive.widgets.shared.list_item_delegate import MultilinePreviewItemDelegate
[docs]
@dataclass(frozen=True)
class ManagerHeaderParts:
"""Container returned by create_manager_header."""
header: QWidget
status_label: QLabel
status_scroll: QScrollArea | None
[docs]
@dataclass(frozen=True)
class ManagerWidgetUiParts:
"""Widgets created for a standard manager list UI."""
header: QWidget
status_label: QLabel
status_scroll: QScrollArea | None
item_list: ReorderableListWidget
button_panel: ButtonPanel
[docs]
def create_manager_header(
*,
title: str,
color_scheme,
enable_status_scrolling: bool = False,
) -> ManagerHeaderParts:
"""Create a standard manager header (title + status label)."""
header = QWidget()
header_layout = QHBoxLayout(header)
header_layout.setContentsMargins(5, 5, 5, 5)
title_label = QLabel(title)
title_label.setFont(QFont("Arial", 12, QFont.Weight.Bold))
title_label.setStyleSheet(
f"color: {color_scheme.to_hex(color_scheme.text_accent)};"
)
header_layout.addWidget(title_label)
if enable_status_scrolling:
status_scroll = QScrollArea()
status_scroll.setWidgetResizable(False)
status_scroll.setHorizontalScrollBarPolicy(
Qt.ScrollBarPolicy.ScrollBarAlwaysOff
)
status_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
status_scroll.setFrameShape(QScrollArea.Shape.NoFrame)
status_scroll.setAlignment(
Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignRight
)
status_scroll.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
status_scroll.setFixedHeight(20)
status_scroll.setContentsMargins(0, 0, 0, 0)
status_scroll.setStyleSheet(
"QScrollArea { padding: 0px; margin: 0px; background: transparent; }"
)
status_label = QLabel("Ready")
status_label.setStyleSheet(
f"color: {color_scheme.to_hex(color_scheme.status_success)}; "
"font-weight: bold; padding: 0px; margin: 0px;"
)
status_label.setTextFormat(Qt.TextFormat.PlainText)
status_label.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
status_label.setFixedHeight(20)
status_label.setContentsMargins(0, 0, 0, 0)
status_label.setAlignment(
Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignRight
)
status_scroll.setWidget(status_label)
header_layout.addWidget(status_scroll, 1)
QTimer.singleShot(0, status_label.adjustSize)
return ManagerHeaderParts(
header=header,
status_label=status_label,
status_scroll=status_scroll,
)
header_layout.addStretch()
status_label = QLabel("Ready")
status_label.setStyleSheet(
f"color: {color_scheme.to_hex(color_scheme.status_success)}; "
"font-weight: bold;"
)
header_layout.addWidget(status_label)
return ManagerHeaderParts(
header=header,
status_label=status_label,
status_scroll=None,
)
[docs]
def create_manager_list_widget(
*,
color_scheme,
style_generator,
delegate_manager,
) -> ReorderableListWidget:
"""Create a styled manager list widget with the multiline preview delegate."""
list_widget = ReorderableListWidget()
list_widget.setStyleSheet(style_generator.generate_list_widget_style())
delegate = MultilinePreviewItemDelegate(
name_color=color_scheme.to_qcolor(color_scheme.text_primary),
preview_color=color_scheme.to_qcolor(color_scheme.text_secondary),
selected_text_color=color_scheme.to_qcolor(color_scheme.selection_text),
parent=list_widget,
manager=delegate_manager,
)
list_widget.setItemDelegate(delegate)
return list_widget
[docs]
def setup_manager_widget_ui(
*,
owner: QWidget,
title: str,
color_scheme,
style_generator,
enable_status_scrolling: bool,
button_configs,
on_action,
button_grid_columns: int,
) -> ManagerWidgetUiParts:
"""Create and lay out the standard manager header, list, and button panel."""
header_parts = create_manager_header(
title=title,
color_scheme=color_scheme,
enable_status_scrolling=enable_status_scrolling,
)
item_list = create_manager_list_widget(
color_scheme=color_scheme,
style_generator=style_generator,
delegate_manager=owner,
)
button_panel = ButtonPanel(
button_configs=button_configs,
on_action=on_action,
style_generator=style_generator,
grid_columns=button_grid_columns,
parent=owner,
)
setup_vertical_manager_layout(
owner=owner,
header=header_parts.header,
top_widget=item_list,
bottom_widget=button_panel,
)
return ManagerWidgetUiParts(
header=header_parts.header,
status_label=header_parts.status_label,
status_scroll=header_parts.status_scroll,
item_list=item_list,
button_panel=button_panel,
)
[docs]
def setup_vertical_manager_layout(
*,
owner: QWidget,
header: QWidget,
top_widget: QWidget,
bottom_widget: QWidget,
margins: tuple[int, int, int, int] = (2, 2, 2, 2),
spacing: int = 2,
initial_sizes: tuple[int, int] = (1000, 1),
stretch_factors: tuple[int, int] = (1, 0),
) -> QSplitter:
"""Create standard manager layout: header + vertical splitter."""
main_layout = QVBoxLayout(owner)
main_layout.setContentsMargins(*margins)
main_layout.setSpacing(spacing)
main_layout.addWidget(header)
splitter = QSplitter(Qt.Orientation.Vertical)
splitter.addWidget(top_widget)
splitter.addWidget(bottom_widget)
splitter.setSizes([initial_sizes[0], initial_sizes[1]])
splitter.setStretchFactor(0, stretch_factors[0])
splitter.setStretchFactor(1, stretch_factors[1])
main_layout.addWidget(splitter)
return splitter