API Reference

This section contains the complete API documentation for pyqt-reactive.

Core Modules

pyqt_reactive.core

Core PyQt6 utilities.

pyqt_reactive.protocols

Widget protocol definitions and adapters.

pyqt_reactive.forms

Form generation and management.

pyqt_reactive.widgets

Extended widget implementations.

pyqt_reactive.theming

Theming and styling system.

pyqt_reactive.animation

Animation and visual effects system.

pyqt_reactive.windows

pyqt_reactive.dialogs

Reusable dialogs for PyQt FormGen.

Module Documentation

pyqt_reactive.core

Core PyQt6 utilities with zero external dependencies.

Core PyQt6 utilities.

Pure PyQt6 utility components with zero external dependencies. Foundational widgets and helpers with no domain-specific logic.

class pyqt_reactive.core.DebounceTimer(delay_ms: int, handler: Callable[[], None])[source]

Bases: object

Reusable trailing debounce timer.

Restarts timer on each call. Handler fires only after delay_ms of inactivity.

Usage:

self._debounce = DebounceTimer(delay_ms=200, handler=self._do_update)

def on_text_changed(self):

self._debounce.trigger() # Restarts timer

__init__(delay_ms: int, handler: Callable[[], None])[source]
trigger()[source]

Trigger debounce — restarts timer.

cancel()[source]

Cancel pending trigger.

force()[source]

Cancel timer and fire handler immediately.

class pyqt_reactive.core.ReorderableListWidget(parent=None)[source]

Bases: QListWidget

Custom QListWidget that properly handles drag and drop reordering.

Emits a signal when items are moved so the parent can update the data model. This is a shared implementation used by both PipelineEditor and PlateManager.

items_reordered

int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

Type:

str = …, revision

__init__(parent=None)[source]

Initialize reorderable list widget.

Parameters:

parent – Parent widget

dropEvent(event)[source]

Handle drop event and emit signal with indices.

class pyqt_reactive.core.BackgroundTask(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, debounce_ms: int = 0, parent=None)[source]

Bases: QThread

Unified background task with cancellation, debounce, and cleanup.

Usage:

task = BackgroundTask(target=my_func, args=(a, b)) task.result_ready.connect(on_success) task.error_occurred.connect(on_error) # Receives Exception, not str task.start()

# Later: task.cancel() # Safe cancellation

Error handling:
def on_error(e: Exception):

logger.exception(“Failed”, exc_info=e) # Full traceback show_message(str(e)) # User-friendly string if isinstance(e, TimeoutError): … # Type checking

result_ready

int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

Type:

str = …, revision

error_occurred

int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

Type:

str = …, revision

__init__(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, debounce_ms: int = 0, parent=None)[source]
run()[source]

Execute target in background, respecting cancellation.

cancel()[source]

Cancel task — signals won’t emit after this.

class pyqt_reactive.core.BackgroundTaskManager[source]

Bases: object

Manages background task lifecycle for a widget.

Handles: - Cancelling previous task before starting new one - Cleanup on widget close - Debounce across rapid calls - Button state management (disable during operation, auto-restore)

Usage in widget:

self._task_manager = BackgroundTaskManager()

def refresh_data(self):
self._task_manager.run(

target=self.service.fetch_data, args=(self.query,), button=self.refresh_button, button_loading_text=”Loading…”, on_success=self._on_data_ready, on_error=self._on_error, debounce_ms=200

)

def closeEvent(self, event):

self._task_manager.cleanup() super().closeEvent(event)

__init__()[source]
run(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, on_success: Callable[[Any], None] = None, on_error: Callable[[Exception], None] = None, debounce_ms: int = 0, button: QPushButton = None, button_loading_text: str = None) BackgroundTask | None[source]

Run a background task, cancelling any previous one.

Parameters:
  • target – Function to execute in background

  • args – Positional arguments for target

  • kwargs – Keyword arguments for target

  • on_success – Callback for successful result

  • on_error – Callback for error (receives Exception, not str)

  • debounce_ms – Minimum time between runs (skip if too soon)

  • button – Button to disable during operation (auto-restored on complete)

  • button_loading_text – Text while loading (default: original + “…”)

Returns:

BackgroundTask if started, None if debounced out

cleanup()[source]

Cancel and wait for current task. Call from closeEvent.

class pyqt_reactive.core.CollapsibleSplitterHelper(splitter: QSplitter, left_panel_index: int = 0)[source]

Bases: object

Helper for adding double-click toggle to splitter handles.

__init__(splitter: QSplitter, left_panel_index: int = 0)[source]

Initialize the collapsible splitter helper.

Parameters:
  • splitter – The QSplitter to make collapsible

  • left_panel_index – Index of the left panel (default 0)

toggle_visibility()[source]

Toggle left panel visibility by collapsing/expanding.

set_initial_size(size: int)[source]

Set the initial size to remember when collapsed.

class pyqt_reactive.core.RichTextAppender(text_edit: QTextEdit, color_scheme: ColorScheme = None)[source]

Bases: object

Utility for appending HTML content to QTextEdit with proper cursor/scroll handling.

Usage:

appender = RichTextAppender(self.chat_history, color_scheme=self.color_scheme) appender.append_html(“<b>User:</b> Hello”) appender.append_code(“def foo(): pass”) appender.append_error(“Something went wrong”)

__init__(text_edit: QTextEdit, color_scheme: ColorScheme = None)[source]
append_html(html_content: str, add_spacing: bool = True)[source]

Append HTML content at end, scroll to bottom.

Parameters:
  • html_content – HTML string to append

  • add_spacing – Whether to add blank line after

append_text(text: str, bold: bool = False, color: str | None = None)[source]

Append plain text (escaped) with optional styling.

Parameters:
  • text – Plain text to append

  • bold – Whether to make text bold

  • color – Optional text color (hex)

append_code(code: str, language: str = None)[source]

Append code block with border styling.

Parameters:
  • code – Code string to display

  • language – Optional language hint (for future syntax highlighting)

append_error(message: str)[source]

Append error message in red.

append_success(message: str)[source]

Append success message in green.

clear()[source]

Clear all content.

pyqt_reactive.protocols

Widget protocol definitions and adapters for type-safe widget contracts.

Widget protocol definitions and adapters.

ABC-based widget contracts that eliminate duck typing in favor of explicit, fail-loud inheritance-based architecture.

class pyqt_reactive.protocols.ValueGettable[source]

Bases: ABC

ABC for widgets that can return a value.

All input widgets must implement this to participate in form value extraction.

abstractmethod get_value() Any[source]

Get the current value from the widget.

Returns:

The widget’s current value. None if no value set.

class pyqt_reactive.protocols.ValueSettable[source]

Bases: ABC

ABC for widgets that can accept a value.

All input widgets must implement this to participate in form value updates.

abstractmethod set_value(value: Any) None[source]

Set the widget’s value.

Parameters:

value – The value to set. None clears the widget.

class pyqt_reactive.protocols.PlaceholderCapable[source]

Bases: ABC

ABC for widgets that can display placeholder text.

Placeholders show inherited/default values without setting actual values.

abstractmethod set_placeholder(text: str) None[source]

Set placeholder text for the widget.

Parameters:

text – Placeholder text to display (e.g., “Pipeline default: 42”)

class pyqt_reactive.protocols.RangeConfigurable[source]

