Skip to content
3 changes: 1 addition & 2 deletions src/pyqt_reactive/forms/form_init_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ class DerivationContext:
"""Context for computing derived config values via properties."""
context_obj: ParameterFormConfig | FormContext | None
extracted: ExtractedParameters
color_scheme: PyQt6ColorScheme | None

@property
def global_config_type(self) -> Type:
Expand Down Expand Up @@ -557,7 +556,7 @@ def _build_config(field_id, extracted, context_obj, color_scheme, parent_manager
use_scroll_area=use_scroll_area
)

ctx = DerivationContext(context_obj, extracted, color_scheme)
ctx = DerivationContext(context_obj, extracted)
vars(config).update(vars(ctx))

from formbridge.forms.parameter_form_service import ParameterAnalysisInput
Expand Down
19 changes: 10 additions & 9 deletions src/pyqt_reactive/forms/inline_dataclass_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from typing import TYPE_CHECKING

from objectstate import DottedFieldPath
from objectstate.lazy_factory import get_base_type_for_lazy, replace_raw
from objectstate.lazy_factory import replace_raw
from python_introspect import resolve_declared_type

if TYPE_CHECKING:
from objectstate import ObjectState
Expand Down Expand Up @@ -57,7 +58,7 @@ def from_inline_widget(
if manager.field_id
else DottedFieldPath(param_info.name)
)
base_type = get_base_type_for_lazy(type(current_value)) or param_info.type
base_type = resolve_declared_type(param_info.type)
return cls(
state=manager.state,
manager=manager,
Expand Down Expand Up @@ -92,10 +93,10 @@ def child_type(self, field_name: str) -> type | None:
return None

def raw_child_value(self, field_name: str):
return self.state.parameters.get(self.child_path(field_name).value)
return DottedFieldPath(self.child_path(field_name).value).bind(self.state).raw

def resolved_child_value(self, field_name: str):
return self.state.get_resolved_value(self.child_path(field_name).value)
return DottedFieldPath(self.child_path(field_name).value).bind(self.state).value

def child_has_inherited_preview(self, field_name: str) -> bool:
return (
Expand All @@ -105,8 +106,8 @@ def child_has_inherited_preview(self, field_name: str) -> bool:

def reset_child(self, field_name: str) -> None:
identity = self.child_identity(field_name)
container_value = self.state.parameters[self.owner_path.value]
default_value = self.state.signature_default(identity.object_state_path.value)
container_value = DottedFieldPath(self.owner_path.value).bind(self.state).raw
default_value = DottedFieldPath(identity.object_state_path.value).bind(self.state).default
if self.raw_child_value(field_name) == default_value:
return
updated_value = replace_raw(container_value, **{field_name: default_value})
Expand All @@ -119,12 +120,12 @@ def reset_child(self, field_name: str) -> None:
def reset_children(self) -> None:
"""Reset every declared inline dataclass child field in one update."""

container_value = self.state.parameters[self.owner_path.value]
container_value = DottedFieldPath(self.owner_path.value).bind(self.state).raw
updates = {}
for dataclass_field in dataclass_fields(self.owner_type):
field_name = dataclass_field.name
identity = self.child_identity(field_name)
default_value = self.state.signature_default(identity.object_state_path.value)
default_value = DottedFieldPath(identity.object_state_path.value).bind(self.state).default
if self.raw_child_value(field_name) != default_value:
updates[field_name] = default_value

Expand Down Expand Up @@ -154,7 +155,7 @@ def _sync_owner_widget(self, raw_value) -> None:
"is not registered."
)

resolved_value = self.state.get_resolved_value(self.owner_path.value)
resolved_value = DottedFieldPath(self.owner_path.value).bind(self.state).value
with SignalService.block_signals(owner_widget):
if isinstance(owner_widget, RawResolvedValueSettable):
owner_widget.set_raw_value_with_resolved_preview(
Expand Down
89 changes: 29 additions & 60 deletions src/pyqt_reactive/forms/parameter_form_chrome_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from collections.abc import Iterable
from typing import Any, Set

from objectstate import DottedFieldPath
from pyqt_reactive.services.field_change_dispatcher import FieldChangeDispatcher, FieldChangeEvent
from objectstate import DottedFieldPath, FieldValue


class ParameterFormChromeSync:
Expand Down Expand Up @@ -34,12 +33,6 @@ def changed_field_visuals(
for field_name in self.manager.reset_buttons:
self.manager._update_reset_button_styling(field_name)

def enabled_field_visuals(self, value: Any) -> None:
from python_introspect import Enableable

self.manager._enabled_field_styling_service.on_enabled_field_changed(
self.manager, Enableable.require_parameter_name(), value
)

def fields_materialized(self, field_names: Iterable[str]) -> None:
"""Apply existing chrome authorities to newly visible form fields."""
Expand Down Expand Up @@ -281,9 +274,8 @@ def refresh_widgets_from_state(self) -> None:
for param_name, widget in manager.widgets.items():
if isinstance(widget, ValueSettable):
dotted_path = f"{manager.field_id}.{param_name}" if manager.field_id else param_name
if dotted_path in manager.state.parameters:
value = manager.state.parameters.get(dotted_path)
manager._widget_service.update_widget_value(widget, value, param_name, False, manager)
value = DottedFieldPath(dotted_path).bind(manager.state).raw
manager._widget_service.update_widget_value(widget, value, param_name, False, manager)

for nested_manager in manager.nested_managers.values():
nested_manager.chrome_sync.refresh_widgets_from_state()
Expand All @@ -298,7 +290,6 @@ def refresh_widgets_for_paths(self, paths: Set[str]) -> set[str]:
from objectstate.time_travel_profile import TimeTravelProfiler

manager = self.manager
missing = object()
refreshed_container_paths: set[str] = set()
refreshed_compound_owner_paths: set[str] = set()

Expand All @@ -324,18 +315,15 @@ def refresh_widgets_for_paths(self, paths: Set[str]) -> set[str]:
)
if owner_path != path and owner_path not in refreshed_container_paths:
owner_widget = manager.widgets.get(owner_field)
raw_value = manager.state.parameters.get(owner_path, missing)
field = DottedFieldPath(owner_path).bind(manager.state)
raw_value = field.raw
with TimeTravelProfiler.phase(
"pyqt.chrome.resolve_owner_value",
manager_field_id=manager.field_id,
owner_field=owner_field,
):
resolved_value = manager.state.get_resolved_value(owner_path)
combined_update = (
raw_value is not missing
and raw_value != resolved_value
and isinstance(owner_widget, RawResolvedValueSettable)
)
resolved_value = field.value
combined_update = isinstance(owner_widget, RawResolvedValueSettable)
if combined_update:
with TimeTravelProfiler.phase(
"pyqt.chrome.update_owner_raw_resolved_value",
Expand All @@ -347,30 +335,24 @@ def refresh_widgets_for_paths(self, paths: Set[str]) -> set[str]:
resolved_value,
)
elif isinstance(owner_widget, ValueSettable):
if raw_value is not missing:
with TimeTravelProfiler.phase(
"pyqt.chrome.update_owner_widget_value",
manager_field_id=manager.field_id,
owner_field=owner_field,
):
manager._widget_service.update_widget_value(
owner_widget,
raw_value,
owner_field,
True,
manager,
)
with TimeTravelProfiler.phase(
"pyqt.chrome.update_owner_widget_value",
manager_field_id=manager.field_id,
owner_field=owner_field,
):
manager._widget_service.update_widget_value(
owner_widget, raw_value, owner_field, True, manager,
)
if (
not combined_update
and isinstance(owner_widget, ResolvedValuePreviewSettable)
):
if raw_value is missing or raw_value != resolved_value:
with TimeTravelProfiler.phase(
"pyqt.chrome.update_owner_resolved_preview",
manager_field_id=manager.field_id,
owner_field=owner_field,
):
owner_widget.set_resolved_value_preview(resolved_value)
with TimeTravelProfiler.phase(
"pyqt.chrome.update_owner_resolved_preview",
manager_field_id=manager.field_id,
owner_field=owner_field,
):
owner_widget.set_resolved_value_preview(resolved_value)
if owner_widget is not None:
self._refresh_compound_widget_semantics(
owner_widget,
Expand All @@ -382,21 +364,14 @@ def refresh_widgets_for_paths(self, paths: Set[str]) -> set[str]:
if path_prefix == manager.field_id:
widget = manager.widgets.get(leaf_field)
if isinstance(widget, ValueSettable):
value = manager.state.parameters.get(path, missing)
if value is not missing:
skip_context_behavior = value is None
manager._widget_service.update_widget_value(
widget,
value,
leaf_field,
skip_context_behavior,
manager,
)
if value is None:
manager._parameter_ops_service.refresh_single_placeholder(
manager,
leaf_field,
)
member = DottedFieldPath(path).bind(manager.state).raw_member
value = member.stored
skip_context_behavior = member.inherits()
manager._widget_service.update_widget_value(
widget, value, leaf_field, skip_context_behavior, manager,
)
if member.inherits():
manager._parameter_ops_service.refresh_single_placeholder(manager, leaf_field)

with TimeTravelProfiler.phase(
"pyqt.chrome.refresh_widgets_children",
Expand All @@ -416,9 +391,3 @@ def _direct_child_field_for_path(self, path: str) -> str | None:
self.manager.field_id,
path,
)

def dispatch_reset(self, param_name: str) -> None:
dotted_path = f"{self.manager.field_id}.{param_name}" if self.manager.field_id else param_name
reset_value = self.manager.state.parameters.get(dotted_path)
event = FieldChangeEvent(param_name, reset_value, self.manager, is_reset=True)
FieldChangeDispatcher.instance().dispatch(event)
Loading