fix(dock_area): skip superseded deferred layout ratio requests

This commit is contained in:
wyzula_j authored and Jan Wyzula committed 2026-10-16 08:48:29 +02:00
1 parent 7ce6bf2a5a
commit 4cfb49ff95
2 files changed
+33 -1

No files matched your search

@@ -1,6 +1,7 @@
from __future__ import annotations
import inspect
import itertools
from dataclasses import dataclass
from typing import Any, Callable, Literal, Mapping, Sequence, cast
@@ -26,6 +27,11 @@ from bec_widgets.widgets.containers.qt_ads import (
logger = bec_logger.logger
# Dynamic property tagging a splitter with its latest layout-ratio request; deferred applies of
# older requests compare against it and skip themselves.
_RATIO_REQUEST_PROPERTY = "_bec_layout_ratio_request"
_ratio_requests = itertools.count(1)
class DockSettingsDialog(QDialog):
"""Generic settings editor shown from dock title bar actions."""
@@ -746,7 +752,9 @@ class DockAreaWidget(BECWidget, QWidget):
The deferred callback is bound to the splitter as context object, so Qt drops it
if the splitter is deleted (e.g. by ADS while the layout changes) before it runs.
While the splitter has no usable size, the ratios wait for its next resize.
While the splitter has no usable size, the ratios wait for its next resize. Every request
tags the splitter, so a deferred apply of an older request skips itself once a newer one
for the same splitter exists.
Args:
splitter(QtAds.CDockSplitter): Target splitter.
@@ -759,7 +767,12 @@ class DockAreaWidget(BECWidget, QWidget):
if not ratios:
return
request = next(_ratio_requests)
splitter.setProperty(_RATIO_REQUEST_PROPERTY, request)
def apply():
if splitter.property(_RATIO_REQUEST_PROPERTY) != request:
return # superseded by a newer request for this splitter
count = splitter.count()
if count != len(ratios):
return
+19
View File
@@ -433,6 +433,12 @@ class TestBasicDockArea:
def findChildren(self, *_args, **_kwargs):
return []
def setProperty(self, name, value):
self.__dict__[name] = value
def property(self, name):
return self.__dict__.get(name)
splitter = DummySplitter()
basic_dock_area._schedule_splitter_weights(splitter, [1, 2, 1])
@@ -647,6 +653,19 @@ class TestBasicDockArea:
assert left_px > 2 * right_px
assert root.findChildren(basic_dock_module._ResizeWatcher) == []
def test_layout_ratios_superseded_request_does_not_apply(self, collapsed_dock_area, qtbot):
"""An older request still queued when a newer one arrives must not win either."""
outer, area, root = collapsed_dock_area
area.set_layout_ratios(horizontal=[1, 3])
# The area gets its width back between the two queued applies.
QTimer.singleShot(0, outer, lambda: outer.setSizes([400, 400]))
area.set_layout_ratios(horizontal=[3, 1])
qtbot.waitUntil(lambda: root.width() > 0)
qtbot.wait(50)
left_px, right_px = root.sizes()
assert left_px > 2 * right_px
def test_first_dock_title_bar_preference_survives_second_dock(self, basic_dock_area):
first = QWidget(parent=basic_dock_area)
first.setObjectName("first_panel")