Bases: ABC

ABC for widgets that support numeric range configuration.

Typically implemented by numeric input widgets (spinboxes, sliders).

abstractmethod configure_range(minimum: float, maximum: float) None[source]

Configure the valid range for numeric input.

Parameters:
  • minimum – Minimum allowed value

  • maximum – Maximum allowed value

class pyqt_reactive.protocols.EnumSelectable[source]

Bases: ABC

ABC for widgets that can select from enum values.

Typically implemented by dropdowns and radio button groups.

abstractmethod set_enum_options(enum_type: type) None[source]

Configure widget with enum options.

Parameters:

enum_type – The Enum class to populate options from

abstractmethod get_selected_enum() Any[source]

Get the currently selected enum value.

Returns:

The selected enum member, or None if no selection

class pyqt_reactive.protocols.ChangeSignalEmitter[source]

Bases: ABC

ABC for widgets that emit change signals.

Provides explicit contract for signal connection, eliminating duck typing of signal names (textChanged vs valueChanged vs currentIndexChanged).

abstractmethod connect_change_signal(callback: Callable[[Any], None]) None[source]

Connect callback to widget’s change signal.

The callback will be invoked whenever the widget’s value changes, receiving the new value as its argument.

Parameters:

callback – Function to call when widget value changes. Signature: callback(new_value: Any) -> None

abstractmethod disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Disconnect callback from widget’s change signal.

Parameters:

callback – The callback function to disconnect

class pyqt_reactive.protocols.LineEditAdapter[source]

Bases: QLineEdit, ValueGettable, ValueSettable, PlaceholderCapable, ChangeSignalEmitter

Adapter for QLineEdit implementing OpenHCS ABCs.

Normalizes Qt API to OpenHCS contracts: - .text() → .get_value() - .setText() → .set_value() - .setPlaceholderText() → .set_placeholder() - .textChanged → .connect_change_signal()

get_value() Any[source]

Implement ValueGettable ABC.

set_value(value: Any) None[source]

Implement ValueSettable ABC.

set_placeholder(text: str) None[source]

Implement PlaceholderCapable ABC.

connect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

class pyqt_reactive.protocols.SpinBoxAdapter(parent=None)[source]

Bases: QSpinBox, ValueGettable, ValueSettable, PlaceholderCapable, RangeConfigurable, ChangeSignalEmitter

Adapter for QSpinBox implementing OpenHCS ABCs.

Handles None values using special value text mechanism. When value is None, displays placeholder text at minimum value.

__init__(parent=None)[source]
get_value() Any[source]

Implement ValueGettable ABC.

set_value(value: Any) None[source]

Implement ValueSettable ABC.

set_placeholder(text: str) None[source]

Implement PlaceholderCapable ABC.

configure_range(minimum: float, maximum: float) None[source]

Implement RangeConfigurable ABC.

connect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

class pyqt_reactive.protocols.DoubleSpinBoxAdapter(parent=None)[source]

Bases: QDoubleSpinBox, ValueGettable, ValueSettable, PlaceholderCapable, RangeConfigurable, ChangeSignalEmitter

Adapter for QDoubleSpinBox implementing OpenHCS ABCs.

Handles None values and floating-point ranges.

__init__(parent=None)[source]
get_value() Any[source]

Implement ValueGettable ABC.

set_value(value: Any) None[source]

Implement ValueSettable ABC.

set_placeholder(text: str) None[source]

Implement PlaceholderCapable ABC.

configure_range(minimum: float, maximum: float) None[source]

Implement RangeConfigurable ABC.

connect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

class pyqt_reactive.protocols.ComboBoxAdapter[source]

Bases: QComboBox, ValueGettable, ValueSettable, PlaceholderCapable, ChangeSignalEmitter

Adapter for QComboBox implementing OpenHCS ABCs.

Stores actual values in itemData, not just display text. Supports enum population and selection.

get_value() Any[source]

Implement ValueGettable ABC.

set_value(value: Any) None[source]

Implement ValueSettable ABC.

set_placeholder(text: str) None[source]

Implement PlaceholderCapable ABC.

populate_enum(enum_type: type) None[source]

Populate combobox with enum values.

Parameters:

enum_type – The Enum class to populate from

connect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

class pyqt_reactive.protocols.CheckBoxAdapter[source]

Bases: QCheckBox, ValueGettable, ValueSettable, ChangeSignalEmitter

Adapter for QCheckBox implementing OpenHCS ABCs.

Returns bool values, treats None as False.

get_value() Any[source]

Implement ValueGettable ABC.

set_value(value: Any) None[source]

Implement ValueSettable ABC.

connect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

disconnect_change_signal(callback: Callable[[Any], None]) None[source]

Implement ChangeSignalEmitter ABC.

class pyqt_reactive.protocols.PyQtWidgetMeta(name, bases, namespace, /, **kwargs)[source]

Bases: wrappertype, ABCMeta

Metaclass for PyQt widgets that need ABC support.

class pyqt_reactive.protocols.FunctionRegistryProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol for function registries that provide function lookup and metadata.

Applications can implement this protocol to provide their own function registry.

Example

from pyqt_reactive.protocols import register_function_registry from myapp.registry import MyFunctionRegistry

register_function_registry(MyFunctionRegistry())

get_function_by_name(name: str) Callable | None[source]

Get function by name.

Parameters:

name – Function name to lookup

Returns:

Function callable if found, None otherwise

get_all_functions() Dict[str, Callable][source]

Get all registered functions.

Returns:

Dictionary mapping function names to callables

get_function_metadata(name: str) Dict[str, Any] | None[source]

Get metadata for a function.

Parameters:

name – Function name

Returns:

Metadata dict if available, None otherwise

__init__(*args, **kwargs)
pyqt_reactive.protocols.register_function_registry(registry: FunctionRegistryProtocol) None[source]

Register a function registry implementation.

Parameters:

registry – Object implementing FunctionRegistryProtocol

pyqt_reactive.protocols.get_function_registry() FunctionRegistryProtocol | None[source]

Get the registered function registry.

Returns:

Registered registry or None if not registered

class pyqt_reactive.protocols.PreviewFormatterRegistry[source]

Bases: object

Registry for preview formatters by config type.

Applications can register formatters for specific config types to customize how fields are displayed in list item previews.

Example

from pyqt_reactive.protocols import PreviewFormatterRegistry

def format_zarr_config(config, field_name):
if field_name == ‘compression’:

return f”comp={config.compression[:3]}” # Abbreviate

return str(getattr(config, field_name))

PreviewFormatterRegistry.register(ZarrConfig, format_zarr_config)

classmethod register(config_type: Type, formatter: Callable[[Any, str], str]) None[source]

Register a formatter for a config type.

Parameters:
  • config_type – Config class to format

  • formatter – Formatter function taking (config, field_name) -> str

classmethod get_formatter(config_type: Type) Callable[[Any, str], str] | None[source]

Get formatter for a config type.

Parameters:

config_type – Config class

Returns:

Formatter function if registered, None otherwise

classmethod format_field(config: Any, field_name: str) str | None[source]

Format a field using registered formatter if available.

Parameters:
  • config – Config instance

  • field_name – Field name to format

Returns:

Formatted string if formatter available, None otherwise

