API Reference
This section contains the complete API documentation for pyqt-reactive.
Core Modules
Core PyQt6 utilities. |
|
Widget protocol definitions and adapters. |
|
Form generation and management. |
|
Extended widget implementations. |
|
Theming and styling system. |
|
Animation and visual effects system. |
|
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:
objectReusable 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
- class pyqt_reactive.core.ReorderableListWidget(parent=None)[source]
Bases:
QListWidgetCustom 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
- class pyqt_reactive.core.BackgroundTask(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, debounce_ms: int = 0, parent=None)[source]
Bases:
QThreadUnified 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
- class pyqt_reactive.core.BackgroundTaskManager[source]
Bases:
objectManages 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)
- 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
- class pyqt_reactive.core.CollapsibleSplitterHelper(splitter: QSplitter, left_panel_index: int = 0)[source]
Bases:
objectHelper for adding double-click toggle to splitter handles.
- class pyqt_reactive.core.RichTextAppender(text_edit: QTextEdit, color_scheme: ColorScheme = None)[source]
Bases:
objectUtility 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)
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:
ABCABC for widgets that can return a value.
All input widgets must implement this to participate in form value extraction.
- class pyqt_reactive.protocols.ValueSettable[source]
Bases:
ABCABC for widgets that can accept a value.
All input widgets must implement this to participate in form value updates.
- class pyqt_reactive.protocols.PlaceholderCapable[source]
Bases:
ABCABC for widgets that can display placeholder text.
Placeholders show inherited/default values without setting actual values.
- class pyqt_reactive.protocols.RangeConfigurable[source]
Bases:
ABCABC for widgets that support numeric range configuration.
Typically implemented by numeric input widgets (spinboxes, sliders).
- class pyqt_reactive.protocols.EnumSelectable[source]
Bases:
ABCABC for widgets that can select from enum values.
Typically implemented by dropdowns and radio button groups.
- class pyqt_reactive.protocols.ChangeSignalEmitter[source]
Bases:
ABCABC 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
- class pyqt_reactive.protocols.LineEditAdapter[source]
Bases:
QLineEdit,ValueGettable,ValueSettable,PlaceholderCapable,ChangeSignalEmitterAdapter for QLineEdit implementing OpenHCS ABCs.
Normalizes Qt API to OpenHCS contracts: - .text() → .get_value() - .setText() → .set_value() - .setPlaceholderText() → .set_placeholder() - .textChanged → .connect_change_signal()
- class pyqt_reactive.protocols.SpinBoxAdapter(parent=None)[source]
Bases:
QSpinBox,ValueGettable,ValueSettable,PlaceholderCapable,RangeConfigurable,ChangeSignalEmitterAdapter for QSpinBox implementing OpenHCS ABCs.
Handles None values using special value text mechanism. When value is None, displays placeholder text at minimum value.
- class pyqt_reactive.protocols.DoubleSpinBoxAdapter(parent=None)[source]
Bases:
QDoubleSpinBox,ValueGettable,ValueSettable,PlaceholderCapable,RangeConfigurable,ChangeSignalEmitterAdapter for QDoubleSpinBox implementing OpenHCS ABCs.
Handles None values and floating-point ranges.
- class pyqt_reactive.protocols.ComboBoxAdapter[source]
Bases:
QComboBox,ValueGettable,ValueSettable,PlaceholderCapable,ChangeSignalEmitterAdapter for QComboBox implementing OpenHCS ABCs.
Stores actual values in itemData, not just display text. Supports enum population and selection.
- populate_enum(enum_type: type) None[source]
Populate combobox with enum values.
- Parameters:
enum_type – The Enum class to populate from
- class pyqt_reactive.protocols.CheckBoxAdapter[source]
Bases:
QCheckBox,ValueGettable,ValueSettable,ChangeSignalEmitterAdapter for QCheckBox implementing OpenHCS ABCs.
Returns bool values, treats None as False.
- class pyqt_reactive.protocols.PyQtWidgetMeta(name, bases, namespace, /, **kwargs)[source]
Bases:
wrappertype,ABCMetaMetaclass for PyQt widgets that need ABC support.
- class pyqt_reactive.protocols.FunctionRegistryProtocol(*args, **kwargs)[source]
Bases:
ProtocolProtocol 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:
objectRegistry 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
- 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:
objectBase configuration for form generation behavior.
Applications can subclass this to provide custom configuration.
- custom_widget_factories
Custom widget factories by type
- Type:
Dict[Type, Any]
- __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:
ProtocolProtocol for LLM services used by LLMChatPanel.
- 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:
ProtocolProtocol 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_config_code(config_obj: Any, clean_mode: bool = True, config_class: type | None = None) 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:
ProtocolProtocol for discovering log files and current log 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:
ProtocolProtocol 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:
ProtocolProtocol 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:
ABCAbstract 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:
ProtocolProtocol for component selection and display metadata.
- 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:
ProtocolProtocol 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:
SpinBoxAdapterSpinBox that ignores wheel events to prevent accidental value changes.
Inherits from SpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.
- class pyqt_reactive.widgets.NoScrollDoubleSpinBox(parent=None)[source]
Bases:
DoubleSpinBoxAdapterDoubleSpinBox that ignores wheel events to prevent accidental value changes.
Inherits from DoubleSpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.
- class pyqt_reactive.widgets.NoScrollComboBox(parent=None, placeholder='')[source]
Bases:
ComboBoxAdapterComboBox 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).
- class pyqt_reactive.widgets.NoneAwareCheckBox(parent=None)[source]
Bases:
QCheckBox,ValueGettable,ValueSettableQCheckBox that supports None state for lazy dataclass contexts.
Shows inherited value as grayed placeholder when value is None. Clicking converts placeholder to explicit value.
- 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.
- 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:
QWidgetReusable 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.
- class pyqt_reactive.widgets.StatusState(*values)[source]
Bases:
EnumStatus indicator states — colors resolved from color scheme at runtime.
- UNKNOWN = 'Unknown'
- CHECKING = 'Checking...'
- CONNECTED = 'connected'
- DISCONNECTED = 'disconnected'
- WARNING = 'warning'
- 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:
objectComprehensive 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.
- 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:
- 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:
- get_color_dict() Dict[str, Tuple[int, int, int]][source]
Get all colors as a dictionary for serialization or inspection.
- 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:
- __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:
objectManages 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)
- class pyqt_reactive.theming.ThemeManager(initial_color_scheme: ColorScheme | None = None)[source]
Bases:
objectHigh-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)
- 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:
- class pyqt_reactive.theming.StyleSheetGenerator(color_scheme: ColorScheme)[source]
Bases:
objectGenerates 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:
- generate_tree_widget_style() str[source]
Generate QStyleSheet for tree widgets and list widgets.
- Returns:
Complete QStyleSheet for tree/list widget styling
- Return type:
- 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:
- generate_button_style() str[source]
Generate QStyleSheet for buttons with all states.
- Returns:
Complete QStyleSheet for button styling
- Return type:
- generate_combobox_style() str[source]
Generate QStyleSheet for combo boxes with dropdown styling.
- Returns:
Complete QStyleSheet for combo box styling
- Return type:
- generate_progress_bar_style() str[source]
Generate QStyleSheet for progress bars.
- Returns:
Complete QStyleSheet for progress bar styling
- Return type:
- generate_frame_style() str[source]
Generate QStyleSheet for frames and panels.
- Returns:
Complete QStyleSheet for frame styling
- Return type:
- generate_tab_widget_style() str[source]
Generate QStyleSheet for tab widgets.
- Returns:
Complete QStyleSheet for tab widget styling
- Return type:
- generate_system_monitor_style() str[source]
Generate QStyleSheet for system monitor widget.
- Returns:
Complete QStyleSheet for system monitor styling
- Return type:
- generate_complete_application_style() str[source]
Generate complete application-wide QStyleSheet.
- Returns:
Complete QStyleSheet for entire application
- Return type:
- generate_config_window_style() str[source]
Generate QStyleSheet for configuration windows with button panel.
- Returns:
Complete QStyleSheet for config window styling
- Return type:
- 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:
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:
objectFlash animation tuning knobs with automatic screen refresh rate detection.
- 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:
QWidgetTransparent 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).
- 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.
- 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.
- is_element_in_viewport(key: str) bool[source]
Check if any element for this key is visible (for viewport culling).
- 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:
objectUnified cache for all overlay geometry calculations.
FIX 3: Single cache object with single invalidation point. Replaces separate scroll_area + element caches.
- 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:
objectAbstract 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.
- __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.windows
Window management and scoped window registry.
pyqt_reactive.dialogs
Dialog components and utilities.
Reusable dialogs for PyQt FormGen.