pyqt_reactive.protocols.register_preview_formatter(config_type: Type, formatter: Callable[[Any, str], str]) None[source]

Register a preview formatter for a config type.

Parameters:
  • config_type – Config class

  • formatter – Formatter function

class pyqt_reactive.protocols.FormGenConfig(enable_placeholder_styling: bool = True, enable_help_buttons: bool = True, enable_inheritance_tracking: bool = True, custom_widget_factories: Type, ~typing.Any]=<factory>, jedi_project_paths: List[str] = <factory>, log_dir: str | None = None, log_prefixes: List[str] = <factory>, log_root_logger_name: str | None = None, performance_logger_name: str = 'pyqt_reactive.performance', performance_log_filename: str = 'performance.log', path_cache_file: str | None = None)[source]

Bases: object

Base configuration for form generation behavior.

Applications can subclass this to provide custom configuration.

enable_placeholder_styling

Whether to apply special styling to placeholder values

Type:

bool

enable_help_buttons

Whether to show help buttons for fields with docstrings

Type:

bool

enable_inheritance_tracking

Whether to show inheritance source indicators

Type:

bool

custom_widget_factories

Custom widget factories by type

Type:

Dict[Type, Any]

enable_placeholder_styling: bool = True
enable_help_buttons: bool = True
enable_inheritance_tracking: bool = True
custom_widget_factories: Dict[Type, Any]
jedi_project_paths: List[str]
log_dir: str | None = None
log_prefixes: List[str]
log_root_logger_name: str | None = None
performance_logger_name: str = 'pyqt_reactive.performance'
performance_log_filename: str = 'performance.log'
path_cache_file: str | None = None
__init__(enable_placeholder_styling: bool = True, enable_help_buttons: bool = True, enable_inheritance_tracking: bool = True, custom_widget_factories: Type, ~typing.Any]=<factory>, jedi_project_paths: List[str] = <factory>, log_dir: str | None = None, log_prefixes: List[str] = <factory>, log_root_logger_name: str | None = None, performance_logger_name: str = 'pyqt_reactive.performance', performance_log_filename: str = 'performance.log', path_cache_file: str | None = None) None
pyqt_reactive.protocols.set_form_config(config: FormGenConfig) None[source]

Set the global form generation configuration.

Parameters:

config – FormGenConfig instance

pyqt_reactive.protocols.get_form_config() FormGenConfig[source]

Get the current form generation configuration.

Returns:

Current FormGenConfig or default if not set

class pyqt_reactive.protocols.LLMServiceProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol for LLM services used by LLMChatPanel.

api_endpoint: str
model: str | None
test_connection() Tuple[bool, str][source]

Return (is_connected, status_message).

generate_code(request: str, code_type: str | None = None) str[source]

Generate code for a request and optional code type.

__init__(*args, **kwargs)
pyqt_reactive.protocols.register_llm_service(service: LLMServiceProtocol) None[source]

Register a global LLM service implementation.

pyqt_reactive.protocols.get_llm_service() LLMServiceProtocol | None[source]

Get the registered LLM service implementation.

class pyqt_reactive.protocols.CodegenProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for code generators used by the simple code editor.

generate_complete_orchestrator_code(plate_paths: list[str], pipeline_data: dict, global_config: Any | None = None, per_plate_configs: dict | None = None, pipeline_config: Any | None = None, clean_mode: bool = True) str[source]
generate_complete_pipeline_steps_code(pipeline_steps: list[Any], clean_mode: bool = True) str[source]
generate_complete_function_pattern_code(func_obj: Any, clean_mode: bool = False) str[source]
generate_config_code(config_obj: Any, clean_mode: bool = True, config_class: type | None = None) str[source]
generate_step_code(step_obj: Any, clean_mode: bool = True) str[source]
__init__(*args, **kwargs)
pyqt_reactive.protocols.register_codegen_provider(provider: CodegenProvider) None[source]

Register a global code generation provider.

pyqt_reactive.protocols.get_codegen_provider() CodegenProvider | None[source]

Get the registered code generation provider.

class pyqt_reactive.protocols.LogDiscoveryProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for discovering log files and current log path.

get_current_log_path() Path[source]

Return current log file path.

discover_logs(base_log_path: str | None = None, include_main_log: bool = True, log_directory: Path | None = None) List[LogFileInfo][source]

Return discovered logs.

__init__(*args, **kwargs)
class pyqt_reactive.protocols.ServerScanProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for discovering server logs (e.g., via port scans).

scan_for_server_logs() List[LogFileInfo][source]

Return logs discovered from live servers.

__init__(*args, **kwargs)
pyqt_reactive.protocols.register_log_discovery_provider(provider: LogDiscoveryProvider) None[source]

Register a global log discovery provider.

pyqt_reactive.protocols.get_log_discovery_provider() LogDiscoveryProvider | None[source]

Get the registered log discovery provider.

pyqt_reactive.protocols.register_server_scan_provider(provider: ServerScanProvider) None[source]

Register a global server scan provider.

pyqt_reactive.protocols.get_server_scan_provider() ServerScanProvider | None[source]

Get the registered server scan provider.

class pyqt_reactive.protocols.WindowFactoryProtocol(*args, **kwargs)[source]

Bases: Protocol

Protocol for creating windows for a given scope.

Use this for duck-typed checking. For implementation, prefer WindowFactoryABC.

create_window_for_scope(scope_id: str, object_state: Any | None = None) QWidget | None[source]

Create and show a window for the given scope id.

__init__(*args, **kwargs)
class pyqt_reactive.protocols.WindowFactoryABC[source]

Bases: ABC

Abstract base class for window factories.

Subclass this to implement application-specific window creation logic. The factory is responsible for: - Parsing scope_id format to determine window type - Creating the appropriate window class - Showing and activating the window

abstractmethod create_window_for_scope(scope_id: str, object_state: Any | None = None) QWidget | None[source]

Create and show a window for the given scope_id.

Parameters:
  • scope_id – Scope identifier. Format is application-specific, e.g.: - “” (empty string): Global config - “/path/to/item”: Item-level config - “/path/to/item::sub”: Nested scope

  • object_state – Optional ObjectState for time-travel restore

Returns:

The created window, or None if creation failed/skipped

pyqt_reactive.protocols.register_window_factory(factory: WindowFactoryProtocol) None[source]

Register a global window factory.

Parameters:

factory – Factory instance implementing WindowFactoryProtocol or WindowFactoryABC

pyqt_reactive.protocols.get_window_factory() WindowFactoryProtocol | None[source]

Get the registered window factory.

class pyqt_reactive.protocols.ComponentSelectionProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for component selection and display metadata.

get_groupby_enum() Any[source]

Return the GroupBy enum (or compatible enum) used by the host app.

get_component_keys(group_by: Any) List[str][source]

Return available component keys for a given group_by.

has_components_available(group_by: Any) bool[source]

Check if components are available for the given group_by without fetching them all.

Used to determine if UI elements (like component selection buttons) should be enabled. Should return False if the underlying data source (e.g., orchestrator) is not ready.

get_component_display_name(group_by: Any, component_key: str) str | None[source]

Return a human-readable name for a component key.

select_components(available_components: Iterable[str], selected_components: Iterable[str], group_by: Any, parent: Any | None = None, **context: Any) List[str] | None[source]

Show selection UI and return chosen components (or None if canceled).

__init__(*args, **kwargs)
class pyqt_reactive.protocols.FunctionSelectionProvider(*args, **kwargs)[source]

Bases: Protocol

Protocol for selecting a function in UI.

select_function(parent: Any | None = None, **context: Any) Callable | None[source]

Return a selected function or None.

__init__(*args, **kwargs)
pyqt_reactive.protocols.register_component_selection_provider(provider: ComponentSelectionProvider) None[source]

Register a global component selection provider.

pyqt_reactive.protocols.get_component_selection_provider() ComponentSelectionProvider | None[source]

Get the registered component selection provider.

pyqt_reactive.protocols.register_function_selection_provider(provider: FunctionSelectionProvider) None[source]

Register a global function selection provider.

pyqt_reactive.protocols.get_function_selection_provider() FunctionSelectionProvider | None[source]

Get the registered function selection provider.

pyqt_reactive.services

Service layer for form management and cross-cutting concerns.

pyqt_reactive.forms

Form generation and management from dataclasses.

Form generation and management.

ParameterFormManager and supporting infrastructure for automatic form generation from dataclasses and function signatures.

pyqt_reactive.widgets

Extended widget implementations with enhanced behavior.

Extended widget implementations.

Specialized widget subclasses that build on the protocol layer with enhanced behavior.

class pyqt_reactive.widgets.NoScrollSpinBox(parent=None)[source]

Bases: SpinBoxAdapter

SpinBox that ignores wheel events to prevent accidental value changes.

Inherits from SpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.

wheelEvent(event: QWheelEvent)[source]

Ignore wheel events to prevent accidental value changes.

class pyqt_reactive.widgets.NoScrollDoubleSpinBox(parent=None)[source]

Bases: DoubleSpinBoxAdapter

DoubleSpinBox that ignores wheel events to prevent accidental value changes.

Inherits from DoubleSpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.

wheelEvent(event: QWheelEvent)[source]

Ignore wheel events to prevent accidental value changes.

textFromValue(value: float) str[source]

Convert value to string without trailing zeros for clean display.

Users can still type additional digits when editing - this only affects the display format, not the underlying precision.

Examples

1.5 -> “1.5” 1.0 -> “1” 1.567 -> “1.567” 0.0001 -> “0.0001”

class pyqt_reactive.widgets.NoScrollComboBox(parent=None, placeholder='')[source]

Bases: ComboBoxAdapter

ComboBox that ignores wheel events to prevent accidental value changes.

Inherits from ComboBoxAdapter which already implements ValueGettable/ValueSettable ABCs. Supports placeholder text when currentIndex == -1 (for None values).

__init__(parent=None, placeholder='')[source]
wheelEvent(event: QWheelEvent)[source]

Ignore wheel events to prevent accidental value changes.

setPlaceholder(text: str)[source]

Set the placeholder text shown when currentIndex == -1.

setCurrentIndex(index: int)[source]

Override to track when placeholder should be active.

get_value()[source]

Get current value (item data at current index).

set_value(value)[source]

Set current value by finding matching item data.

paintEvent(event)[source]

Override to draw placeholder text when currentIndex == -1.

class pyqt_reactive.widgets.NoneAwareCheckBox(parent=None)[source]

Bases: QCheckBox, ValueGettable, ValueSettable

QCheckBox that supports None state for lazy dataclass contexts.

Shows inherited value as grayed placeholder when value is None. Clicking converts placeholder to explicit value.

__init__(parent=None)[source]
get_value()[source]

Get value, returning None if in placeholder state.

is_placeholder() bool[source]

Return whether the checkbox is currently displaying inherited state.

set_value(value)[source]

Set value, handling None by leaving in placeholder state.

set_placeholder_preview(checked: bool) None[source]

Display an inherited checkbox value without making it concrete.

convert_placeholder_to_concrete() None[source]

Keep the displayed value but mark it as a user-controlled value.

clear_placeholder_cache() None[source]

Clear cached placeholder text set by the placeholder enhancer.

mousePressEvent(event)[source]

On click, switch from placeholder to explicit value.

paintEvent(event)[source]

Draw with placeholder styling.

For placeholder state, draw the checkbox with grey text color to make the checkmark appear dimmed.

class pyqt_reactive.widgets.StatusIndicator(check_fn: Callable[[], Tuple[bool, str]] = None, color_scheme: ColorScheme = None, show_refresh: bool = True, debounce_ms: int = 2000, parent=None)[source]

Bases: QWidget

Reusable status indicator with colored dot, label, and refresh button.

Usage:
indicator = StatusIndicator(

check_fn=lambda: my_service.test_connection(), color_scheme=self.color_scheme, parent=self

) layout.addWidget(indicator)

# check_fn returns Tuple[bool, str]: (is_ok, status_message) # True → CONNECTED state, False → DISCONNECTED state

__init__(check_fn: Callable[[], Tuple[bool, str]] = None, color_scheme: ColorScheme = None, show_refresh: bool = True, debounce_ms: int = 2000, parent=None)[source]
set_state(state: StatusState, message: str = None)[source]

Update visual state.

refresh(force: bool = False)[source]

Trigger async status check.

showEvent(event)[source]

Auto-refresh on show (no debounce for initial check).

closeEvent(event)[source]

Cleanup on close.

class pyqt_reactive.widgets.StatusState(*values)[source]

Bases: Enum

Status indicator states — colors resolved from color scheme at runtime.

UNKNOWN = 'Unknown'
CHECKING = 'Checking...'
CONNECTED = 'connected'
DISCONNECTED = 'disconnected'
WARNING = 'warning'
property default_message: str | None
pyqt_reactive.widgets.get_status_color(state: StatusState, color_scheme: ColorScheme) str[source]

Resolve status state to color from scheme.

pyqt_reactive.theming

Color schemes and styling system for dynamic theme switching.

Theming and styling system.

Color schemes, palette management, and stylesheet generation for consistent application-wide theming.

class pyqt_reactive.theming.ColorScheme(window_bg: Tuple[int, int, int] = (43, 43, 43), panel_bg: Tuple[int, int, int] = (30, 30, 30), frame_bg: Tuple[int, int, int] = (43, 43, 43), border_color: Tuple[int, int, int] = (85, 85, 85), border_light: Tuple[int, int, int] = (102, 102, 102), separator_color: Tuple[int, int, int] = (51, 51, 51), text_primary: Tuple[int, int, int] = (255, 255, 255), text_secondary: Tuple[int, int, int] = (204, 204, 204), text_accent: Tuple[int, int, int] = (0, 170, 255), text_disabled: Tuple[int, int, int] = (102, 102, 102), button_normal_bg: Tuple[int, int, int] = (64, 64, 64), button_hover_bg: Tuple[int, int, int] = (80, 80, 80), button_pressed_bg: Tuple[int, int, int] = (48, 48, 48), button_disabled_bg: Tuple[int, int, int] = (42, 42, 42), button_text: Tuple[int, int, int] = (255, 255, 255), button_disabled_text: Tuple[int, int, int] = (102, 102, 102), input_bg: Tuple[int, int, int] = (64, 64, 64), input_border: Tuple[int, int, int] = (102, 102, 102), input_text: Tuple[int, int, int] = (255, 255, 255), input_focus_border: Tuple[int, int, int] = (0, 170, 255), selection_bg: Tuple[int, int, int] = (0, 120, 212), selection_text: Tuple[int, int, int] = (255, 255, 255), hover_bg: Tuple[int, int, int] = (51, 51, 51), focus_outline: Tuple[int, int, int] = (0, 170, 255), search_highlight_bg: Tuple[int, int, int, int] = (255, 255, 0, 100), search_highlight_text: Tuple[int, int, int] = (0, 0, 0), status_success: Tuple[int, int, int] = (0, 255, 0), status_warning: Tuple[int, int, int] = (255, 170, 0), status_error: Tuple[int, int, int] = (255, 0, 0), status_info: Tuple[int, int, int] = (0, 170, 255), progress_bg: Tuple[int, int, int] = (30, 30, 30), progress_fill: Tuple[int, int, int] = (0, 120, 212), activity_indicator: Tuple[int, int, int] = (0, 170, 255), log_critical_fg: Tuple[int, int, int] = (255, 255, 255), log_critical_bg: Tuple[int, int, int] = (139, 0, 0), log_error_color: Tuple[int, int, int] = (255, 85, 85), log_warning_color: Tuple[int, int, int] = (255, 140, 0), log_info_color: Tuple[int, int, int] = (100, 160, 210), log_debug_color: Tuple[int, int, int] = (160, 160, 160), timestamp_color: Tuple[int, int, int] = (105, 105, 105), logger_name_color: Tuple[int, int, int] = (147, 112, 219), memory_address_color: Tuple[int, int, int] = (255, 182, 193), file_path_color: Tuple[int, int, int] = (34, 139, 34), python_keyword_color: Tuple[int, int, int] = (86, 156, 214), python_string_color: Tuple[int, int, int] = (206, 145, 120), python_number_color: Tuple[int, int, int] = (181, 206, 168), python_operator_color: Tuple[int, int, int] = (212, 212, 212), python_name_color: Tuple[int, int, int] = (156, 220, 254), python_function_color: Tuple[int, int, int] = (220, 220, 170), python_class_color: Tuple[int, int, int] = (78, 201, 176), python_builtin_color: Tuple[int, int, int] = (86, 156, 214), python_comment_color: Tuple[int, int, int] = (106, 153, 85), exception_color: Tuple[int, int, int] = (255, 69, 0), function_call_color: Tuple[int, int, int] = (255, 215, 0), boolean_color: Tuple[int, int, int] = (86, 156, 214), tuple_parentheses_color: Tuple[int, int, int] = (255, 215, 0), set_braces_color: Tuple[int, int, int] = (255, 140, 0), class_representation_color: Tuple[int, int, int] = (78, 201, 176), function_representation_color: Tuple[int, int, int] = (220, 220, 170), module_path_color: Tuple[int, int, int] = (147, 112, 219), hex_number_color: Tuple[int, int, int] = (181, 206, 168), scientific_notation_color: Tuple[int, int, int] = (181, 206, 168), binary_number_color: Tuple[int, int, int] = (181, 206, 168), octal_number_color: Tuple[int, int, int] = (181, 206, 168), python_special_color: Tuple[int, int, int] = (255, 20, 147), single_quoted_string_color: Tuple[int, int, int] = (206, 145, 120), list_comprehension_color: Tuple[int, int, int] = (156, 220, 254), generator_expression_color: Tuple[int, int, int] = (156, 220, 254))[source]

Bases: object

Comprehensive color scheme for OpenHCS PyQt6 GUI with semantic color names.

Extends the LogColorScheme pattern to cover all GUI components including windows, dialogs, widgets, and interactive elements. Supports light/dark theme variants and ensures WCAG accessibility compliance.

All colors meet minimum 4.5:1 contrast ratio for normal text readability.

window_bg: Tuple[int, int, int] = (43, 43, 43)
panel_bg: Tuple[int, int, int] = (30, 30, 30)
frame_bg: Tuple[int, int, int] = (43, 43, 43)
border_color: Tuple[int, int, int] = (85, 85, 85)
border_light: Tuple[int, int, int] = (102, 102, 102)
separator_color: Tuple[int, int, int] = (51, 51, 51)
text_primary: Tuple[int, int, int] = (255, 255, 255)
text_secondary: Tuple[int, int, int] = (204, 204, 204)
text_accent: Tuple[int, int, int] = (0, 170, 255)
text_disabled: Tuple[int, int, int] = (102, 102, 102)
button_normal_bg: Tuple[int, int, int] = (64, 64, 64)
button_hover_bg: Tuple[int, int, int] = (80, 80, 80)
button_pressed_bg: Tuple[int, int, int] = (48, 48, 48)
button_disabled_bg: Tuple[int, int, int] = (42, 42, 42)
button_text: Tuple[int, int, int] = (255, 255, 255)
button_disabled_text: Tuple[int, int, int] = (102, 102, 102)
input_bg: Tuple[int, int, int] = (64, 64, 64)
input_border: Tuple[int, int, int] = (102, 102, 102)
input_text: Tuple[int, int, int] = (255, 255, 255)
input_focus_border: Tuple[int, int, int] = (0, 170, 255)
selection_bg: Tuple[int, int, int] = (0, 120, 212)
selection_text: Tuple[int, int, int] = (255, 255, 255)
hover_bg: Tuple[int, int, int] = (51, 51, 51)
focus_outline: Tuple[int, int, int] = (0, 170, 255)
search_highlight_bg: Tuple[int, int, int, int] = (255, 255, 0, 100)
search_highlight_text: Tuple[int, int, int] = (0, 0, 0)
status_success: Tuple[int, int, int] = (0, 255, 0)
status_warning: Tuple[int, int, int] = (255, 170, 0)
status_error: Tuple[int, int, int] = (255, 0, 0)
status_info: Tuple[int, int, int] = (0, 170, 255)
progress_bg: Tuple[int, int, int] = (30, 30, 30)
progress_fill: Tuple[int, int, int] = (0, 120, 212)
activity_indicator: Tuple[int, int, int] = (0, 170, 255)
log_critical_fg: Tuple[int, int, int] = (255, 255, 255)
log_critical_bg: Tuple[int, int, int] = (139, 0, 0)
log_error_color: Tuple[int, int, int] = (255, 85, 85)
log_warning_color: Tuple[int, int, int] = (255, 140, 0)
log_info_color: Tuple[int, int, int] = (100, 160, 210)
log_debug_color: Tuple[int, int, int] = (160, 160, 160)
timestamp_color: Tuple[int, int, int] = (105, 105, 105)
logger_name_color: Tuple[int, int, int] = (147, 112, 219)
memory_address_color: Tuple[int, int, int] = (255, 182, 193)
file_path_color: Tuple[int, int, int] = (34, 139, 34)
python_keyword_color: Tuple[int, int, int] = (86, 156, 214)
python_string_color: Tuple[int, int, int] = (206, 145, 120)
python_number_color: Tuple[int, int, int] = (181, 206, 168)
python_operator_color: Tuple[int, int, int] = (212, 212, 212)
python_name_color: Tuple[int, int, int] = (156, 220, 254)
python_function_color: Tuple[int, int, int] = (220, 220, 170)
python_class_color: Tuple[int, int, int] = (78, 201, 176)
python_builtin_color: Tuple[int, int, int] = (86, 156, 214)
python_comment_color: Tuple[int, int, int] = (106, 153, 85)
exception_color: Tuple[int, int, int] = (255, 69, 0)
function_call_color: Tuple[int, int, int] = (255, 215, 0)
boolean_color: Tuple[int, int, int] = (86, 156, 214)
tuple_parentheses_color: Tuple[int, int, int] = (255, 215, 0)
set_braces_color: Tuple[int, int, int] = (255, 140, 0)
class_representation_color: Tuple[int, int, int] = (78, 201, 176)
function_representation_color: Tuple[int, int, int] = (220, 220, 170)
module_path_color: Tuple[int, int, int] = (147, 112, 219)
hex_number_color: Tuple[int, int, int] = (181, 206, 168)
scientific_notation_color: Tuple[int, int, int] = (181, 206, 168)
binary_number_color: Tuple[int, int, int] = (181, 206, 168)
octal_number_color: Tuple[int, int, int] = (181, 206, 168)
python_special_color: Tuple[int, int, int] = (255, 20, 147)
single_quoted_string_color: Tuple[int, int, int] = (206, 145, 120)
list_comprehension_color: Tuple[int, int, int] = (156, 220, 254)
generator_expression_color: Tuple[int, int, int] = (156, 220, 254)
to_qcolor(color_tuple: Tuple[int, int, int]) QColor[source]

Convert RGB tuple to QColor object.

Parameters:

color_tuple – RGB color tuple (r, g, b)

Returns:

Qt color object

Return type:

QColor

to_qcolor_rgba(color_tuple: Tuple[int, int, int, int]) QColor[source]

Convert RGBA tuple to QColor object.

Parameters:

color_tuple – RGBA color tuple (r, g, b, a)

Returns:

Qt color object with alpha

Return type:

QColor

to_hex(color_tuple: Tuple[int, int, int]) str[source]

Convert RGB tuple to hex color string.

Parameters:

color_tuple – RGB color tuple (r, g, b)

Returns:

Hex color string (e.g., “#ff0000”)

Return type:

str

classmethod create_dark_theme() PyQt6ColorScheme[source]

Create a dark theme variant with adjusted colors for dark backgrounds.

This is the default theme, so most colors remain the same with minor adjustments for better contrast on dark backgrounds.

Returns:

Dark theme color scheme with enhanced contrast

Return type:

PyQt6ColorScheme

classmethod create_light_theme() PyQt6ColorScheme[source]

Create a light theme variant with adjusted colors for light backgrounds.

All colors are adjusted to maintain WCAG 4.5:1 contrast ratio on light backgrounds while preserving the semantic meaning and visual hierarchy.

Returns:

Light theme color scheme with appropriate contrast

Return type:

PyQt6ColorScheme

classmethod load_color_scheme_from_config(config_path: str = None) PyQt6ColorScheme[source]

Load color scheme from external configuration file.

Parameters:

config_path – Path to JSON config file (optional)

Returns:

Loaded color scheme or default if file not found

Return type:

PyQt6ColorScheme

validate_wcag_contrast(foreground: Tuple[int, int, int], background: Tuple[int, int, int], min_ratio: float = 4.5) bool[source]

Validate WCAG contrast ratio between foreground and background colors.

Parameters:
  • foreground – Foreground color RGB tuple

  • background – Background color RGB tuple

  • min_ratio – Minimum contrast ratio (default: 4.5 for normal text)

Returns:

True if contrast ratio meets minimum requirement

Return type:

bool

get_color_dict() Dict[str, Tuple[int, int, int]][source]

Get all colors as a dictionary for serialization or inspection.

Returns:

Dictionary of color name to RGB tuple

Return type:

Dict[str, Tuple[int, int, int]]

save_to_json(config_path: str) bool[source]

Save color scheme to JSON configuration file.

Parameters:

config_path – Path to save JSON config file

Returns:

True if save successful, False otherwise

Return type:

bool

__init__(window_bg: Tuple[int, int, int] = (43, 43, 43), panel_bg: Tuple[int, int, int] = (30, 30, 30), frame_bg: Tuple[int, int, int] = (43, 43, 43), border_color: Tuple[int, int, int] = (85, 85, 85), border_light: Tuple[int, int, int] = (102, 102, 102), separator_color: Tuple[int, int, int] = (51, 51, 51), text_primary: Tuple[int, int, int] = (255, 255, 255), text_secondary: Tuple[int, int, int] = (204, 204, 204), text_accent: Tuple[int, int, int] = (0, 170, 255), text_disabled: Tuple[int, int, int] = (102, 102, 102), button_normal_bg: Tuple[int, int, int] = (64, 64, 64), button_hover_bg: Tuple[int, int, int] = (80, 80, 80), button_pressed_bg: Tuple[int, int, int] = (48, 48, 48), button_disabled_bg: Tuple[int, int, int] = (42, 42, 42), button_text: Tuple[int, int, int] = (255, 255, 255), button_disabled_text: Tuple[int, int, int] = (102, 102, 102), input_bg: Tuple[int, int, int] = (64, 64, 64), input_border: Tuple[int, int, int] = (102, 102, 102), input_text: Tuple[int, int, int] = (255, 255, 255), input_focus_border: Tuple[int, int, int] = (0, 170, 255), selection_bg: Tuple[int, int, int] = (0, 120, 212), selection_text: Tuple[int, int, int] = (255, 255, 255), hover_bg: Tuple[int, int, int] = (51, 51, 51), focus_outline: Tuple[int, int, int] = (0, 170, 255), search_highlight_bg: Tuple[int, int, int, int] = (255, 255, 0, 100), search_highlight_text: Tuple[int, int, int] = (0, 0, 0), status_success: Tuple[int, int, int] = (0, 255, 0), status_warning: Tuple[int, int, int] = (255, 170, 0), status_error: Tuple[int, int, int] = (255, 0, 0), status_info: Tuple[int, int, int] = (0, 170, 255), progress_bg: Tuple[int, int, int] = (30, 30, 30), progress_fill: Tuple[int, int, int] = (0, 120, 212), activity_indicator: Tuple[int, int, int] = (0, 170, 255), log_critical_fg: Tuple[int, int, int] = (255, 255, 255), log_critical_bg: Tuple[int, int, int] = (139, 0, 0), log_error_color: Tuple[int, int, int] = (255, 85, 85), log_warning_color: Tuple[int, int, int] = (255, 140, 0), log_info_color: Tuple[int, int, int] = (100, 160, 210), log_debug_color: Tuple[int, int, int] = (160, 160, 160), timestamp_color: Tuple[int, int, int] = (105, 105, 105), logger_name_color: Tuple[int, int, int] = (147, 112, 219), memory_address_color: Tuple[int, int, int] = (255, 182, 193), file_path_color: Tuple[int, int, int] = (34, 139, 34), python_keyword_color: Tuple[int, int, int] = (86, 156, 214), python_string_color: Tuple[int, int, int] = (206, 145, 120), python_number_color: Tuple[int, int, int] = (181, 206, 168), python_operator_color: Tuple[int, int, int] = (212, 212, 212), python_name_color: Tuple[int, int, int] = (156, 220, 254), python_function_color: Tuple[int, int, int] = (220, 220, 170), python_class_color: Tuple[int, int, int] = (78, 201, 176), python_builtin_color: Tuple[int, int, int] = (86, 156, 214), python_comment_color: Tuple[int, int, int] = (106, 153, 85), exception_color: Tuple[int, int, int] = (255, 69, 0), function_call_color: Tuple[int, int, int] = (255, 215, 0), boolean_color: Tuple[int, int, int] = (86, 156, 214), tuple_parentheses_color: Tuple[int, int, int] = (255, 215, 0), set_braces_color: Tuple[int, int, int] = (255, 140, 0), class_representation_color: Tuple[int, int, int] = (78, 201, 176), function_representation_color: Tuple[int, int, int] = (220, 220, 170), module_path_color: Tuple[int, int, int] = (147, 112, 219), hex_number_color: Tuple[int, int, int] = (181, 206, 168), scientific_notation_color: Tuple[int, int, int] = (181, 206, 168), binary_number_color: Tuple[int, int, int] = (181, 206, 168), octal_number_color: Tuple[int, int, int] = (181, 206, 168), python_special_color: Tuple[int, int, int] = (255, 20, 147), single_quoted_string_color: Tuple[int, int, int] = (206, 145, 120), list_comprehension_color: Tuple[int, int, int] = (156, 220, 254), generator_expression_color: Tuple[int, int, int] = (156, 220, 254)) None
class pyqt_reactive.theming.PaletteManager(color_scheme: ColorScheme)[source]

Bases: object

Manages QPalette integration with ColorScheme.

Provides methods to apply color schemes to Qt’s palette system, enabling system-wide theming and consistent color application.

__init__(color_scheme: ColorScheme)[source]

Initialize the palette manager with a color scheme.

Parameters:

color_scheme – ColorScheme instance to use for palette generation

update_color_scheme(color_scheme: ColorScheme)[source]

Update the color scheme used for palette generation.

Parameters:

color_scheme – New ColorScheme instance

create_palette() QPalette[source]

Create a QPalette from the current color scheme.

Returns:

Configured palette with color scheme colors

Return type:

QPalette

apply_palette_to_application(app: QApplication | None = None)[source]

Apply the color scheme palette to the entire application.

Parameters:

app – QApplication instance (uses QApplication.instance() if None)

restore_original_palette(app: QApplication | None = None)[source]

Restore the original application palette.

Parameters:

app – QApplication instance (uses QApplication.instance() if None)

get_palette_info() dict[source]

Get information about the current palette configuration.

Returns:

Dictionary with palette color information

Return type:

dict

class pyqt_reactive.theming.ThemeManager(initial_color_scheme: ColorScheme | None = None)[source]

Bases: object

High-level theme management for the entire application.

Coordinates color scheme, style sheet generation, and palette management to provide seamless theme switching capabilities.

__init__(initial_color_scheme: ColorScheme | None = None)[source]

Initialize the theme manager.

Parameters:

initial_color_scheme – Initial color scheme (defaults to dark theme)

switch_to_dark_theme()[source]

Switch to dark theme variant.

switch_to_light_theme()[source]

Switch to light theme variant.

apply_color_scheme(color_scheme: ColorScheme)[source]

Apply a new color scheme to the entire application.

Parameters:

color_scheme – New ColorScheme to apply

register_theme_change_callback(callback)[source]

Register a callback to be called when theme changes.

Parameters:

callback – Function to call with new color scheme

unregister_theme_change_callback(callback)[source]

Unregister a theme change callback.

Parameters:

callback – Function to remove from callbacks

get_current_style_sheet() str[source]

Get the current complete application style sheet.

Returns:

Complete QStyleSheet for current theme

Return type:

str

load_theme_from_config(config_path: str) bool[source]

Load and apply theme from configuration file.

Parameters:

config_path – Path to JSON configuration file

Returns:

True if successful, False otherwise

Return type:

bool

save_current_theme(config_path: str) bool[source]

Save current theme to configuration file.

Parameters:

config_path – Path to save JSON configuration file

Returns:

True if successful, False otherwise

Return type:

bool

class pyqt_reactive.theming.StyleSheetGenerator(color_scheme: ColorScheme)[source]

Bases: object

Generates QStyleSheet strings from ColorScheme objects.

Provides methods to generate complete stylesheets for different widget types, replacing hardcoded colors with centralized color scheme references.

__init__(color_scheme: ColorScheme)[source]

Initialize the style generator with a color scheme.

Parameters:

color_scheme – ColorScheme instance to use for styling

update_color_scheme(color_scheme: ColorScheme)[source]

Update the color scheme used for style generation.

Parameters:

color_scheme – New ColorScheme instance

generate_dialog_style() str[source]

Generate QStyleSheet for dialog windows.

Returns:

Complete QStyleSheet for dialog styling

Return type:

str

generate_tree_widget_style() str[source]

Generate QStyleSheet for tree widgets and list widgets.

Returns:

Complete QStyleSheet for tree/list widget styling

Return type:

str

generate_list_widget_style() str[source]

Alias for generate_tree_widget_style (includes QListWidget styling).

generate_table_widget_style() str[source]

Generate QStyleSheet for table widgets.

Returns:

Complete QStyleSheet for table widget styling

Return type:

str

generate_button_style() str[source]

Generate QStyleSheet for buttons with all states.

Returns:

Complete QStyleSheet for button styling

Return type:

str

generate_combobox_style() str[source]

Generate QStyleSheet for combo boxes with dropdown styling.

Returns:

Complete QStyleSheet for combo box styling

Return type:

str

generate_progress_bar_style() str[source]

Generate QStyleSheet for progress bars.

Returns:

Complete QStyleSheet for progress bar styling

Return type:

str

generate_frame_style() str[source]

Generate QStyleSheet for frames and panels.

Returns:

Complete QStyleSheet for frame styling

Return type:

str

generate_tab_widget_style() str[source]

Generate QStyleSheet for tab widgets.

Returns:

Complete QStyleSheet for tab widget styling

Return type:

str

generate_system_monitor_style() str[source]

Generate QStyleSheet for system monitor widget.

Returns:

Complete QStyleSheet for system monitor styling

Return type:

str

generate_complete_application_style() str[source]

Generate complete application-wide QStyleSheet.

Returns:

Complete QStyleSheet for entire application

Return type:

str

generate_config_window_style() str[source]

Generate QStyleSheet for configuration windows with button panel.

Returns:

Complete QStyleSheet for config window styling

Return type:

str

generate_config_button_styles() dict[source]

Generate individual button styles for config window buttons.

Returns:

Dictionary with button styles for generic, reset, cancel, save

Return type:

dict

generate_plate_manager_style() str[source]

Generate QStyleSheet for plate manager widget with all components.

Returns:

Complete QStyleSheet for plate manager styling

Return type:

str

get_status_color_hex(status_type: str) str[source]

Get hex color string for status type.

Parameters:

status_type – Status type (success, warning, error, info)

Returns:

Hex color string for the status type

Return type:

str

pyqt_reactive.animation

Flash animations and visual feedback system.

Animation and visual effects system.

Game-engine inspired flash animation system with O(1) per-window performance for visual feedback on value changes.

class pyqt_reactive.animation.FlashConfig(base_color_rgb: Tuple[int, int, int] = (255, 255, 255), flash_alpha: int = 255, fade_in_s: float = 0.2, hold_s: float = 0.05, fade_out_s: float = 0.6, frame_ms: int | None = None, use_opengl: bool = False, target_fps: int | None = None, max_fps: int | None = 60)[source]

Bases: object

Flash animation tuning knobs with automatic screen refresh rate detection.

base_color_rgb: Tuple[int, int, int] = (255, 255, 255)
flash_alpha: int = 255
fade_in_s: float = 0.2
hold_s: float = 0.05
fade_out_s: float = 0.6
frame_ms: int | None = None
use_opengl: bool = False
target_fps: int | None = None
max_fps: int | None = 60
__post_init__()[source]

Calculate frame_ms from target_fps or auto-detect screen refresh rate.

__init__(base_color_rgb: Tuple[int, int, int] = (255, 255, 255), flash_alpha: int = 255, fade_in_s: float = 0.2, hold_s: float = 0.05, fade_out_s: float = 0.6, frame_ms: int | None = None, use_opengl: bool = False, target_fps: int | None = None, max_fps: int | None = 60) None
pyqt_reactive.animation.get_flash_config() FlashConfig[source]

Return singleton flash config.

pyqt_reactive.animation.FlashMixin

alias of VisualUpdateMixin

class pyqt_reactive.animation.WindowFlashOverlay(window: QWidget)[source]

Bases: QWidget

Transparent overlay that renders ALL flash effects for an entire window.

TRUE GAME ENGINE ARCHITECTURE: - ONE instance per top-level window (QMainWindow/QDialog) - Renders ALL element types (groupboxes, tree items, list items) in ONE paintEvent - Elements register via FlashElement with geometry callbacks - Scales O(1) per window regardless of element count or type

VIEWPORT CULLING: Elements outside visible scroll areas return None from their geometry callback and are skipped.

classmethod get_for_window(widget: QWidget) WindowFlashOverlay | None[source]

Get or create the overlay for a top-level window (factory method).

Automatically chooses between OpenGL and QPainter based on config and availability.

Returns None if: - Widget is not yet in a proper window hierarchy - Widget has been deleted (RuntimeError from Qt C++ layer)

classmethod cleanup_window(window: QWidget) None[source]

Remove overlay for a window (call when window closes).

__init__(window: QWidget)[source]
register_element(element: FlashElement) None[source]

Register a flashable element. Multiple elements can share the same key.

CRITICAL: Deduplicate based on (key, source_id) to prevent duplicate registrations while allowing multiple element types (tree item + groupbox) for the same key.

unregister_element(key: str) None[source]

Unregister all elements for a key.

eventFilter(obj, event)[source]

Catch scroll/resize/layout events to invalidate geometry cache.

invalidate_cache()[source]

Public method to invalidate geometry cache.

Call this when programmatically scrolling (e.g., scroll_to_section via tree item click).

classmethod invalidate_cache_for_widget(widget: QWidget) None[source]

Invalidate geometry cache for the overlay covering a widget’s window.

Convenience method for programmatic scroll/resize operations.

resizeEvent(event) None[source]

Resize to cover entire window.

is_element_in_viewport(key: str) bool[source]

Check if any element for this key is visible (for viewport culling).

get_visible_keys() Set[str][source]

Get set of keys for elements currently visible in viewport.

get_visible_keys_for(keys: Set[str]) Set[str][source]

Get visible keys from a specific subset (avoids scanning all elements).

PERFORMANCE FIX: Use cached geometry instead of recalculating every frame. This eliminates expensive coordinate transformations during animation.

paintEvent(event) None[source]

GAME ENGINE: Render ALL flash effects in ONE paint call.

CARMACK OPTIMIZATION: Cache ALL geometry and QRegion objects. Recompute ONLY on scroll/resize events. During smooth animation: ZERO coordinate transformations, ZERO QRegion operations.

class pyqt_reactive.animation.OverlayGeometryCache(valid: bool = False, scroll_clip_rects: List[QRect] = <factory>, element_rects: Dict[str, ~typing.List[~typing.Tuple[~PyQt6.QtCore.QRect, float] | None]]=<factory>, element_regions: Dict[str, ~typing.List[~PyQt6.QtGui.QPainterPath | None]]=<factory>)[source]

Bases: object

Unified cache for all overlay geometry calculations.

FIX 3: Single cache object with single invalidation point. Replaces separate scroll_area + element caches.

valid: bool = False
scroll_clip_rects: List[QRect]
element_rects: Dict[str, List[Tuple[QRect, float] | None]]
element_regions: Dict[str, List[QPainterPath | None]]
invalidate()[source]

Invalidate entire cache - called on scroll/resize.

__init__(valid: bool = False, scroll_clip_rects: List[QRect] = <factory>, element_rects: Dict[str, ~typing.List[~typing.Tuple[~PyQt6.QtCore.QRect, float] | None]]=<factory>, element_regions: Dict[str, ~typing.List[~PyQt6.QtGui.QPainterPath | None]]=<factory>) None
pyqt_reactive.animation.get_flash_color(opacity: float = 1.0, config: FlashConfig | None = None, base_color: QColor | None = None) QColor[source]

Get the shared flash QColor with optional opacity (0.0-1.0).

pyqt_reactive.animation.get_flash_color_from_palette(scope_id: str, alpha: int = 255, use_parent_scope: bool = True) QColor[source]

Get flash color from circular palette based on scope_id.

Parameters:
  • scope_id – Scope identifier (e.g., “plate::config_field”)

  • alpha – Alpha channel (0-255)

  • use_parent_scope – If True, hash only parent scope (plate path) so all elements in same plate get same color. If False, hash full scope_id.

Returns:

QColor from pre-computed WCAG-compliant palette

class pyqt_reactive.animation.FlashElement(key: str, get_rect_in_window: Callable[[QWidget], QRect | None], get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None, needs_scroll_clipping: bool = True, source_id: str | None = None, corner_radius: float = 0.0, skip_overlay_paint: bool = False, delegate_widget: QWidget | None = None, get_model_index: Callable[[], Any] | None = None)[source]

Bases: object

Abstract representation of a flashable UI element.

Provides a geometry callback that returns the element’s rect in window coords. Works for ANY element type: groupboxes, tree items, list items, etc.

key: str
get_rect_in_window: Callable[[QWidget], QRect | None]
get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None
needs_scroll_clipping: bool = True
source_id: str | None = None
corner_radius: float = 0.0
skip_overlay_paint: bool = False
delegate_widget: QWidget | None = None
get_model_index: Callable[[], Any] | None = None
__init__(key: str, get_rect_in_window: Callable[[QWidget], QRect | None], get_child_rects: Callable[[QWidget], List[Tuple[QRect, bool]]] | None = None, needs_scroll_clipping: bool = True, source_id: str | None = None, corner_radius: float = 0.0, skip_overlay_paint: bool = False, delegate_widget: QWidget | None = None, get_model_index: Callable[[], Any] | None = None) None
pyqt_reactive.animation.get_widget_corner_radius(widget: QWidget) float[source]

Extract corner radius from widget’s stylesheet, with caching.

Searches the widget and its ancestors for border-radius in stylesheets. Returns 0 if no border-radius found (sharp corners).

pyqt_reactive.windows

Window management and scoped window registry.

pyqt_reactive.dialogs

Dialog components and utilities.

Reusable dialogs for PyQt FormGen.